Browse Source

port vrml2egg from DWDTOOL

David Rose 21 years ago
parent
commit
c5dc6f45c7
33 changed files with 6240 additions and 1 deletions
  1. 4 0
      pandatool/src/dxfegg/dxfToEggConverter.cxx
  2. 1 1
      pandatool/src/ptloader/Sources.pp
  3. 4 0
      pandatool/src/ptloader/config_ptloader.cxx
  4. 21 0
      pandatool/src/vrml/Sources.pp
  5. 142 0
      pandatool/src/vrml/parse_vrml.cxx
  6. 24 0
      pandatool/src/vrml/parse_vrml.h
  7. 488 0
      pandatool/src/vrml/standardNodes.wrl
  8. 1340 0
      pandatool/src/vrml/standardNodes.wrl.c
  9. 271 0
      pandatool/src/vrml/standardNodes.wrl.pz.c
  10. 52 0
      pandatool/src/vrml/standard_nodes.cxx
  11. 32 0
      pandatool/src/vrml/standard_nodes.h
  12. 436 0
      pandatool/src/vrml/vrml2egg.cxx
  13. 78 0
      pandatool/src/vrml/vrml2egg.h
  14. 574 0
      pandatool/src/vrml/vrmlLexer.lxx
  15. 33 0
      pandatool/src/vrml/vrmlLexerDefs.h
  16. 81 0
      pandatool/src/vrml/vrmlNode.cxx
  17. 71 0
      pandatool/src/vrml/vrmlNode.h
  18. 333 0
      pandatool/src/vrml/vrmlNodeType.cxx
  19. 108 0
      pandatool/src/vrml/vrmlNodeType.h
  20. 570 0
      pandatool/src/vrml/vrmlParser.yxx
  21. 28 0
      pandatool/src/vrml/vrmlParserDefs.h
  22. 20 0
      pandatool/src/vrmlegg/Sources.pp
  23. 582 0
      pandatool/src/vrmlegg/indexedFaceSet.cxx
  24. 84 0
      pandatool/src/vrmlegg/indexedFaceSet.h
  25. 46 0
      pandatool/src/vrmlegg/vrmlAppearance.cxx
  26. 34 0
      pandatool/src/vrmlegg/vrmlAppearance.h
  27. 411 0
      pandatool/src/vrmlegg/vrmlToEggConverter.cxx
  28. 73 0
      pandatool/src/vrmlegg/vrmlToEggConverter.h
  29. 28 0
      pandatool/src/vrmlprogs/Sources.pp
  30. 80 0
      pandatool/src/vrmlprogs/vrmlToEgg.cxx
  31. 41 0
      pandatool/src/vrmlprogs/vrmlToEgg.h
  32. 104 0
      pandatool/src/vrmlprogs/vrmlTrans.cxx
  33. 46 0
      pandatool/src/vrmlprogs/vrmlTrans.h

+ 4 - 0
pandatool/src/dxfegg/dxfToEggConverter.cxx

@@ -93,6 +93,10 @@ bool DXFToEggConverter::
 convert_file(const Filename &filename) {
   _error = false;
 
+  if (_egg_data->get_coordinate_system() == CS_default) {
+    _egg_data->set_coordinate_system(CS_zup_right);
+  }
+
   process(filename);
   return !_error;
 }

+ 1 - 1
pandatool/src/ptloader/Sources.pp

@@ -2,7 +2,7 @@
   #define TARGET ptloader
   #define BUILDING_DLL BUILDING_PTLOADER
   #define LOCAL_LIBS \
-    fltegg flt lwoegg lwo dxfegg dxf converter pandatoolbase
+    fltegg flt lwoegg lwo dxfegg dxf vrmlegg pvrml converter pandatoolbase
   #define OTHER_LIBS \
     egg2pg:c builder:c egg:c pandaegg:m \
     mathutil:c linmath:c putil:c \

+ 4 - 0
pandatool/src/ptloader/config_ptloader.cxx

@@ -24,6 +24,7 @@
 #include "config_lwo.h"
 #include "lwoToEggConverter.h"
 #include "dxfToEggConverter.h"
+#include "vrmlToEggConverter.h"
 
 /*
 #ifdef HAVE_DX
@@ -85,6 +86,9 @@ init_libptloader() {
   DXFToEggConverter *dxf = new DXFToEggConverter;
   reg->register_type(new LoaderFileTypePandatool(dxf));
 
+  VRMLToEggConverter *vrml = new VRMLToEggConverter;
+  reg->register_type(new LoaderFileTypePandatool(vrml));
+
   /*
 #ifdef HAVE_DX
   init_libxfile();

+ 21 - 0
pandatool/src/vrml/Sources.pp

@@ -0,0 +1,21 @@
+#define YACC_PREFIX vrmlyy
+
+#begin ss_lib_target
+  #define TARGET pvrml
+  #define LOCAL_LIBS \
+    pandatoolbase
+  #define OTHER_LIBS \
+    mathutil:c linmath:c panda:m \
+    dtoolbase:c dtool:m
+
+  #define USE_PACKAGES zlib
+
+  #define SOURCES \
+    parse_vrml.cxx parse_vrml.h \
+    standard_nodes.cxx standard_nodes.h \
+    vrmlLexer.lxx \
+    vrmlParser.yxx \
+    vrmlNode.cxx vrmlNode.h \
+    vrmlNodeType.cxx vrmlNodeType.h
+
+#end ss_lib_target

+ 142 - 0
pandatool/src/vrml/parse_vrml.cxx

@@ -0,0 +1,142 @@
+// Filename: parse_vrml.cxx
+// Created by:  drose (01Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+/**************************************************
+ * VRML 2.0, Draft 2 Parser
+ * Copyright (C) 1996 Silicon Graphics, Inc.
+ *
+ * Author(s)    : Gavin Bell
+ *                Daniel Woods (first port)
+ **************************************************
+ */
+
+#include "pandatoolbase.h"
+
+#include "parse_vrml.h"
+#include "vrmlParserDefs.h"
+#include "vrmlNodeType.h"
+#include "vrmlNode.h"
+#include "standard_nodes.h"
+#include "zStream.h"
+
+extern int vrmlyyparse();
+extern void vrmlyyResetLineNumber();
+extern int vrmlyydebug;
+extern int vrmlyy_flex_debug;
+extern FILE *vrmlyyin;
+
+extern VrmlScene *parsed_scene;
+
+////////////////////////////////////////////////////////////////////
+//     Function: get_standard_nodes
+//  Description: Loads the set of standard VRML node definitions into
+//               the parser, if it has not already been loaded.
+////////////////////////////////////////////////////////////////////
+static bool
+get_standard_nodes() {
+  static bool got_standard_nodes = false;
+  static bool read_ok = true;
+  if (got_standard_nodes) {
+    return read_ok;
+  }
+
+  // The standardNodes.wrl file has been compiled into this binary.
+  // Extract it out.
+
+  string data((const char *)standard_nodes_data, standard_nodes_data_len);
+
+#ifdef HAVE_ZLIB
+  // The data is stored compressed; decompress it on-the-fly.
+  istringstream inz(data);
+  IDecompressStream in(&inz, false);
+  
+#else
+  // The data is stored uncompressed, so just load it.
+  istringstream in(data);
+#endif  // HAVE_ZLIB
+
+  vrml_init_parser(in, "standardNodes.wrl");
+  if (vrmlyyparse() != 0) {
+    read_ok = false;
+  }
+  vrml_cleanup_parser();
+
+  got_standard_nodes = true;
+  return read_ok;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: parse_vrml
+//  Description: Reads the named VRML file and returns a corresponding
+//               VrmlScene, or NULL if there is a parse error.
+////////////////////////////////////////////////////////////////////
+VrmlScene *
+parse_vrml(Filename filename) {
+  filename.set_text();
+  ifstream infile;
+  if (!filename.open_read(infile)) {
+    cerr << "Error, couldn't open " << filename << "\n";
+    return NULL;
+  }
+
+  return parse_vrml(infile, filename);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: parse_vrml
+//  Description: Reads the indicated input stream and returns a corresponding
+//               VrmlScene, or NULL if there is a parse error.
+////////////////////////////////////////////////////////////////////
+VrmlScene *
+parse_vrml(istream &in, const string &filename) {
+  if (!get_standard_nodes()) {
+    cerr << "Internal error--unable to parse VRML.\n";
+    return NULL;
+  }
+
+  VrmlScene *scene = NULL;
+  VrmlNodeType::pushNameSpace();
+
+  vrml_init_parser(in, filename);
+  if (vrmlyyparse() == 0) {
+    scene = parsed_scene;
+  }
+  vrml_cleanup_parser();
+
+  VrmlNodeType::popNameSpace();
+
+  return scene;
+}
+
+#if 0
+int
+main(int argc, char *argv[]) {
+  if (argc < 2) {
+    cerr << "parse_vrml filename.wrl\n";
+    exit(1);
+  }
+
+  VrmlScene *scene = parse_vrml(argv[1]);
+  if (scene == (VrmlScene *)NULL) {
+    exit(1);
+  }
+
+  cout << *scene << "\n";
+  return (0);
+}
+#endif

+ 24 - 0
pandatool/src/vrml/parse_vrml.h

@@ -0,0 +1,24 @@
+// Filename: parse_vrml.h
+// Created by:  drose (24Jun99)
+// 
+////////////////////////////////////////////////////////////////////
+// Copyright (C) 1992,93,94,95,96,97  Walt Disney Imagineering, Inc.
+// 
+// These  coded  instructions,  statements,  data   structures   and
+// computer  programs contain unpublished proprietary information of
+// Walt Disney Imagineering and are protected by  Federal  copyright
+// law.  They may  not be  disclosed to third  parties  or copied or
+// duplicated in any form, in whole or in part,  without  the  prior
+// written consent of Walt Disney Imagineering Inc.
+////////////////////////////////////////////////////////////////////
+
+#ifndef PARSE_VRML_H
+#define PARSE_VRML_H
+
+#include "vrmlNode.h"
+#include "filename.h"
+
+VrmlScene *parse_vrml(Filename filename);
+VrmlScene *parse_vrml(istream &in, const string &filename);
+
+#endif

+ 488 - 0
pandatool/src/vrml/standardNodes.wrl

@@ -0,0 +1,488 @@
+#VRML V2.0 utf8
+#
+# **************************************************
+# * VRML 2.0 Parser
+# * Copyright (C) 1996 Silicon Graphics, Inc.
+# *
+# * Author(s)    : Gavin Bell
+# *                Daniel Woods (first port)
+# **************************************************
+#
+# Definitions for all of the nodes built-in to the spec.
+# Taken almost directly from the VRML 2.0 final spec:
+
+PROTO Anchor [
+  eventIn      MFNode   addChildren
+  eventIn      MFNode   removeChildren
+  exposedField MFNode   children        []
+  exposedField SFString description     "" 
+  exposedField MFString parameter       []
+  exposedField MFString url             []
+  field        SFVec3f  bboxCenter      0 0 0
+  field        SFVec3f  bboxSize        -1 -1 -1
+] { }
+
+PROTO Appearance [
+  exposedField SFNode material          NULL
+  exposedField SFNode texture           NULL
+  exposedField SFNode textureTransform  NULL
+] { }
+
+PROTO AudioClip [
+  exposedField   SFString description  ""
+  exposedField   SFBool   loop         FALSE
+  exposedField   SFFloat  pitch        1.0
+  exposedField   SFTime   startTime    0
+  exposedField   SFTime   stopTime     0
+  exposedField   MFString url          []
+  eventOut       SFTime   duration_changed
+  eventOut       SFBool   isActive
+] { }
+
+PROTO Background [
+  eventIn      SFBool   set_bind
+  exposedField MFFloat  groundAngle  []
+  exposedField MFColor  groundColor  []
+  exposedField MFString backUrl      []
+  exposedField MFString bottomUrl    []
+  exposedField MFString frontUrl     []
+  exposedField MFString leftUrl      []
+  exposedField MFString rightUrl     []
+  exposedField MFString topUrl       []
+  exposedField MFFloat  skyAngle     []
+  exposedField MFColor  skyColor     [ 0 0 0  ]
+  eventOut     SFBool   isBound
+] { }
+
+PROTO Billboard [
+  eventIn      MFNode   addChildren
+  eventIn      MFNode   removeChildren
+  exposedField SFVec3f  axisOfRotation  0 1 0
+  exposedField MFNode   children        []
+  field        SFVec3f  bboxCenter      0 0 0
+  field        SFVec3f  bboxSize        -1 -1 -1
+] { }
+
+PROTO Box [
+  field    SFVec3f size  2 2 2 
+] { }
+
+PROTO Collision [ 
+  eventIn      MFNode   addChildren
+  eventIn      MFNode   removeChildren
+  exposedField MFNode   children        []
+  exposedField SFBool   collide         TRUE
+  field        SFVec3f  bboxCenter      0 0 0
+  field        SFVec3f  bboxSize        -1 -1 -1
+  field        SFNode   proxy           NULL
+  eventOut     SFTime   collideTime
+] { }
+
+PROTO Color [
+  exposedField MFColor color     []
+] { }
+
+PROTO ColorInterpolator [
+  eventIn      SFFloat set_fraction
+  exposedField MFFloat key       []
+  exposedField MFColor keyValue  []
+  eventOut     SFColor value_changed
+] { }
+
+PROTO Cone [
+  field     SFFloat   bottomRadius 1
+  field     SFFloat   height       2
+  field     SFBool    side         TRUE
+  field     SFBool    bottom       TRUE
+] { }
+
+PROTO Coordinate [
+  exposedField MFVec3f point  []
+] { }
+
+PROTO CoordinateInterpolator [
+  eventIn      SFFloat set_fraction
+  exposedField MFFloat key       []
+  exposedField MFVec3f keyValue  []
+  eventOut     MFVec3f value_changed
+] { }
+
+PROTO Cylinder [
+  field    SFBool    bottom  TRUE
+  field    SFFloat   height  2
+  field    SFFloat   radius  1
+  field    SFBool    side    TRUE
+  field    SFBool    top     TRUE
+] { }
+
+PROTO CylinderSensor [
+  exposedField SFBool     autoOffset TRUE
+  exposedField SFFloat    diskAngle  0.262
+  exposedField SFBool     enabled    TRUE
+  exposedField SFFloat    maxAngle   -1
+  exposedField SFFloat    minAngle   0
+  exposedField SFFloat    offset     0
+  eventOut     SFBool     isActive
+  eventOut     SFRotation rotation_changed
+  eventOut     SFVec3f    trackPoint_changed
+] { }
+
+PROTO DirectionalLight [
+  exposedField SFFloat ambientIntensity  0 
+  exposedField SFColor color             1 1 1
+  exposedField SFVec3f direction         0 0 -1
+  exposedField SFFloat intensity         1 
+  exposedField SFBool  on                TRUE 
+] { }
+
+PROTO ElevationGrid [
+  eventIn      MFFloat  set_height
+  exposedField SFNode   color             NULL
+  exposedField SFNode   normal            NULL
+  exposedField SFNode   texCoord          NULL
+  field        SFBool   ccw               TRUE
+  field        SFBool   colorPerVertex    TRUE
+  field        SFFloat  creaseAngle       0
+  field        MFFloat  height            []
+  field        SFBool   normalPerVertex   TRUE
+  field        SFBool   solid             TRUE
+  field        SFInt32  xDimension        0
+  field        SFFloat  xSpacing          0.0
+  field        SFInt32  zDimension        0
+  field        SFFloat  zSpacing          0.0
+
+] { }
+
+PROTO Extrusion [
+  eventIn MFVec2f    set_crossSection
+  eventIn MFRotation set_orientation
+  eventIn MFVec2f    set_scale
+  eventIn MFVec3f    set_spine
+  field   SFBool     beginCap         TRUE
+  field   SFBool     ccw              TRUE
+  field   SFBool     convex           TRUE
+  field   SFFloat    creaseAngle      0
+  field   MFVec2f    crossSection     [ 1 1, 1 -1, -1 -1, -1 1, 1 1 ]
+  field   SFBool     endCap           TRUE
+  field   MFRotation orientation      0 0 1 0
+  field   MFVec2f    scale            1 1
+  field   SFBool     solid            TRUE
+  field   MFVec3f    spine            [ 0 0 0, 0 1 0 ]
+] { }
+
+PROTO Fog [
+  exposedField SFColor  color            1 1 1
+  exposedField SFString fogType          "LINEAR"
+  exposedField SFFloat  visibilityRange  0
+  eventIn      SFBool   set_bind
+  eventOut     SFBool   isBound
+] { }
+
+PROTO FontStyle [
+  field SFString family     "SERIF"
+  field SFBool   horizontal  TRUE
+  field MFString justify     "BEGIN"
+  field SFString language    ""
+  field SFBool   leftToRight TRUE
+  field SFFloat  size       1.0
+  field SFFloat  spacing     1.0
+  field SFString style       "PLAIN"
+  field SFBool   topToBottom TRUE
+] { }
+
+PROTO Group [
+  eventIn      MFNode  addChildren
+  eventIn      MFNode  removeChildren
+  exposedField MFNode  children   []
+  field        SFVec3f bboxCenter 0 0 0
+  field        SFVec3f bboxSize   -1 -1 -1
+] { }
+
+PROTO ImageTexture [
+  exposedField MFString url     []
+  field        SFBool   repeatS TRUE
+  field        SFBool   repeatT TRUE
+] { }
+
+PROTO IndexedFaceSet [ 
+  eventIn       MFInt32 set_colorIndex
+  eventIn       MFInt32 set_coordIndex
+  eventIn       MFInt32 set_normalIndex
+  eventIn       MFInt32 set_texCoordIndex
+  exposedField  SFNode  color             NULL
+  exposedField  SFNode  coord             NULL
+  exposedField  SFNode  normal            NULL
+  exposedField  SFNode  texCoord          NULL
+  field         SFBool  ccw               TRUE
+  field         MFInt32 colorIndex        []
+  field         SFBool  colorPerVertex    TRUE
+  field         SFBool  convex            TRUE
+  field         MFInt32 coordIndex        []
+  field         SFFloat creaseAngle       0
+  field         MFInt32 normalIndex       []
+  field         SFBool  normalPerVertex   TRUE
+  field         SFBool  solid             TRUE
+  field         MFInt32 texCoordIndex     []
+] { }
+
+PROTO IndexedLineSet [
+  eventIn       MFInt32 set_colorIndex
+  eventIn       MFInt32 set_coordIndex
+  exposedField  SFNode  color             NULL
+  exposedField  SFNode  coord             NULL
+  field         MFInt32 colorIndex        []
+  field         SFBool  colorPerVertex    TRUE
+  field         MFInt32 coordIndex        []
+] { }
+
+PROTO Inline [
+  exposedField MFString url        []
+  field        SFVec3f  bboxCenter 0 0 0
+  field        SFVec3f  bboxSize   -1 -1 -1
+] { }
+
+PROTO LOD [
+  exposedField MFNode  level    [] 
+  field        SFVec3f center   0 0 0
+  field        MFFloat range    [] 
+] { }
+
+PROTO Material [
+  exposedField SFFloat ambientIntensity  0.2
+  exposedField SFColor diffuseColor      0.8 0.8 0.8
+  exposedField SFColor emissiveColor     0 0 0
+  exposedField SFFloat shininess         0.2
+  exposedField SFColor specularColor     0 0 0
+  exposedField SFFloat transparency      0
+] { }
+
+PROTO MovieTexture [
+  exposedField SFBool   loop       FALSE
+  exposedField SFFloat  speed      1
+  exposedField SFTime   startTime  0
+  exposedField SFTime   stopTime   0
+  exposedField MFString url       []
+  field        SFBool   repeatS    TRUE
+  field        SFBool   repeatT    TRUE
+  eventOut     SFFloat  duration_changed
+  eventOut     SFBool   isActive
+] { }
+
+PROTO NavigationInfo [
+  eventIn      SFBool   set_bind
+  exposedField MFFloat  avatarSize       [ 0.25, 1.6, 0.75 ]
+  exposedField SFBool   headlight        TRUE
+  exposedField SFFloat  speed            1.0 
+  exposedField MFString type             "WALK" 
+  exposedField SFFloat  visibilityLimit  0.0 
+  eventOut     SFBool   isBound
+] { }
+
+PROTO Normal [
+  exposedField MFVec3f vector []
+] { }
+
+PROTO NormalInterpolator [
+  eventIn      SFFloat set_fraction
+  exposedField MFFloat key       []
+  exposedField MFVec3f keyValue  []
+  eventOut     MFVec3f value_changed
+] { }
+
+PROTO OrientationInterpolator [
+  eventIn      SFFloat    set_fraction
+  exposedField MFFloat    key       []
+  exposedField MFRotation keyValue  []
+  eventOut     SFRotation value_changed
+] { }
+
+PROTO PixelTexture [
+  exposedField SFImage  image      0 0 0
+  field        SFBool   repeatS    TRUE
+  field        SFBool   repeatT    TRUE
+] { }
+
+PROTO PlaneSensor [
+  exposedField SFBool  autoOffset  TRUE
+  exposedField SFBool  enabled     TRUE
+  exposedField SFVec2f maxPosition -1 -1
+  exposedField SFVec2f minPosition 0 0
+  exposedField SFVec3f offset      0 0 0
+  eventOut     SFBool  isActive
+  eventOut     SFVec3f trackPoint_changed
+  eventOut     SFVec3f translation_changed
+] { }
+
+PROTO PointLight [
+  exposedField SFFloat ambientIntensity  0 
+  exposedField SFVec3f attenuation       1 0 0
+  exposedField SFColor color             1 1 1 
+  exposedField SFFloat intensity         1
+  exposedField SFVec3f location          0 0 0
+  exposedField SFBool  on                TRUE 
+  exposedField SFFloat radius            100
+] { }
+
+PROTO PointSet [
+  exposedField  SFNode  color      NULL
+  exposedField  SFNode  coord      NULL
+] { }
+
+PROTO PositionInterpolator [
+  eventIn      SFFloat set_fraction
+  exposedField MFFloat key       []
+  exposedField MFVec3f keyValue  []
+  eventOut     SFVec3f value_changed
+] { }
+
+PROTO ProximitySensor [
+  exposedField SFVec3f    center      0 0 0
+  exposedField SFVec3f    size        0 0 0
+  exposedField SFBool     enabled     TRUE
+  eventOut     SFBool     isActive
+  eventOut     SFVec3f    position_changed
+  eventOut     SFRotation orientation_changed
+  eventOut     SFTime     enterTime
+  eventOut     SFTime     exitTime
+] { }
+
+PROTO ScalarInterpolator [
+  eventIn      SFFloat set_fraction
+  exposedField MFFloat key       []
+  exposedField MFFloat keyValue  []
+  eventOut     SFFloat value_changed
+] { }
+
+PROTO Script [
+  exposedField MFString url           [ ] 
+  field        SFBool   directOutput  FALSE
+  field        SFBool   mustEvaluate  FALSE
+] { }
+
+PROTO Shape [
+  field SFNode appearance NULL
+  field SFNode geometry   NULL
+] { }
+
+PROTO Sound [
+  exposedField SFVec3f  direction     0 0 1
+  exposedField SFFloat  intensity     1
+  exposedField SFVec3f  location      0 0 0
+  exposedField SFFloat  maxBack       10
+  exposedField SFFloat  maxFront      10
+  exposedField SFFloat  minBack       1
+  exposedField SFFloat  minFront      1
+  exposedField SFFloat  priority      0
+  exposedField SFNode   source        NULL
+  field        SFBool   spatialize    TRUE
+] { }
+
+PROTO Sphere [
+  field SFFloat radius  1
+] { }
+
+PROTO SphereSensor [
+  exposedField SFBool     autoOffset TRUE
+  exposedField SFBool     enabled    TRUE
+  exposedField SFRotation offset     0 1 0 0
+  eventOut     SFBool     isActive
+  eventOut     SFRotation rotation_changed
+  eventOut     SFVec3f    trackPoint_changed
+] { }
+
+PROTO SpotLight [
+  exposedField SFFloat ambientIntensity  0 
+  exposedField SFVec3f attenuation       1 0 0
+  exposedField SFFloat beamWidth         1.570796
+  exposedField SFColor color             1 1 1 
+  exposedField SFFloat cutOffAngle       0.785398 
+  exposedField SFVec3f direction         0 0 -1
+  exposedField SFFloat intensity         1  
+  exposedField SFVec3f location          0 0 0  
+  exposedField SFBool  on                TRUE
+  exposedField SFFloat radius            100
+] { }
+
+PROTO Switch [
+  exposedField    MFNode  choice     []
+  exposedField    SFInt32 whichChild -1
+] { }
+
+PROTO Text [
+  exposedField  MFString string    []
+  field         SFNode   fontStyle NULL
+  field         MFFloat  length    []
+  field         SFFloat  maxExtent 0.0
+] { }
+
+PROTO TextureCoordinate [
+  exposedField MFVec2f point []
+] { }
+
+PROTO TextureTransform [
+  exposedField SFVec2f center      0 0
+  exposedField SFFloat rotation    0
+  exposedField SFVec2f scale       1 1
+  exposedField SFVec2f translation 0 0
+] { }
+
+PROTO TimeSensor [
+  exposedField SFTime   cycleInterval 1
+  exposedField SFBool   enabled       TRUE
+  exposedField SFBool   loop          FALSE
+  exposedField SFTime   startTime     0
+  exposedField SFTime   stopTime      0
+  eventOut     SFTime   cycleTime
+  eventOut     SFFloat  fraction_changed
+  eventOut     SFBool   isActive
+  eventOut     SFTime   time
+] { }
+
+PROTO TouchSensor [
+  exposedField SFBool  enabled TRUE
+  eventOut     SFVec3f hitNormal_changed
+  eventOut     SFVec3f hitPoint_changed
+  eventOut     SFVec2f hitTexCoord_changed
+  eventOut     SFBool  isActive
+  eventOut     SFBool  isOver
+  eventOut     SFTime  touchTime
+] { }
+
+PROTO Transform [
+  eventIn      MFNode      addChildren
+  eventIn      MFNode      removeChildren
+  exposedField SFVec3f     center           0 0 0
+  exposedField MFNode      children         []
+  exposedField SFRotation  rotation         0 0 1  0
+  exposedField SFVec3f     scale            1 1 1
+  exposedField SFRotation  scaleOrientation 0 0 1  0
+  exposedField SFVec3f     translation      0 0 0
+  field        SFVec3f     bboxCenter       0 0 0
+  field        SFVec3f     bboxSize         -1 -1 -1
+] { }
+
+PROTO Viewpoint [
+  eventIn      SFBool     set_bind
+  exposedField SFFloat    fieldOfView    0.785398
+  exposedField SFBool     jump           TRUE
+  exposedField SFRotation orientation    0 0 1  0
+  exposedField SFVec3f    position       0 0 10
+  field        SFString   description    ""
+  eventOut     SFTime     bindTime
+  eventOut     SFBool     isBound
+] { }
+
+PROTO VisibilitySensor [
+  exposedField SFVec3f center   0 0 0
+  exposedField SFBool  enabled  TRUE
+  exposedField SFVec3f size     0 0 0
+  eventOut     SFTime  enterTime
+  eventOut     SFTime  exitTime
+  eventOut     SFBool  isActive
+] { }
+
+PROTO WorldInfo [
+  field MFString info  []
+  field SFString title ""
+] { }
+

+ 1340 - 0
pandatool/src/vrml/standardNodes.wrl.c

@@ -0,0 +1,1340 @@
+
+/*
+ * This table was generated by the command:
+ *
+ * bin2c -n standard_nodes_data -o standardNodes.wrl.c standardNodes.wrl
+ */
+
+const unsigned char standard_nodes_data[] = {
+  0x23, 0x56, 0x52, 0x4d, 0x4c, 0x20, 0x56, 0x32, 0x2e, 0x30, 0x20,
+  0x75, 0x74, 0x66, 0x38, 0x0a, 0x23, 0x0a, 0x23, 0x20, 0x2a, 0x2a,
+  0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
+  0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
+  0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
+  0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
+  0x2a, 0x2a, 0x2a, 0x2a, 0x0a, 0x23, 0x20, 0x2a, 0x20, 0x56, 0x52,
+  0x4d, 0x4c, 0x20, 0x32, 0x2e, 0x30, 0x20, 0x50, 0x61, 0x72, 0x73,
+  0x65, 0x72, 0x0a, 0x23, 0x20, 0x2a, 0x20, 0x43, 0x6f, 0x70, 0x79,
+  0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x43, 0x29, 0x20, 0x31,
+  0x39, 0x39, 0x36, 0x20, 0x53, 0x69, 0x6c, 0x69, 0x63, 0x6f, 0x6e,
+  0x20, 0x47, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2c, 0x20,
+  0x49, 0x6e, 0x63, 0x2e, 0x0a, 0x23, 0x20, 0x2a, 0x0a, 0x23, 0x20,
+  0x2a, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x28, 0x73, 0x29,
+  0x20, 0x20, 0x20, 0x20, 0x3a, 0x20, 0x47, 0x61, 0x76, 0x69, 0x6e,
+  0x20, 0x42, 0x65, 0x6c, 0x6c, 0x0a, 0x23, 0x20, 0x2a, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x44, 0x61, 0x6e, 0x69, 0x65, 0x6c, 0x20, 0x57,
+  0x6f, 0x6f, 0x64, 0x73, 0x20, 0x28, 0x66, 0x69, 0x72, 0x73, 0x74,
+  0x20, 0x70, 0x6f, 0x72, 0x74, 0x29, 0x0a, 0x23, 0x20, 0x2a, 0x2a,
+  0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
+  0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
+  0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
+  0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
+  0x2a, 0x2a, 0x2a, 0x2a, 0x0a, 0x23, 0x0a, 0x23, 0x20, 0x44, 0x65,
+  0x66, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x66,
+  0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x66, 0x20, 0x74,
+  0x68, 0x65, 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x20, 0x62, 0x75,
+  0x69, 0x6c, 0x74, 0x2d, 0x69, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x74,
+  0x68, 0x65, 0x20, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x0a, 0x23, 0x20,
+  0x54, 0x61, 0x6b, 0x65, 0x6e, 0x20, 0x61, 0x6c, 0x6d, 0x6f, 0x73,
+  0x74, 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6c, 0x79, 0x20,
+  0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x56, 0x52,
+  0x4d, 0x4c, 0x20, 0x32, 0x2e, 0x30, 0x20, 0x66, 0x69, 0x6e, 0x61,
+  0x6c, 0x20, 0x73, 0x70, 0x65, 0x63, 0x3a, 0x0a, 0x0a, 0x50, 0x52,
+  0x4f, 0x54, 0x4f, 0x20, 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x20,
+  0x5b, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x6e,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4d, 0x46, 0x4e, 0x6f, 0x64,
+  0x65, 0x20, 0x20, 0x20, 0x61, 0x64, 0x64, 0x43, 0x68, 0x69, 0x6c,
+  0x64, 0x72, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e,
+  0x74, 0x49, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4d, 0x46,
+  0x4e, 0x6f, 0x64, 0x65, 0x20, 0x20, 0x20, 0x72, 0x65, 0x6d, 0x6f,
+  0x76, 0x65, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x0a,
+  0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x4d, 0x46, 0x4e, 0x6f, 0x64, 0x65, 0x20,
+  0x20, 0x20, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x20,
+  0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x53, 0x46, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67,
+  0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
+  0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x22, 0x20, 0x0a, 0x20,
+  0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x4d, 0x46, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67,
+  0x20, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20,
+  0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x4d, 0x46, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20,
+  0x75, 0x72, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x66,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x20, 0x62,
+  0x62, 0x6f, 0x78, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x0a, 0x20,
+  0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20,
+  0x20, 0x62, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x31, 0x20, 0x2d, 0x31,
+  0x20, 0x2d, 0x31, 0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a,
+  0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x41, 0x70, 0x70, 0x65, 0x61,
+  0x72, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x65,
+  0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x53, 0x46, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x6d, 0x61, 0x74,
+  0x65, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x0a, 0x20, 0x20,
+  0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x53, 0x46, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x74, 0x65,
+  0x78, 0x74, 0x75, 0x72, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x0a, 0x20,
+  0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x53, 0x46, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x74,
+  0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73,
+  0x66, 0x6f, 0x72, 0x6d, 0x20, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x0a,
+  0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54,
+  0x4f, 0x20, 0x41, 0x75, 0x64, 0x69, 0x6f, 0x43, 0x6c, 0x69, 0x70,
+  0x20, 0x5b, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65,
+  0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x53, 0x46,
+  0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x64, 0x65, 0x73, 0x63,
+  0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x20, 0x22, 0x22,
+  0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x53, 0x46, 0x42, 0x6f,
+  0x6f, 0x6c, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, 0x41, 0x4c, 0x53,
+  0x45, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64,
+  0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x53, 0x46, 0x46,
+  0x6c, 0x6f, 0x61, 0x74, 0x20, 0x20, 0x70, 0x69, 0x74, 0x63, 0x68,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x2e, 0x30,
+  0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x53, 0x46, 0x54, 0x69,
+  0x6d, 0x65, 0x20, 0x20, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54,
+  0x69, 0x6d, 0x65, 0x20, 0x20, 0x20, 0x20, 0x30, 0x0a, 0x20, 0x20,
+  0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x20, 0x20, 0x53, 0x46, 0x54, 0x69, 0x6d, 0x65, 0x20,
+  0x20, 0x20, 0x73, 0x74, 0x6f, 0x70, 0x54, 0x69, 0x6d, 0x65, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70,
+  0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20,
+  0x20, 0x4d, 0x46, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x75,
+  0x72, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74,
+  0x4f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53,
+  0x46, 0x54, 0x69, 0x6d, 0x65, 0x20, 0x20, 0x20, 0x64, 0x75, 0x72,
+  0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67,
+  0x65, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f,
+  0x75, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46,
+  0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x69, 0x73, 0x41, 0x63,
+  0x74, 0x69, 0x76, 0x65, 0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a,
+  0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x42, 0x61, 0x63, 0x6b,
+  0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x5b, 0x0a, 0x20, 0x20,
+  0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20,
+  0x73, 0x65, 0x74, 0x5f, 0x62, 0x69, 0x6e, 0x64, 0x0a, 0x20, 0x20,
+  0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x4d, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x20,
+  0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x41, 0x6e, 0x67, 0x6c, 0x65,
+  0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f,
+  0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x4d, 0x46,
+  0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x20, 0x67, 0x72, 0x6f, 0x75,
+  0x6e, 0x64, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x20, 0x5b, 0x5d,
+  0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x4d, 0x46, 0x53, 0x74, 0x72, 0x69,
+  0x6e, 0x67, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x55, 0x72, 0x6c, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x65,
+  0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x4d, 0x46, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x62,
+  0x6f, 0x74, 0x74, 0x6f, 0x6d, 0x55, 0x72, 0x6c, 0x20, 0x20, 0x20,
+  0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73,
+  0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x4d, 0x46, 0x53,
+  0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x72, 0x6f, 0x6e, 0x74,
+  0x55, 0x72, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x0a,
+  0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x4d, 0x46, 0x53, 0x74, 0x72, 0x69, 0x6e,
+  0x67, 0x20, 0x6c, 0x65, 0x66, 0x74, 0x55, 0x72, 0x6c, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x65, 0x78,
+  0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20,
+  0x4d, 0x46, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x69,
+  0x67, 0x68, 0x74, 0x55, 0x72, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65,
+  0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x4d, 0x46, 0x53, 0x74,
+  0x72, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x70, 0x55, 0x72, 0x6c,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x20,
+  0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x4d, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20,
+  0x20, 0x73, 0x6b, 0x79, 0x41, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70,
+  0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x4d,
+  0x46, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x20, 0x73, 0x6b, 0x79,
+  0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b,
+  0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x20, 0x5d, 0x0a, 0x20,
+  0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20,
+  0x20, 0x69, 0x73, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x0a, 0x5d, 0x20,
+  0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20,
+  0x42, 0x69, 0x6c, 0x6c, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x20, 0x5b,
+  0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x4d, 0x46, 0x4e, 0x6f, 0x64, 0x65,
+  0x20, 0x20, 0x20, 0x61, 0x64, 0x64, 0x43, 0x68, 0x69, 0x6c, 0x64,
+  0x72, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74,
+  0x49, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4d, 0x46, 0x4e,
+  0x6f, 0x64, 0x65, 0x20, 0x20, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76,
+  0x65, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x0a, 0x20,
+  0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20,
+  0x20, 0x61, 0x78, 0x69, 0x73, 0x4f, 0x66, 0x52, 0x6f, 0x74, 0x61,
+  0x74, 0x69, 0x6f, 0x6e, 0x20, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30,
+  0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x4d, 0x46, 0x4e, 0x6f, 0x64, 0x65,
+  0x20, 0x20, 0x20, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x0a,
+  0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66,
+  0x20, 0x20, 0x62, 0x62, 0x6f, 0x78, 0x43, 0x65, 0x6e, 0x74, 0x65,
+  0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20,
+  0x30, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x56, 0x65, 0x63,
+  0x33, 0x66, 0x20, 0x20, 0x62, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a,
+  0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x31,
+  0x20, 0x2d, 0x31, 0x20, 0x2d, 0x31, 0x0a, 0x5d, 0x20, 0x7b, 0x20,
+  0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x42, 0x6f,
+  0x78, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66,
+  0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x32, 0x20, 0x32, 0x20,
+  0x32, 0x20, 0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50,
+  0x52, 0x4f, 0x54, 0x4f, 0x20, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x73,
+  0x69, 0x6f, 0x6e, 0x20, 0x5b, 0x20, 0x0a, 0x20, 0x20, 0x65, 0x76,
+  0x65, 0x6e, 0x74, 0x49, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x4d, 0x46, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x20, 0x20, 0x61, 0x64,
+  0x64, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x0a, 0x20,
+  0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x4d, 0x46, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x20,
+  0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x43, 0x68, 0x69, 0x6c,
+  0x64, 0x72, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f,
+  0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x4d, 0x46,
+  0x4e, 0x6f, 0x64, 0x65, 0x20, 0x20, 0x20, 0x63, 0x68, 0x69, 0x6c,
+  0x64, 0x72, 0x65, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73,
+  0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x42,
+  0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6c, 0x6c, 0x69,
+  0x64, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46,
+  0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x20, 0x62, 0x62, 0x6f, 0x78,
+  0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x66, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x20, 0x62, 0x62,
+  0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x2d, 0x31, 0x20, 0x2d, 0x31, 0x20, 0x2d, 0x31,
+  0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x4e, 0x6f, 0x64, 0x65,
+  0x20, 0x20, 0x20, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4e, 0x55, 0x4c,
+  0x4c, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75,
+  0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x54, 0x69, 0x6d,
+  0x65, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65,
+  0x54, 0x69, 0x6d, 0x65, 0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a,
+  0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x43, 0x6f, 0x6c, 0x6f,
+  0x72, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73,
+  0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x4d, 0x46, 0x43,
+  0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x5d, 0x20, 0x7b, 0x20,
+  0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x43, 0x6f,
+  0x6c, 0x6f, 0x72, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x6f, 0x6c,
+  0x61, 0x74, 0x6f, 0x72, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x65, 0x76,
+  0x65, 0x6e, 0x74, 0x49, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x73, 0x65, 0x74,
+  0x5f, 0x66, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20,
+  0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x4d, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20,
+  0x6b, 0x65, 0x79, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b,
+  0x5d, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64,
+  0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x4d, 0x46, 0x43, 0x6f, 0x6c,
+  0x6f, 0x72, 0x20, 0x6b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65,
+  0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e,
+  0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46,
+  0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65,
+  0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x0a, 0x5d, 0x20,
+  0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20,
+  0x43, 0x6f, 0x6e, 0x65, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x66, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x46,
+  0x6c, 0x6f, 0x61, 0x74, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x74, 0x74,
+  0x6f, 0x6d, 0x52, 0x61, 0x64, 0x69, 0x75, 0x73, 0x20, 0x31, 0x0a,
+  0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x20, 0x20,
+  0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x32, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c,
+  0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x64, 0x65, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a,
+  0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x20,
+  0x62, 0x6f, 0x74, 0x74, 0x6f, 0x6d, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x5d, 0x20, 0x7b, 0x20,
+  0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x43, 0x6f,
+  0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x20, 0x5b, 0x0a,
+  0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x4d, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66,
+  0x20, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x20, 0x20, 0x5b, 0x5d, 0x0a,
+  0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54,
+  0x4f, 0x20, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74,
+  0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x6f, 0x6c, 0x61, 0x74,
+  0x6f, 0x72, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e,
+  0x74, 0x49, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46,
+  0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x66,
+  0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x65,
+  0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x4d, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x6b, 0x65,
+  0x79, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x0a,
+  0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x4d, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66,
+  0x20, 0x6b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x20,
+  0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f,
+  0x75, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4d, 0x46, 0x56, 0x65,
+  0x63, 0x33, 0x66, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x63,
+  0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x0a, 0x5d, 0x20, 0x7b, 0x20,
+  0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x43, 0x79,
+  0x6c, 0x69, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x5b, 0x0a, 0x20, 0x20,
+  0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46,
+  0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x62, 0x6f, 0x74,
+  0x74, 0x6f, 0x6d, 0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x20,
+  0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x53,
+  0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x20, 0x20, 0x68, 0x65,
+  0x69, 0x67, 0x68, 0x74, 0x20, 0x20, 0x32, 0x0a, 0x20, 0x20, 0x66,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x46,
+  0x6c, 0x6f, 0x61, 0x74, 0x20, 0x20, 0x20, 0x72, 0x61, 0x64, 0x69,
+  0x75, 0x73, 0x20, 0x20, 0x31, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f,
+  0x6c, 0x20, 0x20, 0x20, 0x20, 0x73, 0x69, 0x64, 0x65, 0x20, 0x20,
+  0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20, 0x66, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x42, 0x6f,
+  0x6f, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x74, 0x6f, 0x70, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x5d, 0x20, 0x7b,
+  0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x43,
+  0x79, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x72, 0x53, 0x65, 0x6e, 0x73,
+  0x6f, 0x72, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f,
+  0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46,
+  0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x75,
+  0x74, 0x6f, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x20, 0x54, 0x52,
+  0x55, 0x45, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65,
+  0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x46, 0x6c,
+  0x6f, 0x61, 0x74, 0x20, 0x20, 0x20, 0x20, 0x64, 0x69, 0x73, 0x6b,
+  0x41, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x20, 0x30, 0x2e, 0x32, 0x36,
+  0x32, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64,
+  0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f,
+  0x6c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x61, 0x62, 0x6c,
+  0x65, 0x64, 0x20, 0x20, 0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a,
+  0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74,
+  0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x78, 0x41, 0x6e, 0x67, 0x6c,
+  0x65, 0x20, 0x20, 0x20, 0x2d, 0x31, 0x0a, 0x20, 0x20, 0x65, 0x78,
+  0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20,
+  0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x20, 0x20, 0x20,
+  0x6d, 0x69, 0x6e, 0x41, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x20, 0x20,
+  0x30, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64,
+  0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f,
+  0x61, 0x74, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65,
+  0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x65,
+  0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x69, 0x73, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x0a, 0x20,
+  0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x53, 0x46, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69,
+  0x6f, 0x6e, 0x20, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+  0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x0a, 0x20, 0x20,
+  0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x20,
+  0x20, 0x20, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x50, 0x6f, 0x69, 0x6e,
+  0x74, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x0a, 0x5d,
+  0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f,
+  0x20, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61,
+  0x6c, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x20, 0x5b, 0x0a, 0x20, 0x20,
+  0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x61,
+  0x6d, 0x62, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x6e,
+  0x73, 0x69, 0x74, 0x79, 0x20, 0x20, 0x30, 0x20, 0x0a, 0x20, 0x20,
+  0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x53, 0x46, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x63,
+  0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x31,
+  0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33,
+  0x66, 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20,
+  0x30, 0x20, 0x2d, 0x31, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f,
+  0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46,
+  0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e,
+  0x73, 0x69, 0x74, 0x79, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x31, 0x20, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f,
+  0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46,
+  0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x6f, 0x6e, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x20, 0x0a, 0x5d, 0x20, 0x7b,
+  0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x45,
+  0x6c, 0x65, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x47, 0x72, 0x69,
+  0x64, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74,
+  0x49, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4d, 0x46, 0x46,
+  0x6c, 0x6f, 0x61, 0x74, 0x20, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x68,
+  0x65, 0x69, 0x67, 0x68, 0x74, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70,
+  0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53,
+  0x46, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6c,
+  0x6f, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x0a, 0x20, 0x20,
+  0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x53, 0x46, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x20, 0x20,
+  0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4e, 0x55, 0x4c, 0x4c,
+  0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x4e, 0x6f, 0x64, 0x65,
+  0x20, 0x20, 0x20, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4e,
+  0x55, 0x4c, 0x4c, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x42,
+  0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x63, 0x63, 0x77, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20, 0x66, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x63, 0x6f,
+  0x6c, 0x6f, 0x72, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65,
+  0x78, 0x20, 0x20, 0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x20,
+  0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20,
+  0x20, 0x63, 0x72, 0x65, 0x61, 0x73, 0x65, 0x41, 0x6e, 0x67, 0x6c,
+  0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x0a, 0x20,
+  0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x4d, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20,
+  0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x0a,
+  0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20,
+  0x20, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x50, 0x65, 0x72,
+  0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x20, 0x20, 0x20, 0x54, 0x52,
+  0x55, 0x45, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x42, 0x6f,
+  0x6f, 0x6c, 0x20, 0x20, 0x20, 0x73, 0x6f, 0x6c, 0x69, 0x64, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53,
+  0x46, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x20, 0x20, 0x78, 0x44, 0x69,
+  0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53,
+  0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x20, 0x78, 0x53, 0x70,
+  0x61, 0x63, 0x69, 0x6e, 0x67, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x30, 0x2e, 0x30, 0x0a, 0x20, 0x20, 0x66,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x53, 0x46, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x20, 0x20, 0x7a,
+  0x44, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x66,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x20, 0x7a,
+  0x53, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x2e, 0x30, 0x0a, 0x0a,
+  0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54,
+  0x4f, 0x20, 0x45, 0x78, 0x74, 0x72, 0x75, 0x73, 0x69, 0x6f, 0x6e,
+  0x20, 0x5b, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49,
+  0x6e, 0x20, 0x4d, 0x46, 0x56, 0x65, 0x63, 0x32, 0x66, 0x20, 0x20,
+  0x20, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x63, 0x72, 0x6f, 0x73, 0x73,
+  0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x65,
+  0x76, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x20, 0x4d, 0x46, 0x52, 0x6f,
+  0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x65, 0x74, 0x5f,
+  0x6f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+  0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x20,
+  0x4d, 0x46, 0x56, 0x65, 0x63, 0x32, 0x66, 0x20, 0x20, 0x20, 0x20,
+  0x73, 0x65, 0x74, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x0a, 0x20,
+  0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x20, 0x4d, 0x46,
+  0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65,
+  0x74, 0x5f, 0x73, 0x70, 0x69, 0x6e, 0x65, 0x0a, 0x20, 0x20, 0x66,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x53, 0x46, 0x42, 0x6f,
+  0x6f, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x65, 0x67, 0x69,
+  0x6e, 0x43, 0x61, 0x70, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20, 0x66, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f,
+  0x6c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x63, 0x77, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x78,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x20, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74,
+  0x20, 0x20, 0x20, 0x20, 0x63, 0x72, 0x65, 0x61, 0x73, 0x65, 0x41,
+  0x6e, 0x67, 0x6c, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30,
+  0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20,
+  0x4d, 0x46, 0x56, 0x65, 0x63, 0x32, 0x66, 0x20, 0x20, 0x20, 0x20,
+  0x63, 0x72, 0x6f, 0x73, 0x73, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f,
+  0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x20, 0x31, 0x20, 0x31,
+  0x2c, 0x20, 0x31, 0x20, 0x2d, 0x31, 0x2c, 0x20, 0x2d, 0x31, 0x20,
+  0x2d, 0x31, 0x2c, 0x20, 0x2d, 0x31, 0x20, 0x31, 0x2c, 0x20, 0x31,
+  0x20, 0x31, 0x20, 0x5d, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x43, 0x61, 0x70, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54,
+  0x52, 0x55, 0x45, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x20, 0x20, 0x4d, 0x46, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69,
+  0x6f, 0x6e, 0x20, 0x6f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74,
+  0x69, 0x6f, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20,
+  0x30, 0x20, 0x31, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x20, 0x20, 0x4d, 0x46, 0x56, 0x65, 0x63, 0x32,
+  0x66, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x31, 0x20, 0x31, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x73, 0x6f, 0x6c, 0x69, 0x64, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x52,
+  0x55, 0x45, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20,
+  0x20, 0x20, 0x4d, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x20,
+  0x20, 0x20, 0x73, 0x70, 0x69, 0x6e, 0x65, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x20, 0x30,
+  0x20, 0x30, 0x20, 0x30, 0x2c, 0x20, 0x30, 0x20, 0x31, 0x20, 0x30,
+  0x20, 0x5d, 0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50,
+  0x52, 0x4f, 0x54, 0x4f, 0x20, 0x46, 0x6f, 0x67, 0x20, 0x5b, 0x0a,
+  0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x43, 0x6f, 0x6c, 0x6f, 0x72,
+  0x20, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x20, 0x31,
+  0x20, 0x31, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65,
+  0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x53, 0x74,
+  0x72, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x6f, 0x67, 0x54, 0x79, 0x70,
+  0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x22, 0x4c, 0x49, 0x4e, 0x45, 0x41, 0x52, 0x22, 0x0a, 0x20, 0x20,
+  0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x20,
+  0x76, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52,
+  0x61, 0x6e, 0x67, 0x65, 0x20, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x65,
+  0x76, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x73,
+  0x65, 0x74, 0x5f, 0x62, 0x69, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65,
+  0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x69,
+  0x73, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x0a, 0x5d, 0x20, 0x7b, 0x20,
+  0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x46, 0x6f,
+  0x6e, 0x74, 0x53, 0x74, 0x79, 0x6c, 0x65, 0x20, 0x5b, 0x0a, 0x20,
+  0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x53, 0x74,
+  0x72, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x53, 0x45, 0x52, 0x49, 0x46,
+  0x22, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53,
+  0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x68, 0x6f, 0x72,
+  0x69, 0x7a, 0x6f, 0x6e, 0x74, 0x61, 0x6c, 0x20, 0x20, 0x54, 0x52,
+  0x55, 0x45, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20,
+  0x4d, 0x46, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x6a, 0x75,
+  0x73, 0x74, 0x69, 0x66, 0x79, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+  0x42, 0x45, 0x47, 0x49, 0x4e, 0x22, 0x0a, 0x20, 0x20, 0x66, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x53, 0x74, 0x72, 0x69, 0x6e,
+  0x67, 0x20, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x20,
+  0x20, 0x20, 0x20, 0x22, 0x22, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20,
+  0x20, 0x6c, 0x65, 0x66, 0x74, 0x54, 0x6f, 0x52, 0x69, 0x67, 0x68,
+  0x74, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20, 0x66, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74,
+  0x20, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x31, 0x2e, 0x30, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20,
+  0x20, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6e, 0x67, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x31, 0x2e, 0x30, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x53, 0x46, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67,
+  0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x22, 0x50, 0x4c, 0x41, 0x49, 0x4e, 0x22, 0x0a, 0x20,
+  0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x42, 0x6f,
+  0x6f, 0x6c, 0x20, 0x20, 0x20, 0x74, 0x6f, 0x70, 0x54, 0x6f, 0x42,
+  0x6f, 0x74, 0x74, 0x6f, 0x6d, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a,
+  0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54,
+  0x4f, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x5b, 0x0a, 0x20,
+  0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x4d, 0x46, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x20,
+  0x61, 0x64, 0x64, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e,
+  0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x4d, 0x46, 0x4e, 0x6f, 0x64, 0x65,
+  0x20, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x43, 0x68, 0x69,
+  0x6c, 0x64, 0x72, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70,
+  0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x4d,
+  0x46, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x20, 0x63, 0x68, 0x69, 0x6c,
+  0x64, 0x72, 0x65, 0x6e, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x20,
+  0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20,
+  0x62, 0x62, 0x6f, 0x78, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20,
+  0x30, 0x20, 0x30, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53,
+  0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x62, 0x62, 0x6f, 0x78,
+  0x53, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x2d, 0x31, 0x20, 0x2d,
+  0x31, 0x20, 0x2d, 0x31, 0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a,
+  0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x49, 0x6d, 0x61, 0x67,
+  0x65, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x20, 0x5b, 0x0a,
+  0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x4d, 0x46, 0x53, 0x74, 0x72, 0x69, 0x6e,
+  0x67, 0x20, 0x75, 0x72, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b,
+  0x5d, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f,
+  0x6c, 0x20, 0x20, 0x20, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x53,
+  0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53,
+  0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x72, 0x65, 0x70,
+  0x65, 0x61, 0x74, 0x54, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x5d,
+  0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f,
+  0x20, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x64, 0x46, 0x61, 0x63,
+  0x65, 0x53, 0x65, 0x74, 0x20, 0x5b, 0x20, 0x0a, 0x20, 0x20, 0x65,
+  0x76, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x4d, 0x46, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x20, 0x73,
+  0x65, 0x74, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x49, 0x6e, 0x64,
+  0x65, 0x78, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49,
+  0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4d, 0x46, 0x49,
+  0x6e, 0x74, 0x33, 0x32, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x63, 0x6f,
+  0x6f, 0x72, 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x0a, 0x20, 0x20,
+  0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x4d, 0x46, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x20,
+  0x73, 0x65, 0x74, 0x5f, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x49,
+  0x6e, 0x64, 0x65, 0x78, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e,
+  0x74, 0x49, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4d,
+  0x46, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x20, 0x73, 0x65, 0x74, 0x5f,
+  0x74, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x64,
+  0x65, 0x78, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65,
+  0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x53, 0x46, 0x4e,
+  0x6f, 0x64, 0x65, 0x20, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70,
+  0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20,
+  0x53, 0x46, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x20, 0x63, 0x6f, 0x6f,
+  0x72, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x0a, 0x20, 0x20,
+  0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x20, 0x53, 0x46, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x20,
+  0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4e, 0x55, 0x4c, 0x4c,
+  0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x53, 0x46, 0x4e, 0x6f, 0x64,
+  0x65, 0x20, 0x20, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4e,
+  0x55, 0x4c, 0x4c, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46,
+  0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x63, 0x63, 0x77, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20, 0x66, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x4d, 0x46, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x20, 0x63, 0x6f,
+  0x6c, 0x6f, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x66,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x63,
+  0x6f, 0x6c, 0x6f, 0x72, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74,
+  0x65, 0x78, 0x20, 0x20, 0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a,
+  0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c,
+  0x20, 0x20, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x78, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x52,
+  0x55, 0x45, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4d, 0x46, 0x49,
+  0x6e, 0x74, 0x33, 0x32, 0x20, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x49,
+  0x6e, 0x64, 0x65, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46,
+  0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x63, 0x72, 0x65, 0x61, 0x73,
+  0x65, 0x41, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4d, 0x46,
+  0x49, 0x6e, 0x74, 0x33, 0x32, 0x20, 0x6e, 0x6f, 0x72, 0x6d, 0x61,
+  0x6c, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53,
+  0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x6e, 0x6f, 0x72, 0x6d,
+  0x61, 0x6c, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78,
+  0x20, 0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20, 0x66,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x73,
+  0x6f, 0x6c, 0x69, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a,
+  0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x4d, 0x46, 0x49, 0x6e, 0x74, 0x33,
+  0x32, 0x20, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x49,
+  0x6e, 0x64, 0x65, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d,
+  0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f,
+  0x54, 0x4f, 0x20, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x64, 0x4c,
+  0x69, 0x6e, 0x65, 0x53, 0x65, 0x74, 0x20, 0x5b, 0x0a, 0x20, 0x20,
+  0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x4d, 0x46, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x20,
+  0x73, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x49, 0x6e,
+  0x64, 0x65, 0x78, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74,
+  0x49, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4d, 0x46,
+  0x49, 0x6e, 0x74, 0x33, 0x32, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x63,
+  0x6f, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x0a, 0x20,
+  0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x20, 0x53, 0x46, 0x4e, 0x6f, 0x64, 0x65, 0x20,
+  0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4e, 0x55, 0x4c,
+  0x4c, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64,
+  0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x53, 0x46, 0x4e, 0x6f,
+  0x64, 0x65, 0x20, 0x20, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x4e, 0x55, 0x4c, 0x4c, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4d,
+  0x46, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x20, 0x63, 0x6f, 0x6c, 0x6f,
+  0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x63, 0x6f, 0x6c,
+  0x6f, 0x72, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78,
+  0x20, 0x20, 0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20,
+  0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x4d, 0x46, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x20,
+  0x63, 0x6f, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x5d,
+  0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f,
+  0x20, 0x49, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x5b, 0x0a, 0x20,
+  0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x4d, 0x46, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67,
+  0x20, 0x75, 0x72, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x56,
+  0x65, 0x63, 0x33, 0x66, 0x20, 0x20, 0x62, 0x62, 0x6f, 0x78, 0x43,
+  0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30,
+  0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33,
+  0x66, 0x20, 0x20, 0x62, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65,
+  0x20, 0x20, 0x20, 0x2d, 0x31, 0x20, 0x2d, 0x31, 0x20, 0x2d, 0x31,
+  0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f,
+  0x54, 0x4f, 0x20, 0x4c, 0x4f, 0x44, 0x20, 0x5b, 0x0a, 0x20, 0x20,
+  0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x4d, 0x46, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x20, 0x6c,
+  0x65, 0x76, 0x65, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x20,
+  0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33,
+  0x66, 0x20, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x20, 0x20,
+  0x30, 0x20, 0x30, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4d,
+  0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x72, 0x61, 0x6e, 0x67,
+  0x65, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x20, 0x0a, 0x5d, 0x20,
+  0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20,
+  0x4d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x5b, 0x0a,
+  0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74,
+  0x20, 0x61, 0x6d, 0x62, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x74,
+  0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x20, 0x20, 0x30, 0x2e, 0x32,
+  0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x43, 0x6f, 0x6c, 0x6f,
+  0x72, 0x20, 0x64, 0x69, 0x66, 0x66, 0x75, 0x73, 0x65, 0x43, 0x6f,
+  0x6c, 0x6f, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x2e,
+  0x38, 0x20, 0x30, 0x2e, 0x38, 0x20, 0x30, 0x2e, 0x38, 0x0a, 0x20,
+  0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x53, 0x46, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20,
+  0x65, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x6c,
+  0x6f, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20,
+  0x30, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64,
+  0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f,
+  0x61, 0x74, 0x20, 0x73, 0x68, 0x69, 0x6e, 0x69, 0x6e, 0x65, 0x73,
+  0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30,
+  0x2e, 0x32, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65,
+  0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x43, 0x6f,
+  0x6c, 0x6f, 0x72, 0x20, 0x73, 0x70, 0x65, 0x63, 0x75, 0x6c, 0x61,
+  0x72, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x30, 0x20, 0x30, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70,
+  0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53,
+  0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x74, 0x72, 0x61, 0x6e,
+  0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x30, 0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a,
+  0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x4d, 0x6f, 0x76, 0x69,
+  0x65, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x20, 0x5b, 0x0a,
+  0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20,
+  0x20, 0x20, 0x6c, 0x6f, 0x6f, 0x70, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x46, 0x41, 0x4c, 0x53, 0x45, 0x0a, 0x20, 0x20, 0x65,
+  0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x20, 0x73,
+  0x70, 0x65, 0x65, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31,
+  0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x54, 0x69, 0x6d, 0x65,
+  0x20, 0x20, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d,
+  0x65, 0x20, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f,
+  0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46,
+  0x54, 0x69, 0x6d, 0x65, 0x20, 0x20, 0x20, 0x73, 0x74, 0x6f, 0x70,
+  0x54, 0x69, 0x6d, 0x65, 0x20, 0x20, 0x20, 0x30, 0x0a, 0x20, 0x20,
+  0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x4d, 0x46, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20,
+  0x75, 0x72, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b,
+  0x5d, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f,
+  0x6c, 0x20, 0x20, 0x20, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x53,
+  0x20, 0x20, 0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20,
+  0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20,
+  0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x54, 0x20, 0x20, 0x20, 0x20,
+  0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e,
+  0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46,
+  0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x20, 0x64, 0x75, 0x72, 0x61,
+  0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65,
+  0x64, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75,
+  0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f,
+  0x6c, 0x20, 0x20, 0x20, 0x69, 0x73, 0x41, 0x63, 0x74, 0x69, 0x76,
+  0x65, 0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52,
+  0x4f, 0x54, 0x4f, 0x20, 0x4e, 0x61, 0x76, 0x69, 0x67, 0x61, 0x74,
+  0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x20, 0x5b, 0x0a, 0x20,
+  0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20,
+  0x20, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x69, 0x6e, 0x64, 0x0a, 0x20,
+  0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x4d, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20,
+  0x20, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x53, 0x69, 0x7a, 0x65,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x20, 0x30, 0x2e,
+  0x32, 0x35, 0x2c, 0x20, 0x31, 0x2e, 0x36, 0x2c, 0x20, 0x30, 0x2e,
+  0x37, 0x35, 0x20, 0x5d, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f,
+  0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46,
+  0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x68, 0x65, 0x61, 0x64,
+  0x6c, 0x69, 0x67, 0x68, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20, 0x65, 0x78,
+  0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20,
+  0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x20, 0x73, 0x70,
+  0x65, 0x65, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x31, 0x2e, 0x30, 0x20, 0x0a, 0x20, 0x20,
+  0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x4d, 0x46, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20,
+  0x74, 0x79, 0x70, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x57, 0x41, 0x4c, 0x4b,
+  0x22, 0x20, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65,
+  0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x46, 0x6c,
+  0x6f, 0x61, 0x74, 0x20, 0x20, 0x76, 0x69, 0x73, 0x69, 0x62, 0x69,
+  0x6c, 0x69, 0x74, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x20, 0x20,
+  0x30, 0x2e, 0x30, 0x20, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e,
+  0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46,
+  0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x69, 0x73, 0x42, 0x6f,
+  0x75, 0x6e, 0x64, 0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a,
+  0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x4e, 0x6f, 0x72, 0x6d, 0x61,
+  0x6c, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73,
+  0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x4d, 0x46, 0x56,
+  0x65, 0x63, 0x33, 0x66, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72,
+  0x20, 0x5b, 0x5d, 0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a,
+  0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x4e, 0x6f, 0x72, 0x6d, 0x61,
+  0x6c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x6f, 0x6c, 0x61, 0x74,
+  0x6f, 0x72, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e,
+  0x74, 0x49, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46,
+  0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x66,
+  0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x65,
+  0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x4d, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x6b, 0x65,
+  0x79, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x0a,
+  0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x4d, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66,
+  0x20, 0x6b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x20,
+  0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f,
+  0x75, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4d, 0x46, 0x56, 0x65,
+  0x63, 0x33, 0x66, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x63,
+  0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x0a, 0x5d, 0x20, 0x7b, 0x20,
+  0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x4f, 0x72,
+  0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e,
+  0x74, 0x65, 0x72, 0x70, 0x6f, 0x6c, 0x61, 0x74, 0x6f, 0x72, 0x20,
+  0x5b, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x6e,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f,
+  0x61, 0x74, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x66,
+  0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x65,
+  0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x4d, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x20, 0x20,
+  0x20, 0x6b, 0x65, 0x79, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65,
+  0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x4d, 0x46, 0x52, 0x6f,
+  0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6b, 0x65, 0x79, 0x56,
+  0x61, 0x6c, 0x75, 0x65, 0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20,
+  0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x53, 0x46, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f,
+  0x6e, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x63, 0x68, 0x61,
+  0x6e, 0x67, 0x65, 0x64, 0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a,
+  0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x50, 0x69, 0x78, 0x65,
+  0x6c, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x20, 0x5b, 0x0a,
+  0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x49, 0x6d, 0x61, 0x67, 0x65,
+  0x20, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x66,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x72,
+  0x65, 0x70, 0x65, 0x61, 0x74, 0x53, 0x20, 0x20, 0x20, 0x20, 0x54,
+  0x52, 0x55, 0x45, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x42,
+  0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x72, 0x65, 0x70, 0x65, 0x61,
+  0x74, 0x54, 0x20, 0x20, 0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a,
+  0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54,
+  0x4f, 0x20, 0x50, 0x6c, 0x61, 0x6e, 0x65, 0x53, 0x65, 0x6e, 0x73,
+  0x6f, 0x72, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f,
+  0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46,
+  0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x61, 0x75, 0x74, 0x6f, 0x4f,
+  0x66, 0x66, 0x73, 0x65, 0x74, 0x20, 0x20, 0x54, 0x52, 0x55, 0x45,
+  0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c,
+  0x20, 0x20, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20, 0x65,
+  0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x32, 0x66, 0x20, 0x6d, 0x61,
+  0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x2d,
+  0x31, 0x20, 0x2d, 0x31, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f,
+  0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46,
+  0x56, 0x65, 0x63, 0x32, 0x66, 0x20, 0x6d, 0x69, 0x6e, 0x50, 0x6f,
+  0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x30, 0x20, 0x30, 0x0a,
+  0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66,
+  0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x65,
+  0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x69, 0x73,
+  0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x0a, 0x20, 0x20, 0x65, 0x76,
+  0x65, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x74, 0x72, 0x61,
+  0x63, 0x6b, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x63, 0x68, 0x61,
+  0x6e, 0x67, 0x65, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e,
+  0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46,
+  0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73,
+  0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x6e,
+  0x67, 0x65, 0x64, 0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a,
+  0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x50, 0x6f, 0x69, 0x6e, 0x74,
+  0x4c, 0x69, 0x67, 0x68, 0x74, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x65,
+  0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x61, 0x6d,
+  0x62, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x73,
+  0x69, 0x74, 0x79, 0x20, 0x20, 0x30, 0x20, 0x0a, 0x20, 0x20, 0x65,
+  0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x61, 0x74,
+  0x74, 0x65, 0x6e, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30, 0x0a,
+  0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x43, 0x6f, 0x6c, 0x6f, 0x72,
+  0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x20, 0x31,
+  0x20, 0x31, 0x20, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73,
+  0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x46,
+  0x6c, 0x6f, 0x61, 0x74, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x73,
+  0x69, 0x74, 0x79, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x31, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65,
+  0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x56, 0x65,
+  0x63, 0x33, 0x66, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f,
+  0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x30, 0x20, 0x30, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70,
+  0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53,
+  0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x6f, 0x6e, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x20, 0x0a, 0x20, 0x20,
+  0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x72,
+  0x61, 0x64, 0x69, 0x75, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x5d,
+  0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f,
+  0x20, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x53, 0x65, 0x74, 0x20, 0x5b,
+  0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x53, 0x46, 0x4e, 0x6f, 0x64,
+  0x65, 0x20, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x0a, 0x20, 0x20, 0x65,
+  0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x20, 0x53, 0x46, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x20, 0x63,
+  0x6f, 0x6f, 0x72, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4e,
+  0x55, 0x4c, 0x4c, 0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a,
+  0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x50, 0x6f, 0x73, 0x69, 0x74,
+  0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x6f, 0x6c,
+  0x61, 0x74, 0x6f, 0x72, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x65, 0x76,
+  0x65, 0x6e, 0x74, 0x49, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x73, 0x65, 0x74,
+  0x5f, 0x66, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20,
+  0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x4d, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20,
+  0x6b, 0x65, 0x79, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b,
+  0x5d, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64,
+  0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x4d, 0x46, 0x56, 0x65, 0x63,
+  0x33, 0x66, 0x20, 0x6b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65,
+  0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e,
+  0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46,
+  0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65,
+  0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x0a, 0x5d, 0x20,
+  0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20,
+  0x50, 0x72, 0x6f, 0x78, 0x69, 0x6d, 0x69, 0x74, 0x79, 0x53, 0x65,
+  0x6e, 0x73, 0x6f, 0x72, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x65, 0x78,
+  0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20,
+  0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x20, 0x20, 0x20,
+  0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x65, 0x78,
+  0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20,
+  0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x20, 0x20, 0x20,
+  0x73, 0x69, 0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x65, 0x78,
+  0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20,
+  0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65,
+  0x6e, 0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53,
+  0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69,
+  0x73, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x0a, 0x20, 0x20, 0x65,
+  0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x20, 0x20,
+  0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63,
+  0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x76,
+  0x65, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x53, 0x46, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+  0x6f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+  0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x0a, 0x20, 0x20,
+  0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x53, 0x46, 0x54, 0x69, 0x6d, 0x65, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65,
+  0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75, 0x74,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x54, 0x69, 0x6d, 0x65,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x78, 0x69, 0x74, 0x54, 0x69,
+  0x6d, 0x65, 0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50,
+  0x52, 0x4f, 0x54, 0x4f, 0x20, 0x53, 0x63, 0x61, 0x6c, 0x61, 0x72,
+  0x49, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x6f, 0x6c, 0x61, 0x74, 0x6f,
+  0x72, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74,
+  0x49, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x46,
+  0x6c, 0x6f, 0x61, 0x74, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x66, 0x72,
+  0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x65, 0x78,
+  0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20,
+  0x4d, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x6b, 0x65, 0x79,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x20,
+  0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x4d, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20,
+  0x6b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x20, 0x5b,
+  0x5d, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75,
+  0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f,
+  0x61, 0x74, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x63, 0x68,
+  0x61, 0x6e, 0x67, 0x65, 0x64, 0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d,
+  0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x53, 0x63, 0x72,
+  0x69, 0x70, 0x74, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70,
+  0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x4d,
+  0x46, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x72, 0x6c,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x5b, 0x20, 0x5d, 0x20, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46,
+  0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x64, 0x69, 0x72, 0x65,
+  0x63, 0x74, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x20, 0x46,
+  0x41, 0x4c, 0x53, 0x45, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46,
+  0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x6d, 0x75, 0x73, 0x74,
+  0x45, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x20, 0x20, 0x46,
+  0x41, 0x4c, 0x53, 0x45, 0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a,
+  0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x53, 0x68, 0x61, 0x70,
+  0x65, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x53, 0x46, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x61, 0x70, 0x70,
+  0x65, 0x61, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x4e, 0x55, 0x4c,
+  0x4c, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53,
+  0x46, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x67, 0x65, 0x6f, 0x6d, 0x65,
+  0x74, 0x72, 0x79, 0x20, 0x20, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x0a,
+  0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54,
+  0x4f, 0x20, 0x53, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x5b, 0x0a, 0x20,
+  0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20,
+  0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x0a, 0x20,
+  0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20,
+  0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x31, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70,
+  0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53,
+  0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x20, 0x6c, 0x6f, 0x63,
+  0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x30, 0x20, 0x30, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70,
+  0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53,
+  0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x20, 0x6d, 0x61, 0x78,
+  0x42, 0x61, 0x63, 0x6b, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x31, 0x30, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65,
+  0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x46, 0x6c,
+  0x6f, 0x61, 0x74, 0x20, 0x20, 0x6d, 0x61, 0x78, 0x46, 0x72, 0x6f,
+  0x6e, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x30, 0x0a,
+  0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74,
+  0x20, 0x20, 0x6d, 0x69, 0x6e, 0x42, 0x61, 0x63, 0x6b, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x0a, 0x20, 0x20, 0x65, 0x78,
+  0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20,
+  0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x20, 0x6d, 0x69,
+  0x6e, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x31, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65,
+  0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x46, 0x6c,
+  0x6f, 0x61, 0x74, 0x20, 0x20, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x69,
+  0x74, 0x79, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x0a, 0x20,
+  0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x53, 0x46, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x20,
+  0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x0a, 0x20, 0x20,
+  0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20,
+  0x73, 0x70, 0x61, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x20,
+  0x20, 0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x5d, 0x20, 0x7b,
+  0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x53,
+  0x70, 0x68, 0x65, 0x72, 0x65, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x66,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61,
+  0x74, 0x20, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x20, 0x20, 0x31,
+  0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f,
+  0x54, 0x4f, 0x20, 0x53, 0x70, 0x68, 0x65, 0x72, 0x65, 0x53, 0x65,
+  0x6e, 0x73, 0x6f, 0x72, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x65, 0x78,
+  0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20,
+  0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x61, 0x75, 0x74, 0x6f, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x20,
+  0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f,
+  0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46,
+  0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e,
+  0x61, 0x62, 0x6c, 0x65, 0x64, 0x20, 0x20, 0x20, 0x20, 0x54, 0x52,
+  0x55, 0x45, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65,
+  0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x52, 0x6f,
+  0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x66, 0x73,
+  0x65, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x31, 0x20,
+  0x30, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74,
+  0x4f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x42,
+  0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x73, 0x41,
+  0x63, 0x74, 0x69, 0x76, 0x65, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65,
+  0x6e, 0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53,
+  0x46, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72,
+  0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61,
+  0x6e, 0x67, 0x65, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e,
+  0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46,
+  0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x20, 0x20, 0x20, 0x74, 0x72,
+  0x61, 0x63, 0x6b, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x63, 0x68,
+  0x61, 0x6e, 0x67, 0x65, 0x64, 0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d,
+  0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x53, 0x70, 0x6f,
+  0x74, 0x4c, 0x69, 0x67, 0x68, 0x74, 0x20, 0x5b, 0x0a, 0x20, 0x20,
+  0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x61,
+  0x6d, 0x62, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x6e,
+  0x73, 0x69, 0x74, 0x79, 0x20, 0x20, 0x30, 0x20, 0x0a, 0x20, 0x20,
+  0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x61,
+  0x74, 0x74, 0x65, 0x6e, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x20, 0x30, 0x20, 0x30,
+  0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61,
+  0x74, 0x20, 0x62, 0x65, 0x61, 0x6d, 0x57, 0x69, 0x64, 0x74, 0x68,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x2e,
+  0x35, 0x37, 0x30, 0x37, 0x39, 0x36, 0x0a, 0x20, 0x20, 0x65, 0x78,
+  0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20,
+  0x53, 0x46, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x63, 0x6f, 0x6c,
+  0x6f, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x31, 0x20, 0x0a,
+  0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74,
+  0x20, 0x63, 0x75, 0x74, 0x4f, 0x66, 0x66, 0x41, 0x6e, 0x67, 0x6c,
+  0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x2e, 0x37,
+  0x38, 0x35, 0x33, 0x39, 0x38, 0x20, 0x0a, 0x20, 0x20, 0x65, 0x78,
+  0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20,
+  0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x64, 0x69, 0x72,
+  0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x2d, 0x31, 0x0a,
+  0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74,
+  0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x20, 0x20,
+  0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33,
+  0x66, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20,
+  0x30, 0x20, 0x30, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70,
+  0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53,
+  0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x6f, 0x6e, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20, 0x65,
+  0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x72, 0x61,
+  0x64, 0x69, 0x75, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x30, 0x30, 0x0a, 0x5d, 0x20,
+  0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20,
+  0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x20, 0x5b, 0x0a, 0x20, 0x20,
+  0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x20, 0x20, 0x20, 0x4d, 0x46, 0x4e, 0x6f, 0x64, 0x65,
+  0x20, 0x20, 0x63, 0x68, 0x6f, 0x69, 0x63, 0x65, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f,
+  0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20,
+  0x20, 0x53, 0x46, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x20, 0x77, 0x68,
+  0x69, 0x63, 0x68, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x20, 0x2d, 0x31,
+  0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f,
+  0x54, 0x4f, 0x20, 0x54, 0x65, 0x78, 0x74, 0x20, 0x5b, 0x0a, 0x20,
+  0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x20, 0x4d, 0x46, 0x53, 0x74, 0x72, 0x69, 0x6e,
+  0x67, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x20, 0x20,
+  0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46,
+  0x4e, 0x6f, 0x64, 0x65, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x6e, 0x74,
+  0x53, 0x74, 0x79, 0x6c, 0x65, 0x20, 0x4e, 0x55, 0x4c, 0x4c, 0x0a,
+  0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x4d, 0x46, 0x46, 0x6c, 0x6f, 0x61,
+  0x74, 0x20, 0x20, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x20, 0x20,
+  0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53,
+  0x46, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x20, 0x6d, 0x61, 0x78,
+  0x45, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x30, 0x2e, 0x30, 0x0a,
+  0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54,
+  0x4f, 0x20, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f,
+  0x6f, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x20, 0x5b, 0x0a,
+  0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x4d, 0x46, 0x56, 0x65, 0x63, 0x32, 0x66,
+  0x20, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x20, 0x5b, 0x5d, 0x0a, 0x5d,
+  0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f,
+  0x20, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x54, 0x72, 0x61,
+  0x6e, 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x5b, 0x0a, 0x20, 0x20,
+  0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x32, 0x66, 0x20, 0x63,
+  0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x30, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73,
+  0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x46,
+  0x6c, 0x6f, 0x61, 0x74, 0x20, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x69,
+  0x6f, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x65,
+  0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x32, 0x66, 0x20, 0x73, 0x63,
+  0x61, 0x6c, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31,
+  0x20, 0x31, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65,
+  0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x56, 0x65,
+  0x63, 0x32, 0x66, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61,
+  0x74, 0x69, 0x6f, 0x6e, 0x20, 0x30, 0x20, 0x30, 0x0a, 0x5d, 0x20,
+  0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20,
+  0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x20,
+  0x5b, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64,
+  0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x54, 0x69, 0x6d,
+  0x65, 0x20, 0x20, 0x20, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x49, 0x6e,
+  0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x20, 0x31, 0x0a, 0x20, 0x20,
+  0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20,
+  0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20, 0x65,
+  0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x6c,
+  0x6f, 0x6f, 0x70, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x46, 0x41, 0x4c, 0x53, 0x45, 0x0a, 0x20, 0x20, 0x65,
+  0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x53, 0x46, 0x54, 0x69, 0x6d, 0x65, 0x20, 0x20, 0x20, 0x73,
+  0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73,
+  0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x54,
+  0x69, 0x6d, 0x65, 0x20, 0x20, 0x20, 0x73, 0x74, 0x6f, 0x70, 0x54,
+  0x69, 0x6d, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x0a,
+  0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x54, 0x69, 0x6d, 0x65, 0x20,
+  0x20, 0x20, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x54, 0x69, 0x6d, 0x65,
+  0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75, 0x74,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61,
+  0x74, 0x20, 0x20, 0x66, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+  0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x0a, 0x20, 0x20,
+  0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20,
+  0x69, 0x73, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x0a, 0x20, 0x20,
+  0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x53, 0x46, 0x54, 0x69, 0x6d, 0x65, 0x20, 0x20, 0x20,
+  0x74, 0x69, 0x6d, 0x65, 0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a,
+  0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x54, 0x6f, 0x75, 0x63,
+  0x68, 0x53, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x20, 0x5b, 0x0a, 0x20,
+  0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20,
+  0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x20, 0x54, 0x52, 0x55,
+  0x45, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75,
+  0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x56, 0x65, 0x63,
+  0x33, 0x66, 0x20, 0x68, 0x69, 0x74, 0x4e, 0x6f, 0x72, 0x6d, 0x61,
+  0x6c, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x0a, 0x20,
+  0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20,
+  0x68, 0x69, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x63, 0x68,
+  0x61, 0x6e, 0x67, 0x65, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65,
+  0x6e, 0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53,
+  0x46, 0x56, 0x65, 0x63, 0x32, 0x66, 0x20, 0x68, 0x69, 0x74, 0x54,
+  0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x5f, 0x63, 0x68, 0x61,
+  0x6e, 0x67, 0x65, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e,
+  0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46,
+  0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x69, 0x73, 0x41, 0x63, 0x74,
+  0x69, 0x76, 0x65, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74,
+  0x4f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x42,
+  0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x69, 0x73, 0x4f, 0x76, 0x65, 0x72,
+  0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75, 0x74,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x54, 0x69, 0x6d, 0x65,
+  0x20, 0x20, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x54, 0x69, 0x6d, 0x65,
+  0x0a, 0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f,
+  0x54, 0x4f, 0x20, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x6f, 0x72,
+  0x6d, 0x20, 0x5b, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74,
+  0x49, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4d, 0x46, 0x4e,
+  0x6f, 0x64, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x64,
+  0x64, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x0a, 0x20,
+  0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x4d, 0x46, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x43,
+  0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x65,
+  0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x30,
+  0x20, 0x30, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65,
+  0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x4d, 0x46, 0x4e, 0x6f,
+  0x64, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x68, 0x69,
+  0x6c, 0x64, 0x72, 0x65, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70,
+  0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53,
+  0x46, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x20,
+  0x72, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31,
+  0x20, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73,
+  0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x56,
+  0x65, 0x63, 0x33, 0x66, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63,
+  0x61, 0x6c, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x31, 0x20, 0x31, 0x20, 0x31, 0x0a, 0x20,
+  0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x53, 0x46, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69,
+  0x6f, 0x6e, 0x20, 0x20, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x4f, 0x72,
+  0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x30,
+  0x20, 0x30, 0x20, 0x31, 0x20, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x65,
+  0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x69,
+  0x6f, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x30,
+  0x20, 0x30, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x56, 0x65,
+  0x63, 0x33, 0x66, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x62, 0x6f,
+  0x78, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x0a, 0x20, 0x20,
+  0x66, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x62, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x31,
+  0x20, 0x2d, 0x31, 0x20, 0x2d, 0x31, 0x0a, 0x5d, 0x20, 0x7b, 0x20,
+  0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x20, 0x56, 0x69,
+  0x65, 0x77, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x20, 0x5b, 0x0a, 0x20,
+  0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x73, 0x65, 0x74, 0x5f, 0x62, 0x69, 0x6e, 0x64,
+  0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x46, 0x6c, 0x6f, 0x61,
+  0x74, 0x20, 0x20, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4f,
+  0x66, 0x56, 0x69, 0x65, 0x77, 0x20, 0x20, 0x20, 0x20, 0x30, 0x2e,
+  0x37, 0x38, 0x35, 0x33, 0x39, 0x38, 0x0a, 0x20, 0x20, 0x65, 0x78,
+  0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20,
+  0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x6a, 0x75, 0x6d, 0x70, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20,
+  0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c,
+  0x64, 0x20, 0x53, 0x46, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f,
+  0x6e, 0x20, 0x6f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69,
+  0x6f, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20, 0x31,
+  0x20, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73,
+  0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x56,
+  0x65, 0x63, 0x33, 0x66, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x73,
+  0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x30, 0x20, 0x30, 0x20, 0x31, 0x30, 0x0a, 0x20, 0x20, 0x66,
+  0x69, 0x65, 0x6c, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x53, 0x46, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x20,
+  0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f,
+  0x6e, 0x20, 0x20, 0x20, 0x20, 0x22, 0x22, 0x0a, 0x20, 0x20, 0x65,
+  0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x53, 0x46, 0x54, 0x69, 0x6d, 0x65, 0x20, 0x20, 0x20, 0x20,
+  0x20, 0x62, 0x69, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x0a, 0x20,
+  0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75, 0x74, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c, 0x20, 0x20,
+  0x20, 0x20, 0x20, 0x69, 0x73, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x0a,
+  0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54,
+  0x4f, 0x20, 0x56, 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74,
+  0x79, 0x53, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x20, 0x5b, 0x0a, 0x20,
+  0x20, 0x65, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65,
+  0x6c, 0x64, 0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20,
+  0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x20, 0x20, 0x30, 0x20,
+  0x30, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x73,
+  0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x42,
+  0x6f, 0x6f, 0x6c, 0x20, 0x20, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65,
+  0x64, 0x20, 0x20, 0x54, 0x52, 0x55, 0x45, 0x0a, 0x20, 0x20, 0x65,
+  0x78, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x46, 0x69, 0x65, 0x6c, 0x64,
+  0x20, 0x53, 0x46, 0x56, 0x65, 0x63, 0x33, 0x66, 0x20, 0x73, 0x69,
+  0x7a, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x30, 0x20,
+  0x30, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75,
+  0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x54, 0x69, 0x6d,
+  0x65, 0x20, 0x20, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x54, 0x69, 0x6d,
+  0x65, 0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75,
+  0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x54, 0x69, 0x6d,
+  0x65, 0x20, 0x20, 0x65, 0x78, 0x69, 0x74, 0x54, 0x69, 0x6d, 0x65,
+  0x0a, 0x20, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x75, 0x74,
+  0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x46, 0x42, 0x6f, 0x6f, 0x6c,
+  0x20, 0x20, 0x69, 0x73, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x0a,
+  0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a, 0x50, 0x52, 0x4f, 0x54,
+  0x4f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f,
+  0x20, 0x5b, 0x0a, 0x20, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x20,
+  0x4d, 0x46, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x6e,
+  0x66, 0x6f, 0x20, 0x20, 0x5b, 0x5d, 0x0a, 0x20, 0x20, 0x66, 0x69,
+  0x65, 0x6c, 0x64, 0x20, 0x53, 0x46, 0x53, 0x74, 0x72, 0x69, 0x6e,
+  0x67, 0x20, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x20, 0x22, 0x22, 0x0a,
+  0x5d, 0x20, 0x7b, 0x20, 0x7d, 0x0a, 0x0a
+};
+
+const int standard_nodes_data_len = 14604;
+

+ 271 - 0
pandatool/src/vrml/standardNodes.wrl.pz.c

@@ -0,0 +1,271 @@
+
+/*
+ * This table was generated by the command:
+ *
+ * bin2c -n standard_nodes_data -o standardNodes.wrl.pz.c standardNodes.wrl.pz
+ */
+
+const unsigned char standard_nodes_data[] = {
+  0x78, 0x9c, 0xd5, 0x5b, 0x5b, 0x6f, 0xdb, 0x38, 0x16, 0x7e, 0xcf,
+  0xaf, 0x20, 0xd2, 0x97, 0x76, 0xd1, 0x09, 0x62, 0x17, 0xbd, 0xcd,
+  0x5b, 0x92, 0x26, 0x45, 0xb0, 0x69, 0x12, 0x44, 0x6e, 0xfa, 0x50,
+  0x14, 0x03, 0x5a, 0xa2, 0x6d, 0x4e, 0x64, 0x51, 0xa0, 0x28, 0xd7,
+  0xee, 0x62, 0xff, 0xfb, 0xf2, 0x2e, 0x4a, 0xbc, 0x58, 0xdd, 0x66,
+  0x3a, 0x1d, 0xa5, 0x45, 0xd3, 0xf8, 0xd3, 0xe1, 0xe1, 0x39, 0x87,
+  0xe7, 0xca, 0x3c, 0xb9, 0xbf, 0xfb, 0x70, 0x05, 0xee, 0xa7, 0x47,
+  0xc7, 0xa0, 0x65, 0x8b, 0x37, 0x07, 0x4f, 0x0e, 0x9e, 0x80, 0x7f,
+  0x7d, 0xf7, 0x23, 0x5e, 0x02, 0x92, 0x92, 0x20, 0x74, 0x0b, 0x69,
+  0x83, 0xa8, 0xfc, 0xd9, 0x19, 0xa9, 0x77, 0x14, 0x2f, 0x57, 0x0c,
+  0x3c, 0x3d, 0x7b, 0x06, 0x26, 0x6f, 0xdf, 0xbe, 0x02, 0x19, 0x2e,
+  0x71, 0x4e, 0x2a, 0xf0, 0x9e, 0xc2, 0x7a, 0x85, 0xf3, 0xe6, 0x39,
+  0xb8, 0xac, 0xf2, 0x23, 0x81, 0x96, 0x6f, 0x9c, 0xb4, 0x6c, 0x45,
+  0xe8, 0xd3, 0xe6, 0x19, 0xe0, 0xcf, 0xef, 0xe0, 0x3d, 0xdc, 0xe0,
+  0x0a, 0x9c, 0xa2, 0xb2, 0x94, 0x9f, 0x0e, 0x9e, 0x77, 0xb0, 0xc2,
+  0xa8, 0x04, 0x9f, 0x08, 0x29, 0x1a, 0xf0, 0x74, 0x81, 0x69, 0xc3,
+  0x40, 0x4d, 0x28, 0x7b, 0xf6, 0x7f, 0xee, 0x82, 0xbf, 0xf6, 0x0e,
+  0x2d, 0x70, 0x85, 0x19, 0x26, 0x55, 0x03, 0x16, 0x84, 0x02, 0x58,
+  0x96, 0x80, 0x2c, 0x00, 0x5b, 0x21, 0x50, 0x91, 0x02, 0x35, 0x60,
+  0xde, 0xe2, 0x92, 0xfd, 0xc6, 0x99, 0x62, 0x44, 0xfe, 0xb4, 0xa9,
+  0x91, 0x64, 0x7f, 0x06, 0x1f, 0x50, 0xc5, 0xe1, 0x6b, 0xc2, 0x99,
+  0x28, 0x30, 0x45, 0x39, 0x2b, 0x77, 0x60, 0x41, 0xc9, 0x5a, 0xc2,
+  0xac, 0x74, 0x38, 0x79, 0x58, 0xca, 0xb7, 0x7e, 0x3f, 0x38, 0xb8,
+  0xbd, 0xbb, 0x99, 0xdd, 0x80, 0x93, 0x2a, 0xe7, 0x7b, 0x06, 0x9f,
+  0x0f, 0x00, 0x40, 0x1b, 0x54, 0xb1, 0xcb, 0x4a, 0x6d, 0xef, 0xc3,
+  0xc5, 0x35, 0x5f, 0x92, 0x7f, 0x03, 0x8b, 0xe2, 0x6c, 0x85, 0xcb,
+  0x82, 0xa2, 0x2a, 0x8a, 0xa1, 0x68, 0x4d, 0x36, 0xc8, 0x85, 0x6d,
+  0x6b, 0xd2, 0xa0, 0xe2, 0x82, 0x4b, 0xa8, 0xe8, 0x60, 0xb9, 0x06,
+  0x18, 0x11, 0x7e, 0xfe, 0x32, 0x84, 0x66, 0x17, 0x19, 0xa3, 0xb8,
+  0x5a, 0x02, 0xbe, 0xdb, 0x9c, 0xe2, 0x5a, 0xc8, 0x42, 0x42, 0x0f,
+  0x0f, 0x81, 0x4f, 0x56, 0x63, 0x6b, 0x48, 0xe1, 0x1a, 0x31, 0x44,
+  0xa3, 0x64, 0x2d, 0xb4, 0xa5, 0x65, 0x4f, 0x89, 0x12, 0xba, 0x90,
+  0x18, 0xfd, 0x64, 0x17, 0xf7, 0x28, 0x7f, 0xb1, 0x00, 0x60, 0x3e,
+  0x27, 0xdb, 0x33, 0xbe, 0x59, 0x43, 0xf6, 0x58, 0x7c, 0x25, 0xd1,
+  0x19, 0xfe, 0x86, 0xcc, 0x07, 0xbf, 0x4d, 0xd4, 0x9f, 0x83, 0x2f,
+  0xe0, 0x3f, 0xe0, 0xbf, 0x56, 0xd8, 0x75, 0x8d, 0x38, 0xb3, 0x55,
+  0x8e, 0x94, 0xc0, 0xfb, 0x5b, 0x97, 0x52, 0x5a, 0x43, 0xbe, 0x22,
+  0x86, 0x0e, 0x9b, 0xd7, 0x1f, 0xaf, 0xae, 0x22, 0x60, 0x86, 0xb6,
+  0xac, 0xa5, 0x08, 0x7c, 0x0f, 0x78, 0xc6, 0xd7, 0x6f, 0xb8, 0x75,
+  0xad, 0x35, 0xb8, 0xcf, 0x60, 0x5b, 0x60, 0x72, 0x56, 0xe2, 0xda,
+  0xe7, 0x0f, 0x44, 0x94, 0x73, 0x78, 0x18, 0x42, 0x9e, 0x12, 0x22,
+  0xb6, 0x50, 0x12, 0x52, 0x5b, 0xde, 0x2e, 0x4e, 0xae, 0xb2, 0xf3,
+  0x10, 0xf8, 0xa2, 0x24, 0x90, 0x01, 0x50, 0x63, 0x96, 0xaf, 0x0c,
+  0x78, 0x72, 0x74, 0x1c, 0x82, 0xce, 0xf0, 0x5a, 0x6c, 0xb7, 0x61,
+  0x90, 0x32, 0xfd, 0x3d, 0x48, 0x03, 0x49, 0x6d, 0x70, 0x21, 0x60,
+  0xd8, 0x32, 0x94, 0x05, 0x09, 0x53, 0xbf, 0x69, 0x99, 0x55, 0xb5,
+  0xa6, 0x53, 0xb4, 0x14, 0x8a, 0xad, 0xff, 0x91, 0xaf, 0x60, 0xb5,
+  0x44, 0x45, 0x08, 0xaa, 0xb7, 0x8f, 0x9b, 0x93, 0x9c, 0xe1, 0x0d,
+  0xea, 0x0b, 0xf9, 0x14, 0xe6, 0x0f, 0x4b, 0x4a, 0xda, 0xaa, 0xf0,
+  0x8f, 0x9d, 0x7d, 0xb5, 0x41, 0xec, 0x8f, 0x39, 0xae, 0x0a, 0xdf,
+  0x94, 0xb5, 0xb4, 0x14, 0x85, 0x93, 0x6a, 0x59, 0xa2, 0xb0, 0xc9,
+  0x9f, 0x91, 0x92, 0x1f, 0x6c, 0x8d, 0xd3, 0xff, 0x49, 0x1c, 0x8d,
+  0x39, 0xe7, 0xea, 0xa3, 0x11, 0x42, 0x0a, 0x47, 0x18, 0x23, 0x6b,
+  0x8d, 0x4c, 0xe0, 0xb8, 0xf7, 0xa9, 0x98, 0x21, 0x98, 0xc0, 0x95,
+  0x68, 0xc1, 0xc6, 0xac, 0x2b, 0x5d, 0xf9, 0x08, 0x7a, 0x5c, 0xe1,
+  0x96, 0x5c, 0x10, 0xa7, 0xe5, 0xd7, 0x3c, 0xec, 0xb4, 0xf0, 0x22,
+  0x38, 0x2d, 0x32, 0x8e, 0xd3, 0xdf, 0x09, 0x9c, 0x72, 0x03, 0x00,
+  0x78, 0x06, 0xe2, 0xe8, 0xfc, 0x54, 0x08, 0x7c, 0xa0, 0x72, 0x5c,
+  0x96, 0x73, 0x02, 0x69, 0x40, 0xe3, 0x8f, 0xe8, 0x68, 0xad, 0x37,
+  0x82, 0x5b, 0xdc, 0xdc, 0x2c, 0xee, 0x08, 0x83, 0xea, 0x8c, 0x1e,
+  0x83, 0x89, 0x6f, 0xfc, 0x69, 0xb7, 0xfc, 0xf3, 0x9c, 0xe2, 0x29,
+  0xd9, 0x4a, 0xa9, 0x58, 0x1a, 0xe6, 0xfd, 0x46, 0xbe, 0x3a, 0x95,
+  0x5f, 0xfd, 0x57, 0xb8, 0x42, 0x4a, 0xdc, 0x88, 0xad, 0x7d, 0x06,
+  0xbf, 0x4a, 0xe0, 0xd2, 0xea, 0xcf, 0x05, 0x6b, 0x45, 0xe7, 0x92,
+  0x67, 0x77, 0x1f, 0xcf, 0xff, 0x6a, 0x71, 0x7a, 0x2f, 0x68, 0xb6,
+  0x6b, 0x4a, 0xb6, 0x3b, 0xd0, 0x3d, 0x26, 0x38, 0xf4, 0xed, 0x56,
+  0xbb, 0x35, 0xcd, 0xb8, 0xf8, 0x9f, 0x27, 0x6c, 0x93, 0x20, 0x84,
+  0x0e, 0x48, 0xde, 0x1d, 0x8e, 0x2f, 0x81, 0x17, 0x2f, 0xc5, 0xee,
+  0x6a, 0x52, 0x42, 0x16, 0xca, 0x32, 0x8c, 0xef, 0x17, 0xde, 0x6e,
+  0x41, 0x61, 0x2e, 0xcc, 0x35, 0x76, 0x62, 0x1f, 0x90, 0xd9, 0x4b,
+  0xfc, 0xb4, 0x72, 0xcc, 0x3d, 0x2c, 0x5b, 0x14, 0x72, 0xe1, 0x99,
+  0xc6, 0x6c, 0x04, 0xc0, 0x3a, 0xef, 0x01, 0xc7, 0x15, 0xea, 0xdb,
+  0x62, 0x17, 0x9d, 0xb4, 0xe3, 0xbb, 0x83, 0x05, 0x6e, 0x1b, 0x30,
+  0x89, 0x80, 0x56, 0x48, 0x66, 0x9c, 0xea, 0x99, 0x0e, 0x40, 0xda,
+  0x44, 0xb8, 0x61, 0xa7, 0x0c, 0xa4, 0xc3, 0xa9, 0x15, 0x5d, 0xdc,
+  0x80, 0x5b, 0x42, 0x0b, 0x9e, 0xd1, 0xb1, 0x40, 0x36, 0xf1, 0x41,
+  0x1b, 0x4d, 0x4d, 0x70, 0xc5, 0x42, 0xaa, 0x31, 0xaf, 0xfe, 0x2c,
+  0xfd, 0x28, 0x76, 0x52, 0xfa, 0x31, 0x98, 0x94, 0x7e, 0x76, 0x25,
+  0x0f, 0x89, 0x88, 0x0e, 0xfd, 0xc5, 0x50, 0x60, 0x43, 0x99, 0xfa,
+  0xfa, 0x99, 0x86, 0x3f, 0xa6, 0x4a, 0xbb, 0x7d, 0xf5, 0xfa, 0x8a,
+  0xf3, 0xe9, 0x1b, 0x04, 0xd3, 0xf9, 0x4e, 0x40, 0x5b, 0x9a, 0xf7,
+  0x0c, 0x55, 0x4d, 0xe8, 0x3c, 0x75, 0x34, 0x00, 0x6c, 0x19, 0xb9,
+  0x59, 0x2c, 0xb8, 0xd0, 0xcd, 0x4a, 0x03, 0xa4, 0x61, 0x97, 0xe7,
+  0xfa, 0xcd, 0x83, 0x8e, 0x62, 0xc7, 0x47, 0xd3, 0x57, 0xd3, 0x04,
+  0x51, 0x54, 0xc1, 0x79, 0x89, 0x0a, 0x87, 0xfd, 0x18, 0xd1, 0x35,
+  0xdc, 0x9a, 0xc8, 0x28, 0x9d, 0x4b, 0x14, 0x87, 0x2b, 0x83, 0xf3,
+  0x82, 0x8b, 0x03, 0x23, 0x6a, 0x27, 0xc0, 0xc0, 0x82, 0x51, 0xd3,
+  0xc9, 0x95, 0x3c, 0x88, 0x8d, 0x63, 0x54, 0x7f, 0x13, 0xcb, 0xbc,
+  0xac, 0xa7, 0xe4, 0x7a, 0xe0, 0xc6, 0xfa, 0x70, 0x2b, 0x8c, 0x3f,
+  0x6c, 0x49, 0xef, 0x64, 0x91, 0xc4, 0x69, 0xc1, 0xf2, 0x4a, 0x5a,
+  0x44, 0x40, 0x1f, 0x6a, 0x07, 0x70, 0x3d, 0xc7, 0xf2, 0x44, 0x30,
+  0xae, 0x38, 0xcc, 0x76, 0xc2, 0x4b, 0xfb, 0xd8, 0xa1, 0x2f, 0x34,
+  0xcf, 0x44, 0x7c, 0xc5, 0xe2, 0x74, 0x61, 0x98, 0xb0, 0x70, 0x11,
+  0x00, 0xe2, 0x32, 0xc7, 0x1d, 0x0f, 0x96, 0x7c, 0x4c, 0xe3, 0x0e,
+  0x51, 0xc7, 0x81, 0x0c, 0xe2, 0xe8, 0x79, 0x89, 0x36, 0x52, 0xa2,
+  0xef, 0x29, 0x0e, 0xa6, 0x26, 0x26, 0x57, 0xe2, 0xc7, 0x5f, 0x9d,
+  0x9c, 0x48, 0x6d, 0x01, 0x02, 0x5b, 0x4f, 0x94, 0x22, 0x80, 0xd7,
+  0xb3, 0x74, 0x0d, 0xcb, 0xd1, 0x70, 0x5e, 0xbb, 0x48, 0x97, 0xe5,
+  0xc1, 0x07, 0x81, 0xcf, 0x04, 0xe1, 0xfc, 0x6b, 0x60, 0xf3, 0x71,
+  0xb8, 0xe0, 0xfd, 0x16, 0xd1, 0x7b, 0x44, 0xf9, 0x42, 0x71, 0xb8,
+  0x96, 0x46, 0x4e, 0x11, 0x6c, 0x50, 0x97, 0x3c, 0x02, 0x3f, 0x66,
+  0x5b, 0xc9, 0xf5, 0xe2, 0x81, 0x7c, 0x42, 0xd9, 0x95, 0xe6, 0x43,
+  0x09, 0xc5, 0x65, 0x24, 0xc9, 0x76, 0x43, 0x78, 0xc0, 0x1e, 0xb1,
+  0x4b, 0x6e, 0xba, 0x2f, 0xa6, 0x00, 0x6c, 0xdf, 0xf1, 0xd0, 0x5e,
+  0x35, 0x8e, 0xb9, 0x05, 0x52, 0x0d, 0xcd, 0xf6, 0x36, 0xab, 0x61,
+  0x2e, 0xb2, 0x69, 0xfb, 0x1c, 0x1f, 0x05, 0xd0, 0x9a, 0xf2, 0xb7,
+  0xef, 0xa0, 0xfc, 0x2d, 0x48, 0x79, 0x60, 0x96, 0x5b, 0x46, 0x5b,
+  0x95, 0xde, 0x39, 0x26, 0x29, 0xe3, 0xc3, 0x54, 0x9e, 0x6e, 0x61,
+  0x8f, 0x39, 0x25, 0x4d, 0x93, 0x21, 0x1b, 0x92, 0x2c, 0xca, 0xba,
+  0x0b, 0x81, 0x22, 0x54, 0x1c, 0x5e, 0xe8, 0x81, 0x7a, 0xa4, 0x9a,
+  0x1c, 0x96, 0x68, 0xf8, 0xf1, 0x8b, 0xee, 0xe3, 0x1a, 0x57, 0xc8,
+  0xd9, 0x90, 0xe3, 0xb4, 0xe6, 0x68, 0x89, 0xab, 0x33, 0xd8, 0xd5,
+  0xb8, 0x03, 0x0d, 0x38, 0x50, 0xcf, 0x26, 0x13, 0x50, 0x52, 0x6d,
+  0x94, 0x1d, 0xc6, 0xa0, 0xd6, 0xb9, 0x7a, 0xb6, 0xe8, 0x4a, 0xde,
+  0xd9, 0xa6, 0x2b, 0x2d, 0x89, 0xfb, 0x2c, 0x1c, 0xd3, 0x73, 0x20,
+  0xf2, 0xc7, 0xe7, 0x2a, 0x8d, 0x94, 0xff, 0xc8, 0x1f, 0x4d, 0xc0,
+  0x97, 0x30, 0x63, 0x88, 0x17, 0x92, 0xce, 0x66, 0x3d, 0xc6, 0x1c,
+  0xe1, 0x3b, 0x82, 0xd7, 0x8c, 0xd9, 0x2a, 0x24, 0xc0, 0x9e, 0xd4,
+  0x80, 0x2b, 0x9c, 0x49, 0x2f, 0x04, 0x3b, 0x2c, 0x78, 0x46, 0xef,
+  0xb1, 0xd0, 0xe9, 0x4e, 0xe8, 0xcd, 0x85, 0xea, 0xea, 0xed, 0xb9,
+  0xe2, 0x04, 0x0c, 0x72, 0xa2, 0x0b, 0xb2, 0x0c, 0x45, 0x01, 0x5d,
+  0xfc, 0x79, 0xfe, 0x2d, 0xe2, 0xd9, 0x4d, 0xf5, 0x4b, 0x96, 0xb3,
+  0x5d, 0xed, 0xac, 0x7e, 0x78, 0x75, 0x79, 0x7d, 0x7e, 0x72, 0xe7,
+  0x35, 0x4b, 0xac, 0x2e, 0x37, 0xbc, 0xa0, 0x99, 0xe3, 0x92, 0x7b,
+  0xf7, 0x3b, 0x11, 0xaf, 0x9c, 0x60, 0x99, 0xec, 0x0d, 0x8c, 0xaf,
+  0x41, 0x2f, 0x78, 0x3d, 0x9e, 0xb1, 0x5d, 0xe9, 0x66, 0xb8, 0x1d,
+  0xbf, 0x70, 0x8d, 0x4b, 0x15, 0x57, 0x0e, 0xb3, 0xf3, 0xbb, 0xcb,
+  0x8b, 0x43, 0x07, 0xa3, 0xa9, 0xae, 0xb8, 0x4e, 0xbf, 0x71, 0x22,
+  0xc2, 0x6f, 0xf7, 0xa4, 0x6e, 0x6b, 0xef, 0x3f, 0xdb, 0x86, 0xe1,
+  0x85, 0x26, 0x73, 0x7a, 0xfe, 0xfe, 0xf2, 0xfa, 0xd0, 0x5f, 0xaa,
+  0xe4, 0xdb, 0x6b, 0xe1, 0x52, 0xca, 0xe6, 0x30, 0xb0, 0x8c, 0x68,
+  0x08, 0xcc, 0xc8, 0x9d, 0xf4, 0x9b, 0xbd, 0x65, 0xac, 0xa8, 0x9a,
+  0xae, 0x08, 0x9a, 0x38, 0x6e, 0xa9, 0xfb, 0xdc, 0x71, 0x31, 0x7d,
+  0x80, 0x66, 0xa1, 0x91, 0x62, 0xd0, 0x8a, 0xb9, 0xbd, 0x3a, 0xe9,
+  0xf3, 0xa9, 0xf9, 0x10, 0x9d, 0x23, 0x72, 0xaa, 0x32, 0x4a, 0x3f,
+  0x9d, 0x7b, 0x4f, 0x49, 0x5b, 0xc7, 0xab, 0xf9, 0x11, 0xc5, 0xe7,
+  0xb8, 0xda, 0xd3, 0x29, 0x3d, 0xe3, 0x75, 0xb9, 0x53, 0x47, 0x26,
+  0x4b, 0x48, 0xa7, 0x82, 0x0c, 0xd7, 0xe2, 0x97, 0x6b, 0xae, 0x98,
+  0x99, 0xee, 0x2a, 0x06, 0x8a, 0x8a, 0x41, 0xb3, 0x2c, 0x11, 0xcb,
+  0x28, 0xaa, 0x11, 0x64, 0x59, 0x3a, 0x82, 0x29, 0xd0, 0x2c, 0x20,
+  0xde, 0x4b, 0x9e, 0x2a, 0x6f, 0xf9, 0xba, 0x30, 0x47, 0x19, 0x4f,
+  0x1e, 0xfd, 0x32, 0x9f, 0x33, 0xa3, 0xa2, 0x8f, 0x8c, 0x05, 0xaa,
+  0xd2, 0xe4, 0xaf, 0xec, 0x81, 0xf1, 0x14, 0x62, 0x3f, 0x4c, 0x85,
+  0xe1, 0xfd, 0x38, 0x93, 0x94, 0x58, 0x64, 0xaf, 0xb5, 0x68, 0x72,
+  0x97, 0x71, 0x89, 0x91, 0x03, 0xef, 0xa5, 0x39, 0xfb, 0xe0, 0xe3,
+  0xf2, 0x28, 0x0b, 0x1f, 0x97, 0x47, 0x59, 0x05, 0x8d, 0xcb, 0xa3,
+  0xac, 0x50, 0x3a, 0x35, 0x98, 0x4f, 0x7c, 0x03, 0xe9, 0x68, 0x8f,
+  0x4a, 0xba, 0x1c, 0xf8, 0x20, 0x26, 0xee, 0x63, 0xc5, 0x28, 0x26,
+  0xc9, 0x8a, 0x72, 0x18, 0x23, 0x12, 0x3a, 0x4b, 0xd8, 0x31, 0x8e,
+  0xfd, 0x7b, 0x1c, 0x97, 0xd0, 0x59, 0xf8, 0xb8, 0x84, 0xce, 0xb2,
+  0xd2, 0xb3, 0x3f, 0xc3, 0x4a, 0xe8, 0x14, 0x5d, 0xf1, 0x38, 0x28,
+  0x4f, 0xd1, 0xe3, 0x1f, 0xa2, 0xbf, 0xd4, 0xe4, 0x7f, 0x9e, 0x95,
+  0x25, 0xcd, 0x66, 0x20, 0xd2, 0x12, 0x57, 0x63, 0x7c, 0x63, 0x90,
+  0xaf, 0x50, 0xe7, 0x6f, 0x74, 0xd3, 0x2f, 0xec, 0xb2, 0xaf, 0x6e,
+  0xde, 0x85, 0xb8, 0x51, 0xa2, 0xe5, 0xf5, 0x1d, 0xd2, 0x8d, 0x7a,
+  0x10, 0x5b, 0x22, 0x37, 0x0d, 0xc8, 0x20, 0x23, 0xa6, 0x92, 0xa1,
+  0x2a, 0x29, 0x51, 0x94, 0x7a, 0x0c, 0x7c, 0x30, 0x13, 0xab, 0xef,
+  0x29, 0xa1, 0x8f, 0x02, 0xad, 0x0a, 0x95, 0x69, 0x15, 0x78, 0xb1,
+  0x68, 0x1b, 0xd4, 0xf5, 0xdc, 0x39, 0xf8, 0x8d, 0xf9, 0x1b, 0x7b,
+  0x09, 0xad, 0x71, 0xd3, 0xe0, 0x8d, 0xf3, 0x96, 0xd9, 0x4c, 0x90,
+  0xa1, 0x66, 0x85, 0x2b, 0xae, 0xc5, 0xa6, 0xb1, 0x06, 0x90, 0x60,
+  0x48, 0x8c, 0x4b, 0xdb, 0x12, 0xd2, 0x91, 0xb4, 0x99, 0x98, 0xaf,
+  0xd5, 0x90, 0x87, 0xec, 0x5c, 0xd7, 0xe9, 0xc7, 0x03, 0x79, 0x91,
+  0x0d, 0x8e, 0xc7, 0xd8, 0xd0, 0xe8, 0x2c, 0x38, 0x38, 0x73, 0xb2,
+  0x1d, 0x84, 0xb4, 0xba, 0x02, 0xf9, 0xa8, 0x3f, 0x30, 0x0b, 0x70,
+  0xee, 0x0f, 0xcb, 0x02, 0xd3, 0x02, 0xcf, 0xbe, 0x47, 0x44, 0xff,
+  0xc8, 0x79, 0xf3, 0x12, 0x80, 0x0e, 0x37, 0x48, 0x68, 0xf5, 0x1e,
+  0xf7, 0xcd, 0xdc, 0xf6, 0x4c, 0xdc, 0xae, 0xe1, 0x06, 0x2f, 0x25,
+  0x81, 0xcb, 0x6a, 0x41, 0x7e, 0x64, 0xea, 0x06, 0x37, 0x90, 0x4b,
+  0xd2, 0xe9, 0xc2, 0x7f, 0x16, 0xa6, 0xf3, 0x92, 0x57, 0x4d, 0x47,
+  0xaf, 0x78, 0x5d, 0x71, 0xf4, 0xfa, 0x25, 0x88, 0xcf, 0x06, 0x56,
+  0x08, 0x16, 0xa5, 0xdb, 0x0f, 0x48, 0x36, 0xe2, 0x1c, 0xbd, 0x6a,
+  0xed, 0x1e, 0xf9, 0x9d, 0xa7, 0x6e, 0xec, 0xd5, 0xab, 0x36, 0xf8,
+  0x73, 0xf8, 0xe9, 0xe4, 0xea, 0xdf, 0xfe, 0xd4, 0x3c, 0x50, 0x6f,
+  0x5c, 0xe1, 0x35, 0x66, 0xb2, 0x0e, 0x07, 0x09, 0xb9, 0x06, 0x2a,
+  0x8a, 0x6b, 0x95, 0x7c, 0x44, 0x9b, 0xcf, 0x1b, 0x5e, 0x6f, 0x8a,
+  0x56, 0xe7, 0x97, 0xd0, 0x6b, 0xff, 0xa8, 0xc6, 0xf3, 0x4d, 0x57,
+  0xcd, 0x8e, 0xe3, 0x5b, 0xdb, 0xd2, 0x3e, 0xd6, 0xf9, 0x93, 0xe6,
+  0xde, 0xd6, 0xd3, 0xe9, 0xc9, 0x86, 0x85, 0x25, 0xf6, 0x70, 0x8b,
+  0xb7, 0xa8, 0x4c, 0xf8, 0x1d, 0x99, 0xfb, 0x73, 0x4d, 0xaf, 0x75,
+  0x6d, 0x16, 0x1d, 0x47, 0xfd, 0xe0, 0x19, 0xef, 0x33, 0xc5, 0xab,
+  0x41, 0xb4, 0xaf, 0x25, 0xee, 0xf4, 0xc3, 0x23, 0x47, 0x46, 0xe1,
+  0x9c, 0x16, 0x77, 0x04, 0xa7, 0x1a, 0x0e, 0x6b, 0xb8, 0xbd, 0x25,
+  0x8d, 0xbc, 0x68, 0x63, 0x27, 0x68, 0x61, 0x20, 0xae, 0x2c, 0x30,
+  0xe8, 0xf2, 0x95, 0xe1, 0x38, 0x1d, 0xee, 0x2e, 0x36, 0x84, 0x8e,
+  0x51, 0xbc, 0xc7, 0xad, 0x08, 0x05, 0xba, 0xd6, 0x71, 0x64, 0xd5,
+  0x94, 0x7d, 0x9f, 0xd8, 0x17, 0xac, 0xa0, 0xf2, 0x28, 0xad, 0x6d,
+  0xb5, 0x20, 0x64, 0x1c, 0xd4, 0x3a, 0xfd, 0x1c, 0xd9, 0x42, 0x09,
+  0x88, 0x24, 0xd9, 0x09, 0x8f, 0xba, 0xa3, 0x40, 0x6b, 0x3b, 0xc6,
+  0x49, 0x49, 0x72, 0xd8, 0x6b, 0x9a, 0xc7, 0xe2, 0x71, 0xba, 0x11,
+  0x1e, 0x61, 0xc4, 0x4c, 0x80, 0x1c, 0xc6, 0x8f, 0x8f, 0x03, 0xa2,
+  0xb5, 0xf9, 0xf4, 0xbe, 0x0c, 0x78, 0x6c, 0xea, 0xeb, 0x5f, 0xc6,
+  0x31, 0xa6, 0xf7, 0xeb, 0x78, 0xca, 0x6c, 0xbf, 0xa7, 0xbc, 0xa5,
+  0x64, 0x2b, 0xe2, 0xc9, 0x2e, 0x7e, 0xa8, 0x6d, 0x83, 0xce, 0x66,
+  0x9e, 0x71, 0x1d, 0x76, 0xcd, 0x3c, 0x67, 0xf0, 0x9d, 0xd4, 0x37,
+  0x08, 0xfb, 0x81, 0xef, 0x9e, 0x3a, 0xd9, 0x95, 0x6b, 0xad, 0x86,
+  0xf8, 0x91, 0x0c, 0x35, 0x3d, 0xe3, 0x68, 0x7b, 0x1d, 0x49, 0xee,
+  0x5e, 0xce, 0xdb, 0x13, 0x98, 0x2d, 0x66, 0xfe, 0x48, 0x3e, 0xcb,
+  0x21, 0x4f, 0x48, 0x7f, 0x96, 0x5d, 0x58, 0x4c, 0xc2, 0x2e, 0x14,
+  0x26, 0x61, 0x17, 0x99, 0xbc, 0x31, 0x36, 0xae, 0x6e, 0x12, 0x7c,
+  0x80, 0x50, 0xc1, 0xa2, 0xd5, 0xa6, 0xe6, 0x66, 0x7c, 0xf1, 0x5a,
+  0xac, 0x6f, 0xb2, 0xe3, 0x30, 0x76, 0xdd, 0x36, 0xec, 0x5c, 0xf0,
+  0x25, 0xc6, 0xe4, 0x1a, 0xdb, 0x67, 0x6c, 0x05, 0xeb, 0x7e, 0x4b,
+  0x54, 0x1e, 0x4d, 0xd8, 0x5d, 0xd5, 0xeb, 0x55, 0xa3, 0xfa, 0xe3,
+  0x25, 0x22, 0x6b, 0xc4, 0xe8, 0x2e, 0x78, 0x70, 0xb3, 0xee, 0x6e,
+  0x57, 0xd0, 0x9a, 0xfb, 0x73, 0x3f, 0xd9, 0x18, 0x8f, 0xa6, 0x69,
+  0x7d, 0xc7, 0x18, 0x75, 0x8a, 0x03, 0xaf, 0x98, 0xac, 0x50, 0x44,
+  0xfc, 0x13, 0x77, 0xd0, 0xac, 0x7f, 0x4b, 0x01, 0x2f, 0xc4, 0x35,
+  0xae, 0xfd, 0x40, 0x5c, 0xb9, 0x14, 0x53, 0x38, 0x97, 0x60, 0x14,
+  0x57, 0x53, 0xcc, 0xcf, 0x12, 0xb3, 0x05, 0x54, 0x6c, 0x2e, 0xd8,
+  0x90, 0x96, 0xe6, 0xd6, 0x2f, 0x24, 0x67, 0x82, 0xbc, 0x26, 0x63,
+  0xbc, 0x4a, 0xd5, 0x6e, 0xc4, 0xcf, 0x44, 0xb2, 0x7a, 0x85, 0x68,
+  0xdf, 0x10, 0xfa, 0x11, 0x61, 0x12, 0xc2, 0x3f, 0xc6, 0x34, 0x7f,
+  0xfc, 0x88, 0xbe, 0x73, 0x34, 0xce, 0x4c, 0xbd, 0x0b, 0xc4, 0xbf,
+  0xc4, 0x64, 0x3d, 0xab, 0xc9, 0xdf, 0x92, 0x77, 0x28, 0xd2, 0x73,
+  0x04, 0xd7, 0x9f, 0x70, 0xc1, 0xec, 0x3d, 0x52, 0x5e, 0x35, 0xbd,
+  0x7c, 0x7d, 0xfc, 0xfa, 0xed, 0xab, 0xc7, 0xca, 0x54, 0xf2, 0x96,
+  0x71, 0x6d, 0xf6, 0x9a, 0x85, 0x47, 0xaf, 0xdf, 0xbc, 0x7c, 0xf1,
+  0xf6, 0x4d, 0x74, 0x0f, 0x8f, 0x31, 0xe7, 0x8f, 0x12, 0x8f, 0xa4,
+  0x43, 0xa1, 0x17, 0x52, 0x09, 0xd1, 0x0f, 0xe4, 0x43, 0xd9, 0x57,
+  0x79, 0x71, 0x37, 0x70, 0x63, 0xd8, 0x99, 0x62, 0x10, 0x9c, 0xc7,
+  0xae, 0x5a, 0x82, 0x6e, 0x94, 0xfc, 0x75, 0x85, 0xf3, 0x95, 0x1c,
+  0x89, 0x78, 0x7d, 0x2e, 0x51, 0xb9, 0x04, 0xd6, 0xf8, 0xd0, 0xcd,
+  0x74, 0xa8, 0x9e, 0xf9, 0x04, 0xdb, 0x81, 0xda, 0x61, 0x2c, 0xec,
+  0x10, 0x2c, 0xd2, 0x63, 0xd4, 0x0e, 0xa8, 0x44, 0xd5, 0x52, 0x19,
+  0x51, 0xa2, 0x6f, 0x2c, 0xfc, 0xe3, 0xf9, 0x96, 0xeb, 0x8a, 0xc9,
+  0x21, 0xb6, 0xc7, 0x2e, 0x2f, 0xb4, 0xf6, 0xde, 0xd1, 0x9a, 0x9a,
+  0x3b, 0x5a, 0xc3, 0x2a, 0x79, 0x36, 0xbc, 0xae, 0x1d, 0x8e, 0x27,
+  0xd3, 0xc5, 0x30, 0x8d, 0x8a, 0x6a, 0x92, 0x74, 0xe3, 0xd8, 0x70,
+  0xa6, 0xc5, 0x69, 0xb9, 0x83, 0xd8, 0xd8, 0xcd, 0x95, 0x69, 0xaf,
+  0xfc, 0x90, 0x4b, 0xf6, 0x39, 0xe7, 0xf9, 0x4a, 0xdc, 0x2f, 0x9a,
+  0xeb, 0x86, 0xbb, 0xbc, 0x54, 0x97, 0xcf, 0x78, 0x70, 0x0e, 0x2d,
+  0xa4, 0xdd, 0x97, 0x9b, 0xcb, 0xa5, 0xab, 0xbf, 0xfe, 0x65, 0xf3,
+  0x58, 0xd3, 0x2c, 0x74, 0x81, 0x7c, 0x5c, 0x4b, 0x0c, 0x80, 0x90,
+  0x97, 0x75, 0xb7, 0x13, 0xce, 0xe5, 0xb4, 0xad, 0x98, 0x1c, 0x6c,
+  0x7c, 0x0b, 0x2b, 0xb6, 0x16, 0xf3, 0xf2, 0xc1, 0x19, 0x69, 0xf3,
+  0xd5, 0xbe, 0x50, 0x64, 0x24, 0x19, 0xce, 0x88, 0x95, 0x33, 0x59,
+  0x61, 0xa6, 0xba, 0x33, 0xfb, 0x02, 0x01, 0x07, 0xee, 0xaf, 0x53,
+  0xa7, 0x12, 0x37, 0xd3, 0x63, 0x8a, 0x7d, 0x1b, 0x8f, 0xef, 0xdb,
+  0x7c, 0x7e, 0xb3, 0x41, 0x34, 0x26, 0x15, 0x26, 0x44, 0xe0, 0x67,
+  0xca, 0x83, 0xe3, 0x13, 0xbc, 0x04, 0x0c, 0xc6, 0xdd, 0x15, 0x06,
+  0xa3, 0xaf, 0x5f, 0x83, 0x7e, 0x69, 0x63, 0x0e, 0x66, 0xe2, 0x0a,
+  0x36, 0xf0, 0xef, 0x18, 0x07, 0x2f, 0x19, 0x77, 0x57, 0xba, 0xdd,
+  0xd3, 0x6c, 0x17, 0x98, 0xc4, 0x4e, 0xb6, 0xe6, 0x2a, 0x74, 0xcd,
+  0x22, 0x74, 0xf6, 0xba, 0x65, 0xe4, 0x1b, 0x4e, 0xf7, 0x6b, 0xd4,
+  0x32, 0xae, 0x77, 0xe8, 0x6d, 0x3e, 0x3c, 0xe2, 0x00, 0xfe, 0x45,
+  0xe8, 0x71, 0x6f, 0xb8, 0x97, 0xa1, 0x23, 0xd3, 0x91, 0x7b, 0x8c,
+  0xbe, 0x6a, 0xff, 0x1a, 0x6d, 0xfa, 0xc6, 0xdb, 0xbe, 0x4e, 0x37,
+  0x4f, 0x32, 0x72, 0xb3, 0x10, 0xf4, 0x24, 0x7f, 0x3a, 0xe6, 0x27,
+  0xb2, 0xb9, 0x3f, 0xdb, 0x75, 0xe0, 0xaa, 0x4c, 0x34, 0xa3, 0xeb,
+  0xdf, 0x97, 0x19, 0x21, 0x66, 0x53, 0x97, 0xba, 0xfa, 0x0f, 0x88,
+  0x2c, 0x33, 0x71, 0x71, 0xf0, 0x2b, 0x55, 0xea, 0xf7, 0x76, 0x22,
+  0x65, 0xa7, 0x10, 0x46, 0xd8, 0x9b, 0x39, 0x59, 0x65, 0xa0, 0x23,
+  0x7c, 0x6f, 0x9b, 0xca, 0xfb, 0xca, 0x7f, 0x6f, 0xea, 0x94, 0xee,
+  0xe8, 0x45, 0xdb, 0x79, 0xf6, 0xf7, 0x04, 0x40, 0xb4, 0xf7, 0xa6,
+  0x76, 0xb5, 0xb7, 0xda, 0xb6, 0xa5, 0xf6, 0x3e, 0xff, 0xd4, 0xdb,
+  0xf1, 0x27, 0x42, 0xcb, 0xc2, 0x4e, 0x15, 0x16, 0xfd, 0x9a, 0x16,
+  0x8b, 0x9f, 0xbb, 0x19, 0x84, 0x55, 0x07, 0xc3, 0x8c, 0x9f, 0x44,
+  0xae, 0x03, 0x4d, 0xec, 0x7f, 0x09, 0x6f, 0xb6, 0x7d
+};
+
+const int standard_nodes_data_len = 2847;
+

+ 52 - 0
pandatool/src/vrml/standard_nodes.cxx

@@ -0,0 +1,52 @@
+// Filename: standard_nodes.cxx
+// Created by:  drose (01Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "standard_nodes.h"
+
+// The binary data included here was generated from standardNodes.wrl
+// (in this directory) file via the utility program bin2c (defined in
+// pandatool).  It contains the set of VRML definitions that must be
+// loaded before any standard VRML file can be properly interpreted.
+
+#ifndef CPPPARSER
+
+#if defined(HAVE_ZLIB)
+
+// If we have zlib available, we can store this file compressed, which
+// is much smaller.
+
+// Regenerate this file with:
+
+// pcompress standardNodes.wrl standardNodes.wrl.pz
+// bin2c -n standard_nodes_data -o standardNodes.wrl.pz.c standardNodes.wrl.pz
+
+#include "standardNodes.wrl.pz.c"
+
+#else  // HAVE_ZLIB
+
+// If we don't have zlib, just include the whole uncompressed file.
+
+// Regenerate this file with:
+
+// bin2c -n standard_nodes_data -o standardNodes.wrl.c standardNodes.wrl
+
+#include "standardNodes.wrl.c"
+
+#endif  // HAVE_ZLIB
+
+#endif  // CPPPARSER

+ 32 - 0
pandatool/src/vrml/standard_nodes.h

@@ -0,0 +1,32 @@
+// Filename: standard_nodes.h
+// Created by:  drose (01Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef STANDARD_NODES_H
+#define STANDARD_NODES_H
+
+#include "pandatoolbase.h"
+
+#ifndef CPPPARSER
+
+extern const unsigned char standard_nodes_data[];
+extern const int standard_nodes_data_len;
+
+#endif  // CPPPARSER
+
+#endif
+

+ 436 - 0
pandatool/src/vrml/vrml2egg.cxx

@@ -0,0 +1,436 @@
+// Filename: vrml2egg.C
+// Created by:  drose (24Jun99)
+// 
+////////////////////////////////////////////////////////////////////
+// Copyright (C) 1992,93,94,95,96,97  Walt Disney Imagineering, Inc.
+// 
+// These  coded  instructions,  statements,  data   structures   and
+// computer  programs contain unpublished proprietary information of
+// Walt Disney Imagineering and are protected by  Federal  copyright
+// law.  They may  not be  disclosed to third  parties  or copied or
+// duplicated in any form, in whole or in part,  without  the  prior
+// written consent of Walt Disney Imagineering Inc.
+////////////////////////////////////////////////////////////////////
+
+#include "vrml2egg.h"
+#include "parse_vrml.h"
+#include "vrmlNode.h"
+#include "appearance.h"
+#include "indexedFaceSet.h"
+#include "y.tab.h"
+
+#include <assert.h>
+#include <math.h>
+
+static const double pi = 4.0 * atan(1.0);
+
+////////////////////////////////////////////////////////////////////
+//     Function: MainProgram::Help
+//       Access: Public, Virtual
+//  Description: Displays the "what is this program" message, along
+//               with the usage message.  Should be overridden in base
+//               classes to describe the current program.
+////////////////////////////////////////////////////////////////////
+void MainProgram::
+Help() {
+  cerr <<
+    "\n"
+    "vrml2egg converts VRML 2.0 files (with the .wrl extension) to egg format.\n"
+    "A reasonable subset of the VRML standard is supported, including polygons,\n"
+    "colors, normals, textures, and hierarchy.\n";
+
+  Usage();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MainProgram::Usage
+//       Access: Public, Virtual
+//  Description: Displays the usage message.
+////////////////////////////////////////////////////////////////////
+void MainProgram::
+Usage() {
+  cerr << "\nUsage:\n"
+       << _commandName << " [opts] input.wrl\n\n"
+
+       << "Options:\n";
+
+  ShowOpts();
+  cerr << "\n";
+}
+
+    
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: MainProgram::ShowOpts
+//       Access: Public, Virtual
+//  Description: Displays the valid options.  Should be extended in
+//               base classes to show additional options relevant to
+//               the current program.
+////////////////////////////////////////////////////////////////////
+void MainProgram::
+ShowOpts() {
+  EggBase::ShowOpts();
+}
+
+  
+
+////////////////////////////////////////////////////////////////////
+//     Function: MainProgram::HandleGetopts
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+boolean MainProgram::
+HandleGetopts(char flag, char *optarg, int &optind,
+	      int argc, char **argv) {
+  bool okflag = true;
+
+  switch (flag) {
+  default:
+    okflag = EggBase::HandleGetopts(flag, optarg, optind, argc, argv);
+  }
+
+  return okflag;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: MainProgram::HandleArgs
+//       Access: Public
+//  Description: Called by EggBase::CommandLine() to do the right
+//               thing with the arguments after the switches.
+////////////////////////////////////////////////////////////////////
+boolean MainProgram::
+HandleArgs(int &argc, char **&argv) {
+  if (argc != 2) {
+    cerr << "VRML file name required.\n";
+    return false;
+  }
+
+  _filename = argv[1];
+
+  return EggBase::HandleArgs(argc, argv);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MainProgram::vrml_group
+//       Access: Public
+//  Description: Creates an Egg group corresponding to the VRML group.
+////////////////////////////////////////////////////////////////////
+void MainProgram::
+vrml_group(const VrmlNode *node, EggGroup *group,
+	   const pfMatrix &net_transform) {
+  const MFArray *children = node->get_value("children")._mf;
+  MFArray::const_iterator ci;
+  for (ci = children->begin(); ci != children->end(); ++ci) {
+    vrml_node((*ci)._sfnode, group, net_transform);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MainProgram::vrml_transform
+//       Access: Public
+//  Description: Creates an Egg group with a transform corresponding
+//               to the VRML group.
+////////////////////////////////////////////////////////////////////
+void MainProgram::
+vrml_transform(const VrmlNode *node, EggGroup *group,
+	       const pfMatrix &net_transform) {
+  const double *scale = node->get_value("scale")._sfvec;
+  const double *rotation = node->get_value("rotation")._sfvec;
+  const double *translation = node->get_value("translation")._sfvec;
+
+  const double *center = node->get_value("center")._sfvec;
+  const double *o = node->get_value("scaleOrientation")._sfvec;
+
+  pfMatrix local_transform;
+  local_transform.makeIdent();
+
+  boolean any_transform = false;
+
+  if (scale[0] != 1.0 || scale[1] != 1.0 || scale[2] != 1.0) {
+    any_transform = true;
+    if (center[0] != 0.0 || center[1] != 0.0 || center[2] != 0.0) {
+      local_transform.postTrans(local_transform, 
+				-center[0], -center[1], -center[2]);
+      if (o[3] != 0.0) {
+	local_transform.postRot(local_transform,
+				-o[3] * 180.0 / pi, o[0], o[1], o[2]);
+	local_transform.postScale(local_transform,
+				  scale[0], scale[1], scale[2]);
+	local_transform.postRot(local_transform,
+				o[3] * 180.0 / pi, o[0], o[1], o[2]);
+      } else {
+	local_transform.postScale(local_transform, 
+				  scale[0], scale[1], scale[2]);
+      }
+      local_transform.postTrans(local_transform, 
+				center[0], center[1], center[2]);
+    } else {
+      if (o[3] != 0.0) {
+	local_transform.postRot(local_transform,
+				-o[3] * 180.0 / pi, o[0], o[1], o[2]);
+	local_transform.postScale(local_transform,
+				  scale[0], scale[1], scale[2]);
+	local_transform.postRot(local_transform,
+				o[3] * 180.0 / pi, o[0], o[1], o[2]);
+      } else {
+	local_transform.postScale(local_transform, 
+				  scale[0], scale[1], scale[2]);
+      }
+    }      
+  }
+
+  if (rotation[3] != 0.0) {
+    any_transform = true;
+    if (center[0] != 0.0 || center[1] != 0.0 || center[2] != 0.0) {
+      local_transform.postTrans(local_transform, 
+				-center[0], -center[1], -center[2]);
+      local_transform.postRot(local_transform,
+			      rotation[3] * 180.0 / pi,
+			      rotation[0], rotation[1], rotation[2]);
+      local_transform.postTrans(local_transform, 
+				center[0], center[1], center[2]);
+
+    } else {
+      local_transform.postRot(local_transform,
+			      rotation[3] * 180.0 / pi,
+			      rotation[0], rotation[1], rotation[2]);
+    }
+  }
+
+  if (translation[0] != 0.0 ||
+      translation[1] != 0.0 ||
+      translation[2] != 0.0) {
+    any_transform = true;
+    local_transform.postTrans(local_transform, 
+			      translation[0],
+			      translation[1],
+			      translation[2]);
+  }
+
+  if (any_transform) {
+    group->transform = local_transform;
+    group->flags |= EF_TRANSFORM;
+  }
+
+  pfMatrix next_transform = local_transform * net_transform;
+
+  const MFArray *children = node->get_value("children")._mf;
+  MFArray::const_iterator ci;
+  for (ci = children->begin(); ci != children->end(); ++ci) {
+    vrml_node((*ci)._sfnode, group, next_transform);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MainProgram::vrml_shape
+//       Access: Public
+//  Description: Creates an Egg group corresponding a VRML shape.
+//               This will probably contain a vertex pool and a number
+//               of polygons.
+////////////////////////////////////////////////////////////////////
+void MainProgram::
+vrml_shape(const VrmlNode *node, EggGroup *group,
+	   const pfMatrix &net_transform) {
+  const VrmlNode *geometry = node->get_value("geometry")._sfnode._p;
+
+  double transparency = 0.0;
+
+  if (geometry != NULL) {
+    Appearance appearance
+      (node->get_value("appearance")._sfnode._p, _data);
+
+    if (strcmp(geometry->_type->getName(), "IndexedFaceSet") == 0) {
+      IndexedFaceSet ifs(geometry, appearance, _data);
+      ifs.convert_to_egg(group, net_transform);
+    } else {
+      cerr << "Ignoring " << geometry->_type->getName() << "\n";
+    }
+  }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: MainProgram::vrml_grouping_node
+//       Access: Public
+//  Description: Begins initial processing of a grouping-type node;
+//               that is, any node (like Group, Transform, or Shape)
+//               that maps to a <Group> or <Instance> in egg.  This
+//               create the group and does any instance-munging
+//               necessary, then calls the indicated method with the
+//               new parameters.
+////////////////////////////////////////////////////////////////////
+void MainProgram::
+vrml_grouping_node(const SFNodeRef &vrml, EggGroup *egg,
+		   const pfMatrix &net_transform,
+		   void (MainProgram::*process_func)
+		   (const VrmlNode *node, EggGroup *group,
+		    const pfMatrix &net_transform)) {
+  const VrmlNode *node = vrml._p;
+  assert(node != NULL);
+  const char *name = vrml._name;
+
+  if (vrml._type == SFNodeRef::T_use) {
+    // If this is an instancing reference, just add the reference and
+    // return; no need for further processing on the node.
+    Instances::const_iterator fi = _instances.find(node);
+    assert(fi != _instances.end());
+    EggInstance *inst = _data.CreateInstance(egg);
+    inst->AddGroupRef((*fi).second);
+    return;
+  }
+
+  EggGroup *group;
+  pfMatrix next_transform;
+
+  if (node->_use_count > 0) {
+    // If this node is referenced one or more times later in the file,
+    // we must make it an instance node.
+    group = _data.CreateInstance(egg, name);
+    next_transform.makeIdent();
+
+    // And define the instance for future references.
+    _instances[node] = group;
+
+  } else {
+    group = _data.CreateGroup(egg, name);
+    next_transform = net_transform;
+  }
+
+  (this->*process_func)(node, group, next_transform);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MainProgram::vrml_node
+//       Access: Public
+//  Description: Processes a single VRML node, converting it to egg
+//               and adding it to the egg file, if appropriate, or
+//               doing whatever else should be done.
+////////////////////////////////////////////////////////////////////
+void MainProgram::
+vrml_node(const SFNodeRef &vrml, EggGroup *egg, 
+	  const pfMatrix &net_transform) {
+  const VrmlNode *node = vrml._p;
+  if (node != NULL) {
+    // Now add it to the egg file at this point.
+    if (strcmp(node->_type->getName(), "Group") == 0) {
+      vrml_grouping_node(vrml, egg, net_transform, &vrml_group);
+    } else if (strcmp(node->_type->getName(), "Transform") == 0) {
+      vrml_grouping_node(vrml, egg, net_transform, &vrml_transform);
+    } else if (strcmp(node->_type->getName(), "Shape") == 0) {
+      vrml_grouping_node(vrml, egg, net_transform, &vrml_shape);
+    }
+  }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: MainProgram::get_all_defs
+//       Access: Public
+//  Description: Makes a first pass through the VRML hierarchy,
+//               identifying all nodes marked with a DEF code, and
+//               also counting the times each one is referenced by
+//               USE.  Later, we'll need this information: if a node
+//               is referenced at least once, we need to define it as
+//               an instance node.
+////////////////////////////////////////////////////////////////////
+void MainProgram::
+get_all_defs(SFNodeRef &vrml, MainProgram::Nodes &nodes) {
+  Nodes::iterator ni;
+
+  switch (vrml._type) {
+  case SFNodeRef::T_def:
+    // If this is a node definition, add it to the map.
+    assert(vrml._name != NULL);
+    assert(vrml._p != NULL);
+    /*
+      This happens too often to bother yelling about it.
+    ni = nodes.find(vrml._name);
+    if (ni != nodes.end()) {
+      cerr << "Warning: node name " << vrml._name 
+	   << " appears multiple times.\n";
+    }
+    */
+    nodes[vrml._name] = vrml._p;
+    break;
+
+  case SFNodeRef::T_use:
+    // If it's a reference, resolve it.
+    assert(vrml._name != NULL);
+    ni = nodes.find(vrml._name);
+    if (ni == nodes.end()) {
+      cerr << "Unknown node reference: " << vrml._name << "\n";
+    } else {
+      // Increment the use count of the node.
+      (*ni).second->_use_count++;
+
+      // Store the pointer itself in the reference, so we don't have
+      // to do this again later.
+      vrml._p = (*ni).second;
+    }
+    return;
+  }
+
+  VrmlNode *node = vrml._p;
+  if (node != NULL) {
+    VrmlNode::Fields::iterator fi;
+    for (fi = node->_fields.begin(); fi != node->_fields.end(); ++fi) {
+      if ((*fi)._type->type == SFNODE) {
+	get_all_defs((*fi)._value._sfnode, nodes);
+      } else if ((*fi)._type->type == MFNODE) {
+	MFArray *children = (*fi)._value._mf;
+	MFArray::iterator ci;
+	for (ci = children->begin(); ci != children->end(); ++ci) {
+	  get_all_defs((*ci)._sfnode, nodes);
+	}
+      }
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MainProgram::DoIt
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+void MainProgram::
+DoIt() {
+  VrmlScene *scene = parse_vrml(_filename.c_str());
+  if (scene != NULL) {
+    // First, resolve all the DEF/USE references, and count the number
+    // of times each node is USEd.
+    Nodes nodes;
+    VrmlScene::iterator si;
+    for (si = scene->begin(); si != scene->end(); ++si) {
+      get_all_defs((*si)._node, nodes);
+    }
+
+    // Now go through the hierarchy again, and this time actually
+    // build the egg structure.
+    pfMatrix ident;
+    ident.makeIdent();
+
+    VrmlScene::const_iterator csi;
+    for (csi = scene->begin(); csi != scene->end(); ++csi) {
+      vrml_node((*csi)._node, &_data.root_group, ident);
+    }
+
+    _data.UniquifyNames();
+    Output() << _data << "\n";
+  }
+}
+
+
+int 
+main(int argc, char *argv[]) {
+  pfInitArenas();
+
+  MainProgram prog;
+
+  if (prog.CommandLine(argc, argv)) {
+    prog.DoIt();
+    return 0;
+  }
+  return 1;
+}

+ 78 - 0
pandatool/src/vrml/vrml2egg.h

@@ -0,0 +1,78 @@
+// Filename: vrml2egg.h
+// Created by:  drose (24Jun99)
+// 
+////////////////////////////////////////////////////////////////////
+// Copyright (C) 1992,93,94,95,96,97  Walt Disney Imagineering, Inc.
+// 
+// These  coded  instructions,  statements,  data   structures   and
+// computer  programs contain unpublished proprietary information of
+// Walt Disney Imagineering and are protected by  Federal  copyright
+// law.  They may  not be  disclosed to third  parties  or copied or
+// duplicated in any form, in whole or in part,  without  the  prior
+// written consent of Walt Disney Imagineering Inc.
+////////////////////////////////////////////////////////////////////
+
+#ifndef VRML2EGG_H
+#define VRML2EGG_H
+
+#include <eggBase.h>
+
+#include <mstring.h>
+#include <map.h>
+
+class VrmlNode;
+struct SFNodeRef;
+class EggGroup;
+class pfMatrix;
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : MainProgram
+// Description : The vrml2egg program class.  This handles the user
+//               input and gets things going.
+////////////////////////////////////////////////////////////////////
+class MainProgram : public EggBase {
+public:
+  MainProgram() : EggBase("") {
+  }
+
+  virtual void Help();
+  virtual void Usage();
+  virtual void ShowOpts();
+  
+  virtual boolean
+  HandleGetopts(char flag, char *optarg, int &optind,
+		int argc, char **argv);
+
+  virtual boolean
+  HandleArgs(int &argc, char **&argv);
+
+  void vrml_group(const VrmlNode *node, EggGroup *group,
+		  const pfMatrix &net_transform);
+  void vrml_transform(const VrmlNode *node, EggGroup *group,
+		      const pfMatrix &net_transform);
+  void vrml_shape(const VrmlNode *node, EggGroup *group,
+		  const pfMatrix &net_transform);
+
+  void vrml_grouping_node(const SFNodeRef &vrml, EggGroup *egg,
+			  const pfMatrix &net_transform,
+			  void (MainProgram::*process_func)
+			  (const VrmlNode *node, EggGroup *group,
+			   const pfMatrix &net_transform));
+
+  void vrml_node(const SFNodeRef &vrml,
+		 EggGroup *egg, const pfMatrix &net_transform);
+
+  typedef map<String, VrmlNode *> Nodes;
+
+  void get_all_defs(SFNodeRef &vrml, Nodes &nodes);
+
+  void DoIt();
+
+  typedef map<const VrmlNode *, EggGroup *> Instances;
+  Instances _instances;
+
+  string _filename;
+};
+
+
+#endif

+ 574 - 0
pandatool/src/vrml/vrmlLexer.lxx

@@ -0,0 +1,574 @@
+/*
+// Filename: vrmlLexer.lxx
+// Created by:  drose (01Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+*/
+
+/**************************************************
+ * VRML 2.0 Parser
+ * Copyright (C) 1996 Silicon Graphics, Inc.
+ *
+ * Author(s)    : Gavin Bell
+ *                Daniel Woods (first port)
+ **************************************************
+ */
+%{
+#include "pandatoolbase.h"
+
+#include "vrmlNode.h"
+#include "vrmlParser.h"
+#include "indent.h"
+#include "notify.h"
+
+static int yyinput(void);        // declared by flex.
+extern "C" int vrmlyywrap();
+
+////////////////////////////////////////////////////////////////////
+// Static variables
+////////////////////////////////////////////////////////////////////
+
+// We'll increment line_number and col_number as we parse the file, so
+// that we can report the position of an error.
+static int line_number = 0;
+static int col_number = 0;
+
+// current_line holds as much of the current line as will fit.  Its
+// only purpose is for printing it out to report an error to the user.
+static const int max_error_width = 1024;
+static char current_line[max_error_width + 1];
+
+static int error_count = 0;
+static int warning_count = 0;
+
+// This is the pointer to the current input stream.
+static istream *inp = NULL;
+
+// This is the name of the vrml file we're parsing.  We keep it so we
+// can print it out for error messages.
+static string vrml_filename;
+
+int vrmlyy_flex_debug = 0;
+
+extern void vrmlyyerror(const string &);
+
+    /* The YACC parser sets this to a token to direct the lexer */
+    /* in cases where just syntax isn't enough: */
+int expectToken = 0;
+
+    /* True when parsing a multiple-valued field: */
+static int parsing_mf = 0;
+
+    /* These are used when parsing SFImage fields: */
+static int sfImageIntsParsed = 0;
+static int sfImageIntsExpected = 0;
+
+// This is used while scanning a quoted string.
+static string quoted_string;
+
+// And this keeps track of the currently-parsing array.
+static MFArray *mfarray;
+
+void
+vrml_init_lexer(istream &in, const string &filename) {
+  vrmlyy_flex_debug = 0;
+  inp = &in;
+  vrml_filename = filename;
+  line_number = 0;
+  col_number = 0;
+  error_count = 0;
+  warning_count = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+// Internal support functions.
+////////////////////////////////////////////////////////////////////
+
+int
+vrmlyywrap(void) {
+  return 1;
+}
+
+void
+vrmlyyerror(const string &msg) {
+  cerr << "\nError";
+  if (!vrml_filename.empty()) {
+    cerr << " in " << vrml_filename;
+  }
+  cerr 
+    << " at line " << line_number << ", column " << col_number << ":\n"
+    << current_line << "\n";
+  indent(cerr, col_number-1) 
+    << "^\n" << msg << "\n\n";
+  
+  error_count++;
+}
+
+void
+vrmlyywarning(const string &msg) {
+  cerr << "\nWarning";
+  if (!vrml_filename.empty()) {
+    cerr << " in " << vrml_filename;
+  }
+  cerr 
+    << " at line " << line_number << ", column " << col_number << ":\n"
+    << current_line << "\n";
+  indent(cerr, col_number-1) 
+    << "^\n" << msg << "\n\n";
+
+  warning_count++;
+}
+
+// Now define a function to take input from an istream instead of a
+// stdio FILE pointer.  This is flex-specific.
+static void
+input_chars(char *buffer, int &result, int max_size) {
+  nassertv(inp != NULL);
+  if (*inp) {
+    inp->read(buffer, max_size);
+    result = inp->gcount();
+    if (result >= 0 && result < max_size) {
+      // Truncate at the end of the read.
+      buffer[result] = '\0';
+    }
+
+    if (line_number == 0) {
+      // This is a special case.  If we are reading the very first bit
+      // from the stream, copy it into the current_line array.  This
+      // is because the \n.* rule below, which fills current_line
+      // normally, doesn't catch the first line.
+      strncpy(current_line, vrmlyytext, max_error_width);
+      current_line[max_error_width] = '\0';
+      line_number++;
+      col_number = 0;
+
+      // Truncate it at the newline.
+      char *end = strchr(current_line, '\n');
+      if (end != NULL) {
+        *end = '\0';
+      }
+    }
+
+  } else {
+    // End of file or I/O error.
+    result = 0;
+  }
+}
+#undef YY_INPUT
+#define YY_INPUT(buffer, result, max_size) input_chars(buffer, result, max_size)
+
+int extract_int() {
+  return strtol(yytext, NULL, 0);
+}
+
+double extract_float() {
+  return atof(yytext);
+}
+
+void extract_vec(double vec[], int num_elements) {
+  char *p = yytext;
+  for (int i = 0; i < num_elements; i++) {
+    vec[i] = strtod(p, &p);
+  }
+}
+
+%}
+
+    /* Normal state:  parsing nodes.  The initial start state is used */
+    /* only to recognize the VRML header. */
+%x NODE
+
+    /* Start tokens for all of the field types, */
+    /* except for MFNode and SFNode, which are almost completely handled */
+    /* by the parser: */
+%x SFB SFC SFF SFIMG SFI SFR SFS SFT SFV2 SFV3
+%x MFC MFF MFI MFR MFS MFV2 MFV3
+%x IN_SFS IN_MFS IN_SFIMG
+
+    /* Big hairy expression for floating point numbers: */
+float (-?(([0-9]+)|([0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?))
+
+    /* Ints are decimal or hex (0x##): */
+int (-?([0-9]+)|(0[xX][0-9a-fA-F]*))
+
+    /* Whitespace.  Using this pattern can screw up currentLineNumber, */
+    /* so it is only used wherever it is really convenient and it is */
+    /* extremely unlikely that the user will put in a carriage return */
+    /* (example: between the floats in an SFVec3f) */
+ws ([ \t\r\n,]|(#.*))+
+    /* And the same pattern without the newline */
+wsnnl ([ \t\r,]|(#.*))
+
+    /* Legal characters to start an identifier */
+idStartChar ([^\x30-\x39\x00-\x20\x22\x23\x27\x2b-\x2e\x5b-\x5d\x7b\x7d])
+    /* Legal other characters in an identifier */
+  /*idRestChar  ([^\x00-\x20\x22\x23\x27\x2b-\x2e\x5b-\x5d\x7b\x7d])*/
+
+  /* Allow hyphen (0x2d) in identifiers. */
+idRestChar  ([^\x00-\x20\x22\x23\x27\x2b-\x2c\x2e\x5b-\x5d\x7b\x7d])
+%%
+
+%{
+    /* Switch into a new start state if the parser */
+    /* just told us that we've read a field name */
+    /* and should expect a field value (or IS) */
+    if (expectToken != 0) {
+      if (vrmlyy_flex_debug)
+          fprintf(stderr,"LEX--> Start State %d\n", expectToken);
+      
+      /*
+       * Annoying.  This big switch is necessary because
+       * LEX wants to assign particular numbers to start
+       * tokens, and YACC wants to define all the tokens
+       * used, too.  Sigh.
+       */
+      switch(expectToken) {
+        case SFBOOL: BEGIN SFB; break;
+        case SFCOLOR: BEGIN SFC; break;
+        case SFFLOAT: BEGIN SFF; break;
+        case SFIMAGE: BEGIN SFIMG; break;
+        case SFINT32: BEGIN SFI; break;
+        case SFROTATION: BEGIN SFR; break;
+        case SFSTRING: BEGIN SFS; break;
+        case SFTIME: BEGIN SFT; break;
+        case SFVEC2F: BEGIN SFV2; break;
+        case SFVEC3F: BEGIN SFV3; break;
+        case MFCOLOR: BEGIN MFC; break;
+        case MFFLOAT: BEGIN MFF; break;
+        case MFINT32: BEGIN MFI; break;
+        case MFROTATION: BEGIN MFR; break;
+        case MFSTRING: BEGIN MFS; break;
+        case MFVEC2F: BEGIN MFV2; break;
+        case MFVEC3F: BEGIN MFV3; break;
+
+        /* SFNode and MFNode are special.  Here the lexer just returns */
+        /* "marker tokens" so the parser knows what type of field is */
+        /* being parsed; unlike the other fields, parsing of SFNode/MFNode */
+        /* field happens in the parser. */
+        case MFNODE: expectToken = 0; return MFNODE;
+        case SFNODE: expectToken = 0; return SFNODE;
+        
+        default: vrmlyyerror("ACK: Bad expectToken"); break;
+      }
+    }
+%}
+
+    /* This is more complicated than they really need to be because */
+    /* I was ambitious and made the whitespace-matching rule aggressive */
+<INITIAL>"#VRML V2.0 utf8".*\n{wsnnl}* {
+  BEGIN NODE; 
+}
+
+    /* The lexer is in the NODE state when parsing nodes, either */
+    /* top-level nodes in the .wrl file, in a prototype implementation, */
+    /* or when parsing the contents of SFNode or MFNode fields. */
+<NODE>PROTO         { return PROTO; }
+<NODE>EXTERNPROTO   { return EXTERNPROTO; }
+<NODE>DEF           { return DEF; }
+<NODE>USE           { return USE; }
+<NODE>TO            { return TO; }
+<NODE>IS            { return IS; }
+<NODE>ROUTE         { return ROUTE; }
+<NODE>NULL          { return SFN_NULL; }
+<NODE>eventIn       { return EVENTIN; }
+<NODE>eventOut      { return EVENTOUT; }
+<NODE>field         { return FIELD; }
+<NODE>exposedField  { return EXPOSEDFIELD; }
+
+    /* Legal identifiers: */
+<NODE>{idStartChar}{idRestChar}* {
+  vrmlyylval.string = strdup(yytext);
+  return IDENTIFIER; 
+}
+   /* This hopefully won't bitch things too much.  It's not legal for
+      an identifier to begin with a digit, but Form-Z writes out VRML
+      files that do.  So we'll allow it.  Hopefully the start states
+      will keep them sorted out. */
+<NODE>[0-9]{idRestChar}* {
+  vrmlyylval.string = strdup(yytext);
+  return IDENTIFIER; 
+}
+
+    /* All fields may have an IS declaration: */
+<SFB,SFC,SFF,SFIMG,SFI,SFR,SFS,SFT,SFV2,SFV3>IS {
+  BEGIN NODE;
+  expectToken = 0;
+  yyless(0);
+}
+
+<MFC,MFF,MFI,MFR,MFS,MFV2,MFV3>IS {
+  BEGIN NODE;
+  expectToken = 0;
+  yyless(0); /* put back the IS */
+}
+
+  /* All MF field types other than MFNode are completely parsed here */
+  /* in the lexer, and one token is returned to the parser.  They all */
+  /* share the same rules for open and closing brackets: */
+<MFC,MFF,MFI,MFR,MFS,MFV2,MFV3>\[ {
+  if (parsing_mf) vrmlyyerror("Double [");
+  parsing_mf = 1;
+  mfarray = new MFArray;
+}
+
+<MFC,MFF,MFI,MFR,MFS,MFV2,MFV3>\] {
+  if (!parsing_mf) vrmlyyerror("Unmatched ]");
+  int fieldType = expectToken;
+  BEGIN NODE;
+  parsing_mf = 0;
+  expectToken = 0;
+  vrmlyylval.fv._mf = mfarray;
+  return fieldType;
+}
+                                      
+<SFB>TRUE {
+  BEGIN NODE;
+  expectToken = 0;
+  vrmlyylval.fv._sfbool = true;
+  return SFBOOL; 
+}
+
+<SFB>FALSE { 
+  BEGIN NODE; 
+  expectToken = 0; 
+  vrmlyylval.fv._sfbool = false;
+  return SFBOOL; 
+}
+
+<SFI>{int} {
+  BEGIN NODE; 
+  expectToken = 0; 
+  vrmlyylval.fv._sfint32 = extract_int();
+  return SFINT32; 
+}
+
+<MFI>{int} { 
+  VrmlFieldValue v;
+  v._sfint32 = extract_int();
+  if (parsing_mf) {
+    mfarray->push_back(v);
+  } else {
+    BEGIN NODE; 
+    expectToken = 0;
+    vrmlyylval.fv._mf = new MFArray;
+    vrmlyylval.fv._mf->push_back(v);
+    return MFINT32;
+  }
+}
+
+  /* All the floating-point types are pretty similar: */
+<SFF>{float} {
+  BEGIN NODE; 
+  expectToken = 0; 
+  vrmlyylval.fv._sffloat = extract_float();
+  return SFFLOAT; 
+}
+
+<MFF>{float} { 
+  VrmlFieldValue v;
+  v._sffloat = extract_float();
+  if (parsing_mf) {
+    /* Add to array... */
+    mfarray->push_back(v);
+  } else {
+    /* No open bracket means a single value: */
+    BEGIN NODE; 
+    expectToken = 0;
+    vrmlyylval.fv._mf = new MFArray;
+    vrmlyylval.fv._mf->push_back(v);
+    return MFFLOAT;
+  }
+}
+
+<SFV2>{float}{ws}{float} { 
+  BEGIN NODE;
+  expectToken = 0;
+  extract_vec(vrmlyylval.fv._sfvec, 2);
+  return SFVEC2F; 
+}
+
+<MFV2>{float}{ws}{float} { 
+  VrmlFieldValue v;
+  extract_vec(v._sfvec, 2);
+  if (parsing_mf) {
+    mfarray->push_back(v);
+  } else {
+    BEGIN NODE;
+    expectToken = 0;
+    vrmlyylval.fv._mf = new MFArray;
+    vrmlyylval.fv._mf->push_back(v);
+    return MFVEC2F;
+  }
+}
+
+<SFV3>({float}{ws}){2}{float} { 
+  BEGIN NODE;
+  expectToken = 0;
+  extract_vec(vrmlyylval.fv._sfvec, 3);
+  return SFVEC3F; 
+}
+
+<MFV3>({float}{ws}){2}{float} { 
+  VrmlFieldValue v;
+  extract_vec(v._sfvec, 3);
+  if (parsing_mf) {
+    mfarray->push_back(v);
+  } else {
+    BEGIN NODE;
+    expectToken = 0;
+    vrmlyylval.fv._mf = new MFArray;
+    vrmlyylval.fv._mf->push_back(v);
+    return MFVEC3F;
+  }
+}
+
+<SFR>({float}{ws}){3}{float} { 
+  BEGIN NODE;
+  expectToken = 0;
+  extract_vec(vrmlyylval.fv._sfvec, 4);
+  return SFROTATION; 
+}
+
+<MFR>({float}{ws}){3}{float} { 
+  VrmlFieldValue v;
+  extract_vec(v._sfvec, 4);
+  if (parsing_mf) {
+    mfarray->push_back(v);
+  } else {
+    BEGIN NODE;
+    expectToken = 0;
+    vrmlyylval.fv._mf = new MFArray;
+    vrmlyylval.fv._mf->push_back(v);
+    return MFROTATION;
+  }
+}
+
+<SFC>({float}{ws}){2}{float} { 
+  BEGIN NODE;
+  expectToken = 0;
+  extract_vec(vrmlyylval.fv._sfvec, 3);
+  return SFCOLOR; 
+}
+
+<MFC>({float}{ws}){2}{float} { 
+  VrmlFieldValue v;
+  extract_vec(v._sfvec, 3);
+  if (parsing_mf) {
+    mfarray->push_back(v);
+  } else {
+    BEGIN NODE;
+    expectToken = 0;
+    vrmlyylval.fv._mf = new MFArray;
+    vrmlyylval.fv._mf->push_back(v);
+    return MFCOLOR;
+  }
+}
+
+<SFT>{float} {
+  BEGIN NODE; 
+  expectToken = 0; 
+  vrmlyylval.fv._sffloat = extract_float();
+  return SFTIME; 
+}
+               
+    /* SFString/MFString */
+<SFS>\" {
+  BEGIN IN_SFS;
+  quoted_string = ""; 
+}
+
+<MFS>\" {
+  BEGIN IN_MFS;
+  quoted_string = ""; 
+}
+
+    /* Anything besides open-quote (or whitespace) is an error: */
+<SFS>[^ \"\t\r\,\n]+ {
+  vrmlyyerror("String missing open-quote");
+  BEGIN NODE; 
+  expectToken = 0; 
+  vrmlyylval.fv._sfstring = strdup(""); 
+  return SFSTRING;
+}
+
+    /* Expect open-quote, open-bracket, or whitespace: */
+<MFS>[^ \[\]\"\t\r\,\n]+ {
+  vrmlyyerror("String missing open-quote");
+  BEGIN NODE;
+  expectToken = 0;
+  return MFSTRING;
+}
+
+    /* Backslashed-quotes are OK: */
+<IN_SFS,IN_MFS>\\\" {
+  quoted_string += '"'; 
+}
+
+    /* Gobble up anything besides quotes and newlines. */
+    /* Newlines are legal in strings, but we exclude them here so */
+    /* that line number are counted correctly by the catch-all newline */
+    /* rule that applies to everything. */
+<IN_SFS,IN_MFS>[^\"\n]+ { 
+  quoted_string += yytext; 
+}
+
+    /* Quote ends the string: */
+<IN_SFS>\" { 
+  BEGIN NODE;
+  expectToken = 0;
+  vrmlyylval.fv._sfstring = strdup(quoted_string.c_str());
+  return SFSTRING; 
+}
+
+<IN_MFS>\" {
+  VrmlFieldValue v;
+  v._sfstring = strdup(quoted_string.c_str());
+  if (parsing_mf) { 
+    BEGIN MFS;
+    mfarray->push_back(v);
+    quoted_string = "";
+  } else {
+    BEGIN NODE;
+    expectToken = 0;
+    vrmlyylval.fv._mf = new MFArray;
+    vrmlyylval.fv._mf->push_back(v);
+    return MFSTRING;
+  }
+}
+
+    /* SFImage: width height numComponents then width*height integers: */
+<SFIMG>{int}{ws}{int}   { int w, h;
+                          sscanf(yytext, "%d %d", &w, &h);
+                          sfImageIntsExpected = 1+w*h;
+                          sfImageIntsParsed = 0;                          
+                          BEGIN IN_SFIMG;
+                        }
+<IN_SFIMG>{int}         { ++sfImageIntsParsed;
+                          if (sfImageIntsParsed == sfImageIntsExpected) {
+                              BEGIN NODE; expectToken = 0; return SFIMAGE;
+                          }
+                        }
+
+    /* Whitespace and catch-all rules apply to all start states: */
+<*>{wsnnl}+     ;
+    /* This is also whitespace, but we'll keep track of line number */
+    /* to report in errors: */
+<*>{wsnnl}*\n{wsnnl}*	;
+
+    /* This catch-all rule catches anything not covered by any of */
+    /* the above: */
+<*>.            { return yytext[0]; }
+

+ 33 - 0
pandatool/src/vrml/vrmlLexerDefs.h

@@ -0,0 +1,33 @@
+// Filename: vrmlLexerDefs.h
+// Created by:  drose (30Sep04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef VRMLLEXERDEFS_H
+#define VRMLLEXERDEFS_H
+
+#include "pandatoolbase.h"
+
+void vrml_init_lexer(istream &in, const string &filename);
+int vrml_error_count();
+int vrml_warning_count();
+
+void vrmlyyerror(const string &msg);
+void vrmlyywarning(const string &msg);
+
+int vrmlyylex();
+
+#endif

+ 81 - 0
pandatool/src/vrml/vrmlNode.cxx

@@ -0,0 +1,81 @@
+// Filename: vrmlNode.cxx
+// Created by:  drose (23Jun99)
+// 
+////////////////////////////////////////////////////////////////////
+// Copyright (C) 1992,93,94,95,96,97  Walt Disney Imagineering, Inc.
+// 
+// These  coded  instructions,  statements,  data   structures   and
+// computer  programs contain unpublished proprietary information of
+// Walt Disney Imagineering and are protected by  Federal  copyright
+// law.  They may  not be  disclosed to third  parties  or copied or
+// duplicated in any form, in whole or in part,  without  the  prior
+// written consent of Walt Disney Imagineering Inc.
+////////////////////////////////////////////////////////////////////
+
+#include "vrmlNode.h"
+#include "vrmlParser.h"
+
+#include "indent.h"
+#include "notify.h"
+
+VrmlNode::
+VrmlNode(const VrmlNodeType *type) {
+  _type = type;
+  _use_count = 0;
+}
+
+VrmlNode::
+~VrmlNode() {
+}
+
+ 
+const VrmlFieldValue &VrmlNode::
+get_value(const char *field_name) const {
+  Fields::const_iterator fi;
+  for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
+    if (strcmp((*fi)._type->name, field_name) == 0) {
+      return ((*fi)._value);
+    }
+  }
+
+  // That field was not defined.  Get the default value.
+  const VrmlNodeType::NameTypeRec *field = _type->hasField(field_name);
+  if (field != NULL) {
+    return field->dflt;
+  }
+
+  cerr << "No such field defined for type " << _type->getName() << ": "
+       << field_name << "\n";
+  exit(1);
+  // Just to make the compiler happy.
+  static VrmlFieldValue zero;
+  return zero;
+}
+
+void VrmlNode::
+output(ostream &out, int indent_level) const {
+  out << _type->getName() << " {\n";
+  Fields::const_iterator fi;
+  for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
+    indent(out, indent_level + 2) << (*fi)._type->name << " ";
+    output_value(out, (*fi)._value, (*fi)._type->type, indent_level + 2) << "\n";
+  }
+  indent(out, indent_level) << "}";
+}
+
+
+void Declaration::
+output(ostream &out, int indent) const {
+  VrmlFieldValue v;
+  v._sfnode = _node;
+  output_value(out, v, SFNODE, indent);
+}
+
+ostream &operator << (ostream &out, const VrmlScene &scene) {
+  VrmlScene::const_iterator si;
+  for (si = scene.begin(); si != scene.end(); ++si) {
+    out << (*si) << "\n";
+  }
+
+  return out;
+}

+ 71 - 0
pandatool/src/vrml/vrmlNode.h

@@ -0,0 +1,71 @@
+// Filename: vrmlNode.h
+// Created by:  drose (23Jun99)
+// 
+////////////////////////////////////////////////////////////////////
+// Copyright (C) 1992,93,94,95,96,97  Walt Disney Imagineering, Inc.
+// 
+// These  coded  instructions,  statements,  data   structures   and
+// computer  programs contain unpublished proprietary information of
+// Walt Disney Imagineering and are protected by  Federal  copyright
+// law.  They may  not be  disclosed to third  parties  or copied or
+// duplicated in any form, in whole or in part,  without  the  prior
+// written consent of Walt Disney Imagineering Inc.
+////////////////////////////////////////////////////////////////////
+
+#ifndef VRMLNODE_H
+#define VRMLNODE_H
+
+#include "pandatoolbase.h"
+
+#include "vrmlNodeType.h"
+#include "pvector.h"
+#include "pmap.h"
+
+class VrmlNode {
+public:
+  VrmlNode(const VrmlNodeType *type);
+  ~VrmlNode();
+
+  const VrmlFieldValue &get_value(const char *field_name) const;
+
+  void output(ostream &out, int indent) const;
+
+  class Field {
+  public:
+    Field() { }
+    Field(const VrmlNodeType::NameTypeRec *type, const VrmlFieldValue &value) :
+      _type(type), _value(value) { }
+    const VrmlNodeType::NameTypeRec *_type;
+    VrmlFieldValue _value;
+  };
+
+  typedef vector<Field> Fields;
+  Fields _fields;
+
+  int _use_count;
+
+  const VrmlNodeType *_type;
+};
+
+inline ostream &operator << (ostream &out, const VrmlNode &node) {
+  node.output(out, 0);
+  return out;
+}
+
+class Declaration {
+public:
+  SFNodeRef _node;
+
+  void output(ostream &out, int indent) const;
+};
+
+inline ostream &operator << (ostream &out, const Declaration &dec) {
+  dec.output(out, 0);
+  return out;
+}
+
+typedef pvector<Declaration> VrmlScene;
+
+ostream &operator << (ostream &out, const VrmlScene &scene);
+
+#endif

+ 333 - 0
pandatool/src/vrml/vrmlNodeType.cxx

@@ -0,0 +1,333 @@
+/**************************************************
+ * VRML 2.0 Parser
+ * Copyright (C) 1996 Silicon Graphics, Inc.
+ *
+ * Author(s)    : Gavin Bell
+ *                Daniel Woods (first port)
+ **************************************************
+ */
+
+//
+// The VrmlNodeType class is responsible for storing information about node
+// or prototype types.
+//
+
+#include "vrmlNodeType.h"
+#include "vrmlNode.h"
+#include "vrmlParser.h"
+#include "notify.h"
+#include "indent.h"
+
+//
+// Static list of node types.
+//
+plist<VrmlNodeType*> VrmlNodeType::typeList;
+
+static ostream &
+output_array(ostream &out, const MFArray *mf,
+	     int type, int indent_level, int items_per_row) {
+  if (mf->empty()) {
+    out << "[ ]";
+  } else {
+    out << "[";
+    MFArray::const_iterator mi;
+    int col = 0;
+    for (mi = mf->begin(); mi != mf->end(); ++mi) {
+      if (col == 0) {
+	out << "\n";
+	indent(out, indent_level + 2);
+      }      
+      output_value(out, (*mi), type, indent_level + 2);
+      if (++col >= items_per_row) {
+	col = 0;
+      } else {
+	out << " ";
+      }
+    }
+    out << "\n";
+    indent(out, indent_level) << "]";
+  }
+  return out;
+}
+
+ostream & 
+output_value(ostream &out, const VrmlFieldValue &value, int type,
+	     int indent) {
+  switch (type) {
+  case SFBOOL:
+    return out << (value._sfbool ? "TRUE" : "FALSE");
+
+  case SFFLOAT:
+  case SFTIME:
+    return out << value._sffloat;
+
+  case SFINT32:
+    return out << value._sfint32;
+
+  case SFSTRING:
+    {
+      out << '"';
+      for (const char *p = value._sfstring; *p != '\0'; p++) {
+	if (*p == '"') {
+	  out << "\\\"";
+	} else {
+	  out << *p;
+	}
+      }
+      return out << '"';
+    }
+
+  case SFVEC2F:
+    return out << value._sfvec[0] << " " << value._sfvec[1];
+
+  case SFCOLOR:
+  case SFVEC3F:
+    return out << value._sfvec[0] << " " << value._sfvec[1] << " "
+	       << value._sfvec[2];
+
+  case SFROTATION:
+    return out << value._sfvec[0] << " " << value._sfvec[1] << " "
+	       << value._sfvec[2] << " " << value._sfvec[3];
+
+  case SFNODE:
+    switch (value._sfnode._type) {
+    case SFNodeRef::T_null:
+      return out << "NULL";
+
+    case SFNodeRef::T_unnamed:
+      nassertr(value._sfnode._p != NULL, out);
+      value._sfnode._p->output(out, indent);
+      return out;
+
+    case SFNodeRef::T_def:
+      out << "DEF " << value._sfnode._name << " ";
+      value._sfnode._p->output(out, indent);
+      return out;
+
+    case SFNodeRef::T_use:
+      return out << "USE " << value._sfnode._name;
+    }
+    return out << "(invalid)";
+
+  case SFIMAGE:
+    return out << "(image)";
+
+  case MFCOLOR:
+    return output_array(out, value._mf, SFCOLOR, indent, 1);
+
+  case MFFLOAT:
+    return output_array(out, value._mf, SFFLOAT, indent, 5);
+
+  case MFINT32:
+    return output_array(out, value._mf, SFINT32, indent, 10);
+
+  case MFROTATION:
+    return output_array(out, value._mf, SFROTATION, indent, 1);
+
+  case MFSTRING:
+    return output_array(out, value._mf, SFSTRING, indent, 1);
+
+  case MFVEC2F:
+    return output_array(out, value._mf, SFVEC2F, indent, 1);
+
+  case MFVEC3F:
+    return output_array(out, value._mf, SFVEC3F, indent, 1);
+
+  case MFNODE:
+    return output_array(out, value._mf, SFNODE, indent, 1);
+  }
+
+  return out << "(unknown)";
+}
+
+VrmlNodeType::VrmlNodeType(const char *nm)
+{
+    nassertv(nm != NULL);
+    name = strdup(nm);
+}
+
+VrmlNodeType::~VrmlNodeType()
+{
+    free(name);
+
+    // Free strings duplicated when fields/eventIns/eventOuts added:
+    plist<NameTypeRec*>::iterator i;
+
+    for (i = eventIns.begin(); i != eventIns.end(); i++) {
+        NameTypeRec *r = *i;
+        free(r->name);
+        delete r;
+    }
+    for (i = eventOuts.begin(); i != eventOuts.end(); i++) {
+        NameTypeRec *r = *i;
+        free(r->name);
+        delete r;
+    }
+    for (i = fields.begin(); i != fields.end(); i++) {
+        NameTypeRec *r = *i;
+        free(r->name);
+        delete r;
+    }
+}
+
+void
+VrmlNodeType::addToNameSpace(VrmlNodeType *_type)
+{
+    if (find(_type->getName()) != NULL) {
+        cerr << "PROTO " << _type->getName() << " already defined\n";
+        return;
+    }
+    typeList.push_front(_type);
+}
+
+//
+// One list is used to store all the node types.  Nested namespaces are
+// separated by NULL elements.
+// This isn't terribly efficient, but it is nice and simple.
+//
+void
+VrmlNodeType::pushNameSpace()
+{
+    typeList.push_front(NULL);
+}
+
+void
+VrmlNodeType::popNameSpace()
+{
+    // Remove everything up to and including the next NULL marker:
+    plist<VrmlNodeType*>::iterator i;
+    for (i = typeList.begin(); i != typeList.end();) {
+        VrmlNodeType *nodeType = *i;
+        ++i;
+        typeList.pop_front();
+
+        if (nodeType == NULL) {
+            break;
+        }
+        else {
+            // NOTE:  Instead of just deleting the VrmlNodeTypes, you will
+            // probably want to reference count or garbage collect them, since
+            // any nodes created as part of the PROTO implementation will
+            // probably point back to their VrmlNodeType structure.
+            delete nodeType;
+        }
+    }
+}
+
+const VrmlNodeType *
+VrmlNodeType::find(const char *_name)
+{
+    // Look through the type stack:
+    plist<VrmlNodeType*>::iterator i;
+    for (i = typeList.begin(); i != typeList.end(); i++) {
+        const VrmlNodeType *nt = *i;
+        if (nt != NULL && strcmp(nt->getName(),_name) == 0) {
+            return nt;
+        }
+    }
+    return NULL;
+}
+
+void
+VrmlNodeType::addEventIn(const char *name, int type,
+			 const VrmlFieldValue *dflt)
+{
+    add(eventIns, name, type, dflt);
+};
+void
+VrmlNodeType::addEventOut(const char *name, int type,
+			  const VrmlFieldValue *dflt)
+{
+    add(eventOuts, name, type, dflt);
+};
+void
+VrmlNodeType::addField(const char *name, int type,
+		       const VrmlFieldValue *dflt)
+{
+    add(fields, name, type, dflt);
+};
+void
+VrmlNodeType::addExposedField(const char *name, int type,
+			      const VrmlFieldValue *dflt)
+{
+    char tmp[1000];
+    add(fields, name, type, dflt);
+    sprintf(tmp, "set_%s", name);
+    add(eventIns, tmp, type, dflt);
+    sprintf(tmp, "%s_changed", name);
+    add(eventOuts, tmp, type, dflt);
+};
+
+void
+VrmlNodeType::add(plist<NameTypeRec*> &recs, const char *name, int type,
+		  const VrmlFieldValue *dflt)
+{
+    NameTypeRec *r = new NameTypeRec;
+    r->name = strdup(name);
+    r->type = type;
+    if (dflt != NULL) {
+      r->dflt = *dflt;
+    } else {
+      memset(&r->dflt, 0, sizeof(r->dflt));
+    }
+    recs.push_front(r);
+}
+
+const VrmlNodeType::NameTypeRec *
+VrmlNodeType::hasEventIn(const char *name) const
+{
+    return has(eventIns, name);
+}
+
+const VrmlNodeType::NameTypeRec *
+VrmlNodeType::hasEventOut(const char *name) const
+{
+    return has(eventOuts, name);
+}
+
+const VrmlNodeType::NameTypeRec *
+VrmlNodeType::hasField(const char *name) const
+{
+    return has(fields, name);
+}
+
+const VrmlNodeType::NameTypeRec *
+VrmlNodeType::hasExposedField(const char *name) const
+{
+    // Must have field "name", eventIn "set_name", and eventOut
+    // "name_changed", all with same type:
+    char tmp[1000];
+    const NameTypeRec *base, *set_name, *name_changed;
+
+    base = has(fields, name);
+
+    sprintf(tmp, "set_%s\n", name);
+    nassertr(strlen(tmp) < 1000, NULL);
+    set_name = has(eventIns, tmp);
+
+    sprintf(tmp, "%s_changed\n", name);
+    nassertr(strlen(tmp) < 1000, NULL);
+    name_changed = has(eventOuts, tmp);
+
+    if (base == NULL || set_name == NULL || name_changed == NULL) {
+      return NULL;
+    }
+
+    if (base->type != set_name->type || base->type != name_changed->type) {
+      return NULL;
+    }
+
+    return base;
+}
+
+const VrmlNodeType::NameTypeRec *
+VrmlNodeType::has(const plist<NameTypeRec*> &recs, const char *name) const
+{
+    plist<NameTypeRec*>::const_iterator i;
+    for (i = recs.begin(); i != recs.end(); i++) {
+        if (strcmp((*i)->name, name) == 0)
+            return (*i);
+    }
+    return NULL;
+}
+

+ 108 - 0
pandatool/src/vrml/vrmlNodeType.h

@@ -0,0 +1,108 @@
+/**************************************************
+ * VRML 2.0 Parser
+ * Copyright (C) 1996 Silicon Graphics, Inc.
+ *
+ * Author(s)    : Gavin Bell
+ *                Daniel Woods (first port)
+ **************************************************
+ */
+
+#ifndef VRMLNODETYPE_H
+#define VRMLNODETYPE_H
+
+//
+// The VrmlNodeType class is responsible for storing information about node
+// or prototype types.
+//
+
+
+#include "pandatoolbase.h"
+
+#include "plist.h"
+#include "pvector.h"
+
+class VrmlNode;
+
+struct SFNodeRef {
+  VrmlNode *_p;
+  enum { T_null, T_unnamed, T_def, T_use } _type;
+  char *_name;
+};
+
+union VrmlFieldValue {
+  bool _sfbool;
+  double _sffloat;
+  long _sfint32;
+  char *_sfstring;
+  double _sfvec[4];
+  SFNodeRef _sfnode;
+  pvector<VrmlFieldValue> *_mf;
+};
+
+typedef pvector<VrmlFieldValue> MFArray;
+
+
+ostream &output_value(ostream &out, const VrmlFieldValue &value, int type,
+		      int indent = 0);
+
+
+class VrmlNodeType {
+public:
+  // Constructor.  Takes name of new type (e.g. "Transform" or "Box")
+  // Copies the string given as name.
+  VrmlNodeType(const char *nm);
+  
+  // Destructor exists mainly to deallocate storage for name
+  ~VrmlNodeType();
+  
+  // Namespace management functions.  PROTO definitions add node types
+  // to the namespace.  PROTO implementations are a separate node
+  // namespace, and require that any nested PROTOs NOT be available
+  // outside the PROTO implementation.
+  // addToNameSpace will print an error to stderr if the given type
+  // is already defined.
+  static void addToNameSpace(VrmlNodeType *);
+  static void pushNameSpace();
+  static void popNameSpace();
+  
+  // Find a node type, given its name.  Returns NULL if type is not defined.
+  static const VrmlNodeType *find(const char *nm);
+  
+  // Routines for adding/getting eventIns/Outs/fields
+  void addEventIn(const char *name, int type, 
+                  const VrmlFieldValue *dflt = NULL);
+  void addEventOut(const char *name, int type,
+                   const VrmlFieldValue *dflt = NULL);
+  void addField(const char *name, int type,
+                const VrmlFieldValue *dflt = NULL);
+  void addExposedField(const char *name, int type,
+                       const VrmlFieldValue *dflt = NULL);
+  
+  typedef struct {
+    char *name;
+    int type;
+    VrmlFieldValue dflt;
+  } NameTypeRec;
+  
+  const NameTypeRec *hasEventIn(const char *name) const;
+  const NameTypeRec *hasEventOut(const char *name) const;
+  const NameTypeRec *hasField(const char *name) const;
+  const NameTypeRec *hasExposedField(const char *name) const;
+  
+  const char *getName() const { return name; }
+  
+private:
+  void add(plist<NameTypeRec*> &,const char *,int, const VrmlFieldValue *dflt);
+  const NameTypeRec *has(const plist<NameTypeRec*> &,const char *) const;
+  
+  char *name;
+  
+  // Node types are stored in this data structure:
+  static plist<VrmlNodeType*> typeList;
+  
+  plist<NameTypeRec*> eventIns;
+  plist<NameTypeRec*> eventOuts;
+  plist<NameTypeRec*> fields;
+};
+
+#endif

+ 570 - 0
pandatool/src/vrml/vrmlParser.yxx

@@ -0,0 +1,570 @@
+// Filename: vrmlParser.yxx
+// Created by:  drose (01Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+// *******************************************************
+// VRML 2.0 Parser
+// Copyright (C) 1996 Silicon Graphics, Inc.
+//
+// Author(s)    : Gavin Bell
+//                Daniel Woods (first port, minor fixes)
+// *******************************************************
+//
+%{
+
+//
+// Parser for VRML 2.0 files.
+// This is a minimal parser that does NOT generate an in-memory scene graph.
+// 
+
+// The original parser was developed on a Windows 95 PC with
+// Borland's C++ 5.0 development tools.  This was then ported
+// to a Windows 95 PC with Microsoft's MSDEV C++ 4.0 development
+// tools.  The port introduced the ifdef's for
+//    USING_BORLAND_CPP_5          : since this provides a "std namespace",
+//    TWO_ARGUMENTS_FOR_STL_STACK  : STL is a moving target.  The stack template
+//                                     class takes either one or two arguments.
+
+#include "pandatoolbase.h"
+#include "vrmlLexerDefs.h"
+#include "vrmlNodeType.h"
+#include "vrmlNode.h"
+#include "notify.h"
+#include "plist.h"
+#include <stack>
+
+//#define YYDEBUG 1
+
+// Currently-being-define proto.  Prototypes may be nested, so a stack
+// is needed:
+
+stack< VrmlNodeType*, plist<VrmlNodeType*> > currentProtoStack;
+
+// This is used to keep track of which field in which type of node is being
+// parsed.  Field are nested (nodes are contained inside MFNode/SFNode fields)
+// so a stack of these is needed:
+typedef struct {
+    const VrmlNodeType *nodeType;
+    const char *fieldName;
+    const VrmlNodeType::NameTypeRec *typeRec;
+} FieldRec;
+
+stack< FieldRec*, plist<FieldRec*> > currentField;
+
+// Similarly for the node entries (which contain the actual values for
+// the fields as they are encountered):
+
+stack< VrmlNode*, plist<VrmlNode*> > currentNode;
+
+// This is used when the parser knows what kind of token it expects
+// to get next-- used when parsing field values (whose types are declared
+// and read by the parser) and at certain other places:
+extern int expectToken;
+
+// This is where we store the parsed scene.
+VrmlScene *parsed_scene = NULL;
+
+// Some helper routines defined below:
+static void beginProto(const char *);
+static void endProto();
+int addField(const char *type, const char *name, const VrmlFieldValue *dflt = NULL);
+int addEventIn(const char *type, const char *name, const VrmlFieldValue *dflt = NULL);
+int addEventOut(const char *type, const char *name, const VrmlFieldValue *dflt = NULL);
+int addExposedField(const char *type, const char *name, const VrmlFieldValue *dflt = NULL);
+int add(void (VrmlNodeType::*func)(const char *, int, const VrmlFieldValue *), 
+	const char *typeString, const char *name,
+	const VrmlFieldValue *dflt);
+int fieldType(const char *type);
+void enterNode(const char *);
+VrmlNode *exitNode();
+void inScript();
+void enterField(const char *);
+void storeField(const VrmlFieldValue &value);
+void exitField();
+void expect(int type);
+
+extern void vrmlyyerror(const string &);
+
+////////////////////////////////////////////////////////////////////
+// Defining the interface to the parser.
+////////////////////////////////////////////////////////////////////
+
+void
+vrml_init_parser(istream &in, const string &filename) {
+  //yydebug = 0;
+  vrml_init_lexer(in, filename);
+}
+
+void
+vrml_cleanup_parser() {
+}
+
+%}
+
+%union {
+  char *string;
+  VrmlFieldValue fv;
+  VrmlNode *node;
+  MFArray *mfarray;
+  SFNodeRef nodeRef;
+  VrmlScene *scene;
+};
+
+%type <fv> fieldValue
+%type <node> node
+%type <nodeRef> nodeDeclaration
+%type <mfarray> mfnodeValue nodes
+%type <scene> declarations
+
+/*
+ * And types that will be needed by a true VRML implementation:
+ * %type <nodeList> vrmlscene declarations
+ */
+
+%token <string> IDENTIFIER 
+%token DEF USE PROTO EXTERNPROTO TO IS ROUTE SFN_NULL
+%token EVENTIN EVENTOUT FIELD EXPOSEDFIELD
+
+%token <fv> SFBOOL SFCOLOR SFFLOAT SFIMAGE SFINT32 SFNODE SFROTATION
+%token <fv> SFSTRING SFTIME SFVEC2F SFVEC3F
+%token <fv> MFCOLOR MFFLOAT MFINT32 MFROTATION MFSTRING MFVEC2F MFVEC3F
+%token <fv> MFNODE
+
+%%
+
+vrmlscene:  declarations
+{
+  parsed_scene = $1;
+}
+    ;
+
+declarations:
+    /* Empty is OK */ 
+{
+  $$ = new VrmlScene;
+}
+    |  declarations nodeDeclaration
+{
+  Declaration d;
+  d._node = $2;
+  $1->push_back(d);
+  $$ = $1;
+}
+    |  declarations protoDeclaration
+    |  declarations routeDeclaration
+    ;
+
+nodeDeclaration:
+        node
+{
+  $$._p = $1;
+  $$._type = SFNodeRef::T_unnamed;
+  $$._name = NULL;
+}
+    |   DEF IDENTIFIER node    
+{
+  $$._p = $3;
+  $$._type = SFNodeRef::T_def;
+  $$._name = $2;
+}
+    |   USE IDENTIFIER
+{
+  $$._p = NULL;
+  $$._type = SFNodeRef::T_use;
+  $$._name = $2;
+}
+    ;
+
+protoDeclaration:
+        proto
+    |   externproto
+    ;
+
+proto:
+         PROTO IDENTIFIER           { beginProto($2); }                     
+            '[' interfaceDeclarations ']'
+            '{' declarations '}'    { endProto();  free($2);}
+    ;
+
+externproto:
+         EXTERNPROTO IDENTIFIER         { beginProto($2); }                     
+            '[' externInterfaceDeclarations ']' 
+                                        { expect(MFSTRING); }
+            fieldValue                  { endProto();  free($2); }
+    ;
+interfaceDeclarations:
+        /* Empty is OK */
+    |   interfaceDeclarations interfaceDeclaration
+    ;
+
+interfaceDeclaration:
+        EVENTIN IDENTIFIER IDENTIFIER       { addEventIn($2, $3);
+                                              free($2); free($3); }
+    |   EVENTOUT IDENTIFIER IDENTIFIER      { addEventOut($2, $3);
+                                              free($2); free($3); }
+    |   FIELD IDENTIFIER IDENTIFIER         
+{
+  int type = fieldType($2);
+  expect(type); 
+}
+            fieldValue                      
+{
+  addField($2, $3, &($5));
+  free($2); 
+  free($3); 
+}
+    |   EXPOSEDFIELD IDENTIFIER IDENTIFIER  
+{ 
+  int type = fieldType($2);
+  expect(type); 
+}
+            fieldValue                      
+{ 
+  addExposedField($2, $3, &($5));
+  free($2); 
+  free($3); 
+}
+    ;
+
+externInterfaceDeclarations:
+        /* Empty is OK */
+     |  externInterfaceDeclarations externInterfaceDeclaration
+     ;
+
+externInterfaceDeclaration:
+        EVENTIN IDENTIFIER IDENTIFIER       { addEventIn($2, $3);
+                                              free($2); free($3); }
+    |   EVENTOUT IDENTIFIER IDENTIFIER      { addEventOut($2, $3);
+                                              free($2); free($3); }
+    |   FIELD IDENTIFIER IDENTIFIER         { addField($2, $3);
+                                              free($2); free($3); }
+    |   EXPOSEDFIELD IDENTIFIER IDENTIFIER  { addExposedField($2, $3);
+                                              free($2); free($3); }
+    ;
+
+routeDeclaration:
+        ROUTE IDENTIFIER '.' IDENTIFIER TO IDENTIFIER '.' IDENTIFIER
+                { free($2); free($4); free($6); free($8); }
+    ; 
+
+node:
+        IDENTIFIER                  { enterNode($1); }
+            '{' nodeGuts '}'        { $$ = exitNode(); free($1);}
+    ;
+
+nodeGuts:
+        /* Empty is OK */
+    |   nodeGuts nodeGut
+    ;
+
+nodeGut:
+        IDENTIFIER                  { enterField($1); }
+                fieldValue          
+{
+  storeField($3);
+  exitField(); 
+  free($1); 
+}
+    |   routeDeclaration
+    |   protoDeclaration
+
+        /* The following are only valid for Script nodes: */
+    |   EVENTIN IDENTIFIER IDENTIFIER       { inScript(); free($2); free($3); }
+    |   EVENTOUT IDENTIFIER IDENTIFIER      { inScript(); free($2); free($3); }
+    |   FIELD IDENTIFIER IDENTIFIER         { inScript(); 
+                                              int type = fieldType($2);
+                                              expect(type); }
+            fieldValue                      { free($2); free($3); }
+    |   EVENTIN IDENTIFIER IDENTIFIER IS IDENTIFIER
+                { inScript(); free($2); free($3); free($5); }
+    |   EVENTOUT IDENTIFIER IDENTIFIER IS IDENTIFIER
+                { inScript(); free($2); free($3); free($5); }
+   ;
+
+fieldValue:
+	SFBOOL
+    |   SFCOLOR
+    |   MFCOLOR
+    |   SFFLOAT
+    |   MFFLOAT
+    |   SFIMAGE
+    |   SFINT32
+    |   MFINT32
+    |   SFROTATION
+    |   MFROTATION
+    |   SFSTRING
+    |   MFSTRING
+    |   SFTIME
+    |   SFVEC2F
+    |   MFVEC2F
+    |   SFVEC3F
+    |   MFVEC3F
+    
+    |   SFNODE nodeDeclaration { $$._sfnode = $2; }
+    |   SFNODE SFN_NULL 
+{ 
+  $$._sfnode._p = NULL;
+  $$._sfnode._type = SFNodeRef::T_null;
+  $$._sfnode._name = NULL;
+}
+    |   MFNODE mfnodeValue { $$._mf = $2; }
+    |   IS IDENTIFIER               { free($2); }
+    ;
+
+mfnodeValue:
+    '[' nodes ']' 
+{
+  $$ = $2; 
+}
+    |  nodeDeclaration 
+{
+  $$ = new MFArray;
+  VrmlFieldValue v;
+  v._sfnode = $1;
+  $$->push_back(v);
+}
+     ;
+
+nodes:
+    /* Empty is OK */ 
+{
+  $$ = new MFArray;
+}
+     |  nodes nodeDeclaration
+{
+  VrmlFieldValue v;
+  v._sfnode = $2;
+  $1->push_back(v);
+  $$ = $1;
+}
+     ;
+
+%%
+
+static void
+beginProto(const char *protoName)
+{
+    // Any protos in the implementation are in a local namespace:
+    VrmlNodeType::pushNameSpace();
+
+    VrmlNodeType *t = new VrmlNodeType(protoName);
+    currentProtoStack.push(t);
+}
+
+static void
+endProto()
+{
+    // Make any protos defined in implementation unavailable:
+    VrmlNodeType::popNameSpace();
+
+    // Add this proto definition:
+    if (currentProtoStack.empty()) {
+        cerr << "Error: Empty PROTO stack!\n";
+    }
+    else {
+        VrmlNodeType *t = currentProtoStack.top();
+        currentProtoStack.pop();
+        VrmlNodeType::addToNameSpace(t);
+    }
+}
+
+int
+addField(const char *type, const char *name,
+	 const VrmlFieldValue *dflt)
+{
+    return add(&VrmlNodeType::addField, type, name, dflt);
+}
+
+int
+addEventIn(const char *type, const char *name,
+	   const VrmlFieldValue *dflt)
+{
+    return add(&VrmlNodeType::addEventIn, type, name, dflt);
+}
+int
+addEventOut(const char *type, const char *name,
+	    const VrmlFieldValue *dflt)
+{
+  return add(&VrmlNodeType::addEventOut, type, name, dflt);
+}
+int
+addExposedField(const char *type, const char *name,
+		const VrmlFieldValue *dflt)
+{
+    return add(&VrmlNodeType::addExposedField, type, name, dflt);
+}
+
+int
+add(void (VrmlNodeType::*func)(const char *, int, const VrmlFieldValue *), 
+    const char *typeString, const char *name,
+    const VrmlFieldValue *dflt)
+{
+    int type = fieldType(typeString);
+
+    if (type == 0) {
+        cerr << "Error: invalid field type: " << type << "\n";
+    }
+
+    // Need to add support for Script nodes:
+    // if (inScript) ... ???
+
+    if (currentProtoStack.empty()) {
+        cerr << "Error: declaration outside of prototype\n";
+        return 0;
+    }
+    VrmlNodeType *t = currentProtoStack.top();
+    (t->*func)(name, type, dflt);
+
+    return type;
+}
+
+int
+fieldType(const char *type)
+{
+    if (strcmp(type, "SFBool") == 0) return SFBOOL;
+    if (strcmp(type, "SFColor") == 0) return SFCOLOR;
+    if (strcmp(type, "SFFloat") == 0) return SFFLOAT;
+    if (strcmp(type, "SFImage") == 0) return SFIMAGE;
+    if (strcmp(type, "SFInt32") == 0) return SFINT32;
+    if (strcmp(type, "SFNode") == 0) return SFNODE;
+    if (strcmp(type, "SFRotation") == 0) return SFROTATION;
+    if (strcmp(type, "SFString") == 0) return SFSTRING;
+    if (strcmp(type, "SFTime") == 0) return SFTIME;
+    if (strcmp(type, "SFVec2f") == 0) return SFVEC2F;
+    if (strcmp(type, "SFVec3f") == 0) return SFVEC3F;
+    if (strcmp(type, "MFColor") == 0) return MFCOLOR;
+    if (strcmp(type, "MFFloat") == 0) return MFFLOAT;
+    if (strcmp(type, "MFInt32") == 0) return MFINT32;
+    if (strcmp(type, "MFNode") == 0) return MFNODE;
+    if (strcmp(type, "MFRotation") == 0) return MFROTATION;
+    if (strcmp(type, "MFString") == 0) return MFSTRING;
+    if (strcmp(type, "MFVec2f") == 0) return MFVEC2F;
+    if (strcmp(type, "MFVec3f") == 0) return MFVEC3F;
+
+    cerr << "Illegal field type: " << type << "\n";
+
+    return 0;
+}
+
+void
+enterNode(const char *nodeType)
+{
+    const VrmlNodeType *t = VrmlNodeType::find(nodeType);
+    if (t == NULL) {
+        char tmp[1000];
+        sprintf(tmp, "Unknown node type '%s'", nodeType);
+        vrmlyyerror(tmp);
+    }
+    FieldRec *fr = new FieldRec;
+    fr->nodeType = t;
+    fr->fieldName = NULL;
+    fr->typeRec = NULL;
+    currentField.push(fr);
+
+    VrmlNode *node = new VrmlNode(t);
+    currentNode.push(node);
+}
+
+VrmlNode *
+exitNode()
+{
+    FieldRec *fr = currentField.top();
+    nassertr(fr != NULL, NULL);
+    currentField.pop();
+
+    VrmlNode *node = currentNode.top();
+    nassertr(node != NULL, NULL);
+    currentNode.pop();
+
+    //    cerr << "Just defined node:\n" << *node << "\n\n";
+
+    delete fr;
+    return node;
+}
+
+void
+inScript()
+{
+    FieldRec *fr = currentField.top();
+    if (fr->nodeType == NULL ||
+        strcmp(fr->nodeType->getName(), "Script") != 0) {
+        vrmlyyerror("interface declaration outside of Script or prototype");
+    }
+}
+
+void
+enterField(const char *fieldName)
+{
+    FieldRec *fr = currentField.top();
+    nassertv(fr != NULL);
+
+    fr->fieldName = fieldName;
+    fr->typeRec = NULL;
+    if (fr->nodeType != NULL) {
+        // enterField is called when parsing eventIn and eventOut IS
+        // declarations, in which case we don't need to do anything special--
+        // the IS IDENTIFIER will be returned from the lexer normally.
+        if (fr->nodeType->hasEventIn(fieldName) ||
+            fr->nodeType->hasEventOut(fieldName))
+            return;
+    
+        const VrmlNodeType::NameTypeRec *typeRec =
+	  fr->nodeType->hasField(fieldName);
+        if (typeRec != NULL) {
+	    fr->typeRec = typeRec;
+            // Let the lexer know what field type to expect:
+            expect(typeRec->type);
+        }
+        else {
+            cerr << "Error: Nodes of type " << fr->nodeType->getName() <<
+                " do not have fields/eventIn/eventOut named " <<
+                fieldName << "\n";
+            // expect(ANY_FIELD);
+        }
+    }
+    // else expect(ANY_FIELD);
+}
+
+void
+storeField(const VrmlFieldValue &value) {
+  FieldRec *fr = currentField.top();
+  nassertv(fr != NULL);
+
+  VrmlNode *node = currentNode.top();
+  nassertv(node != NULL);
+
+  if (fr->typeRec != NULL) {
+    node->_fields.push_back(VrmlNode::Field(fr->typeRec, value));
+  }
+}
+
+void
+exitField()
+{
+    FieldRec *fr = currentField.top();
+    nassertv(fr != NULL);
+
+    fr->fieldName = NULL;
+    fr->typeRec = NULL;
+}
+
+void
+expect(int type)
+{
+    expectToken = type;
+}
+

+ 28 - 0
pandatool/src/vrml/vrmlParserDefs.h

@@ -0,0 +1,28 @@
+// Filename: vrmlParserDefs.h
+// Created by:  drose (30Sep04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef VRMLPARSERDEFS_H
+#define VRMLPARSERDEFS_H
+
+#include "pandatoolbase.h"
+
+void vrml_init_parser(istream &in, const string &filename);
+void vrml_cleanup_parser();
+int vrmlyyparse();
+
+#endif

+ 20 - 0
pandatool/src/vrmlegg/Sources.pp

@@ -0,0 +1,20 @@
+#begin ss_lib_target
+  #define TARGET vrmlegg
+  #define LOCAL_LIBS converter pvrml pandatoolbase
+  #define OTHER_LIBS \
+    egg:c event:c pandaegg:m \
+    mathutil:c linmath:c putil:c express:c panda:m \
+    interrogatedb:c dconfig:c dtoolconfig:m \
+    dtoolutil:c dtoolbase:c dtool:m
+
+  #define SOURCES \
+    indexedFaceSet.cxx indexedFaceSet.h \
+    vrmlAppearance.cxx vrmlAppearance.h \
+    vrmlToEggConverter.cxx vrmlToEggConverter.h
+
+  #define INSTALL_HEADERS \
+    indexedFaceSet.h \
+    vrmlAppearance.h \
+    vrmlToEggConverter.h
+
+#end ss_lib_target

+ 582 - 0
pandatool/src/vrmlegg/indexedFaceSet.cxx

@@ -0,0 +1,582 @@
+// Filename: indexedFaceSet.cxx
+// Created by:  drose (24Jun99)
+// 
+////////////////////////////////////////////////////////////////////
+// Copyright (C) 1992,93,94,95,96,97  Walt Disney Imagineering, Inc.
+// 
+// These  coded  instructions,  statements,  data   structures   and
+// computer  programs contain unpublished proprietary information of
+// Walt Disney Imagineering and are protected by  Federal  copyright
+// law.  They may  not be  disclosed to third  parties  or copied or
+// duplicated in any form, in whole or in part,  without  the  prior
+// written consent of Walt Disney Imagineering Inc.
+////////////////////////////////////////////////////////////////////
+
+#include "indexedFaceSet.h"
+#include "vrmlAppearance.h"
+#include "vrmlNodeType.h"
+#include "vrmlNode.h"
+#include "notify.h"
+
+#include "eggGroup.h"
+#include "eggVertex.h"
+#include "eggVertexPool.h"
+#include "eggPolygon.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: IndexedFaceSet::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+IndexedFaceSet::
+IndexedFaceSet(const VrmlNode *geometry, const VRMLAppearance &appearance) :
+  _geometry(geometry), _appearance(appearance)
+{
+  get_coord_values();
+  get_polys();
+  get_colors();
+  _has_normals = get_normals();
+  if (!_per_vertex_normals.empty()) {
+    assign_per_vertex_normals();
+  }
+  get_uvs();
+  if (!_per_vertex_uvs.empty()) {
+    assign_per_vertex_uvs();
+  }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: IndexedFaceSet::convert_to_egg
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void IndexedFaceSet::
+convert_to_egg(EggGroup *group, const LMatrix4d &net_transform) {
+  EggVertexPool *vpool = new EggVertexPool(group->get_name());
+  group->add_child(vpool);
+
+  make_polys(vpool, group, net_transform);
+  if (!_has_normals && _appearance._has_material) {
+    compute_normals(group);
+  }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: IndexedFaceSet::get_coord_values
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void IndexedFaceSet::
+get_coord_values() {
+  const VrmlNode *coord = _geometry->get_value("coord")._sfnode._p;
+
+  if (coord != NULL) {
+    const MFArray *point = coord->get_value("point")._mf;
+    MFArray::const_iterator ci;
+    for (ci = point->begin(); ci != point->end(); ++ci) {
+      const double *p = (*ci)._sfvec;
+      _coord_values.push_back(Vertexd(p[0], p[1], p[2]));
+    }
+  }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: IndexedFaceSet::get_polys
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void IndexedFaceSet::
+get_polys() {
+  const MFArray *coordIndex = _geometry->get_value("coordIndex")._mf;
+  VrmlPolygon poly;
+
+  MFArray::const_iterator ci;
+  for (ci = coordIndex->begin(); ci != coordIndex->end(); ++ci) {
+    if ((*ci)._sfint32 < 0) {
+      _polys.push_back(poly);
+      poly._verts.clear();
+    } else {
+      const Vertexd &p = _coord_values[(*ci)._sfint32];
+      VrmlVertex vert;
+      vert._index = (*ci)._sfint32;
+      vert._pos = p;
+      poly._verts.push_back(vert);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IndexedFaceSet::get_vrml_colors
+//       Access: Private
+//  Description: Builds up a vector of Colorf pointers corresponding
+//               to the VRML color node.
+////////////////////////////////////////////////////////////////////
+void IndexedFaceSet::
+get_vrml_colors(const VrmlNode *color_node, double transparency,
+		pvector<Colorf> &color_list) {
+  const MFArray *color = color_node->get_value("color")._mf;
+  MFArray::const_iterator ci;
+  for (ci = color->begin(); ci != color->end(); ++ci) {
+    const double *p = (*ci)._sfvec;
+    Colorf color(p[0], p[1], p[2], 1.0 - transparency);
+    color_list.push_back(color);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IndexedFaceSet::get_vrml_normals
+//       Access: Private
+//  Description: Builds up a vector of double array pointers corresponding
+//               to the VRML normal node.
+////////////////////////////////////////////////////////////////////
+void IndexedFaceSet::
+get_vrml_normals(const VrmlNode *normal_node, 
+		 pvector<Normald> &normal_list) {
+  const MFArray *point = normal_node->get_value("vector")._mf;
+  MFArray::const_iterator ci;
+  for (ci = point->begin(); ci != point->end(); ++ci) {
+    const double *p = (*ci)._sfvec;
+    Normald normal(p[0], p[1], p[2]);
+    normal_list.push_back(normal);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IndexedFaceSet::get_vrml_uvs
+//       Access: Private
+//  Description: Builds up a vector of double array pointers corresponding
+//               to the VRML texCoord node.
+////////////////////////////////////////////////////////////////////
+void IndexedFaceSet::
+get_vrml_uvs(const VrmlNode *texCoord_node, 
+	     pvector<TexCoordd> &uv_list) {
+  const MFArray *point = texCoord_node->get_value("point")._mf;
+  MFArray::const_iterator ci;
+  for (ci = point->begin(); ci != point->end(); ++ci) {
+    const double *p = (*ci)._sfvec;
+    TexCoordd uv(p[0], p[1]);
+    uv_list.push_back(uv);
+  }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: IndexedFaceSet::get_colors
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+bool IndexedFaceSet::
+get_colors() {
+  const VrmlNode *color = _geometry->get_value("color")._sfnode._p;
+  if (color != NULL) {
+    // Vertex or face colors.
+    pvector<Colorf> color_list;
+    get_vrml_colors(color, _appearance._transparency, color_list);
+    
+    bool colorPerVertex = _geometry->get_value("colorPerVertex")._sfbool;
+    MFArray *colorIndex = _geometry->get_value("colorIndex")._mf;
+    if (colorPerVertex) {
+      MFArray::const_iterator ci;
+      size_t pi = 0;
+      size_t pv = 0;
+      for (ci = colorIndex->begin(); ci != colorIndex->end(); ++ci) {
+	if ((*ci)._sfint32 < 0) {
+	  // End of poly.
+	  if (pv != _polys[pi]._verts.size()) {
+	    cerr << "Color indices don't match up!\n";
+	    return false;
+	  }
+	  pi++;
+	  pv = 0;
+	} else {
+	  if (pi >= _polys.size() || pv >= _polys[pi]._verts.size()) {
+	    cerr << "Color indices don't match up!\n";
+	    return false;
+	  }
+	  _polys[pi]._verts[pv]._attrib.set_color(color_list[(*ci)._sfint32]);
+	  pv++;
+	}
+      }
+      if (pi != _polys.size()) {
+	cerr << "Not enough color indices!\n";
+	return false;
+      }
+    } else {
+      if (!colorIndex->empty()) {
+	MFArray::const_iterator ci;
+	size_t pi = 0;
+	if (colorIndex->size() != _polys.size()) {
+	  cerr << "Wrong number of color indices!\n";
+	  return false;
+	}
+	for (ci = colorIndex->begin(); ci != colorIndex->end(); ++ci) {
+	  if ((*ci)._sfint32 < 0 || (*ci)._sfint32 >= (int)color_list.size()) {
+	    cerr << "Invalid color index!\n";
+	    return false;
+	  }
+	  _polys[pi]._attrib.set_color(color_list[(*ci)._sfint32]);
+	  pi++;
+	}
+      } else {
+	if (color_list.size() != _polys.size()) {
+	  cerr << "Wrong number of colors!\n";
+	  return false;
+	}
+	for (size_t pi = 0; pi < color_list.size(); pi++) {
+	  _polys[pi]._attrib.set_color(color_list[pi]);
+	}
+      }
+    }
+    return true;
+  }
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IndexedFaceSet::get_normals
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+bool IndexedFaceSet::
+get_normals() {
+  const VrmlNode *normal = _geometry->get_value("normal")._sfnode._p;
+  if (normal != NULL) {
+    // Vertex or face normals.
+    pvector<Normald> normal_list;
+    get_vrml_normals(normal, normal_list);
+    
+    bool normalPerVertex = _geometry->get_value("normalPerVertex")._sfbool;
+    MFArray *normalIndex = _geometry->get_value("normalIndex")._mf;
+    MFArray::const_iterator ci;
+
+    if (normalPerVertex &&
+	normal_list.size() == _polys.size() &&
+	normalIndex->empty()) {
+      // Here's an interesting formZ bug.  We end up with a VRML file
+      // that claims to have normals per vertex, yet there is no
+      // normal index list, and there are exactly enough normals in
+      // the list to indicate one normal per face.  Silly formZ.
+      normalPerVertex = false;
+    }
+
+    if (normalPerVertex) {
+
+      if (normalIndex->empty()) {
+	// If we have *no* normal index array, but we do have
+	// per-vertex normals, assume the VRML writer meant to imply a
+	// one-to-one mapping.  This works around a broken formZ VRML
+	// file writer.
+	for (size_t i = 0; i < normal_list.size(); i++) {
+	  VrmlFieldValue fv;
+	  fv._sfint32 = i;
+	  (*normalIndex).push_back(fv);
+	}
+      }
+
+      // It's possible that this .wrl file indexes normals directly
+      // into the vertex array, instead of into the polygon list.
+      // Check for this possibility.  This can only happen if the
+      // number of normal indices exactly matches the number of
+      // vertices, and none of the indices is -1.
+      bool linear_list = (normalIndex->size() == _coord_values.size());
+      for (ci = normalIndex->begin(); 
+	   ci != normalIndex->end() && linear_list; 
+	   ++ci) {
+	linear_list = ((*ci)._sfint32 >= 0);
+      }
+      
+      if (linear_list) {
+	// Ok, we do have such a list.  This .wrl file seems to store
+	// its texture coordinates one per vertex, instead of one per
+	// polygon vertex.
+	_per_vertex_normals.reserve(_coord_values.size());
+
+	for (ci = normalIndex->begin(); ci != normalIndex->end(); ++ci) {
+	  size_t vi = (*ci)._sfint32;
+	  nassertr(vi >= 0, false);
+	  if (vi >= normal_list.size()) {
+	    cerr << "Invalid normal index: " << vi << "\n";
+	    return false;
+	  }
+	  _per_vertex_normals.push_back(normal_list[vi]);
+	}
+	nassertr(_per_vertex_normals.size() == _coord_values.size(), false);
+	
+      } else {
+	// This is a "correct" .wrl file that stores its texture
+	// coordinates one per polygon vertex.  This allows a shared
+	// vertex to contain two different normal values in differing
+	// polygons (meaning it's not actually shared).
+	
+	MFArray::const_iterator ci;
+	size_t pi = 0;
+	size_t pv = 0;
+	for (ci = normalIndex->begin(); ci != normalIndex->end(); ++ci) {
+	  if ((*ci)._sfint32 < 0) {
+	    // End of poly.
+	    if (pv != _polys[pi]._verts.size()) {
+	      cerr << "Normal indices don't match up!\n";
+	      return false;
+	    }
+	    pi++;
+	    pv = 0;
+	  } else {
+	    if (pi >= _polys.size() || pv >= _polys[pi]._verts.size()) {
+	      cerr << "Normal indices don't match up!\n";
+	      return false;
+	    }
+	    const Normald &d = normal_list[(*ci)._sfint32];
+	    _polys[pi]._verts[pv]._attrib.set_normal(d);
+	    pv++;
+	  }
+	}
+	if (pi != _polys.size()) {
+	  cerr << "Not enough normal indices!\n";
+	  return false;
+	}
+      }
+    } else {
+      if (!normalIndex->empty()) {
+	size_t pi = 0;
+	if (normalIndex->size() != _polys.size()) {
+	  cerr << "Wrong number of normal indices!\n";
+	  return false;
+	}
+	for (ci = normalIndex->begin(); ci != normalIndex->end(); ++ci) {
+	  if ((*ci)._sfint32 < 0 || (*ci)._sfint32 >= (int)normal_list.size()) {
+	    cerr << "Invalid normal index!\n";
+	    return false;
+	  }
+	  const Normald &d = normal_list[(*ci)._sfint32];
+	  _polys[pi]._attrib.set_normal(d);
+	  pi++;
+	}
+      } else {
+	if (normal_list.size() != _polys.size()) {
+	  cerr << "Wrong number of normals!\n";
+	  return false;
+	}
+	for (size_t pi = 0; pi < normal_list.size(); pi++) {
+	  const Normald &d = normal_list[pi];
+	  _polys[pi]._attrib.set_normal(d);
+	}
+      }
+    }
+    return true;
+  }
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IndexedFaceSet::assign_per_vertex_normals
+//       Access: Private
+//  Description: Once the array of _per_vertex_normals has been filled
+//               (by a broken .wrl file that indexes the normal's
+//               directly into the vertex array instead of per polygon
+//               vertex), go back through the polygons and assign the
+//               normals by index number.
+////////////////////////////////////////////////////////////////////
+void IndexedFaceSet::
+assign_per_vertex_normals() {
+  for (size_t pi = 0; pi < _polys.size(); pi++) {
+    for (size_t pv = 0; pv < _polys[pi]._verts.size(); pv++) {
+      VrmlVertex &vv = _polys[pi]._verts[pv];
+      if (vv._index >= 0 && vv._index < (int)_per_vertex_normals.size()) {
+	const Normald &d = _per_vertex_normals[vv._index];
+	vv._attrib.set_normal(d);
+      }
+    }
+  }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: IndexedFaceSet::get_uvs
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+bool IndexedFaceSet::
+get_uvs() {
+  const VrmlNode *texCoord = _geometry->get_value("texCoord")._sfnode._p;
+  if (texCoord != NULL) {
+    // Vertex or face texCoords.
+    pvector<TexCoordd> uv_list;
+    get_vrml_uvs(texCoord, uv_list);
+    
+    MFArray *texCoordIndex = _geometry->get_value("texCoordIndex")._mf;
+    MFArray::const_iterator ci;
+
+    if (texCoordIndex->empty()) {
+      // If we have *no* texture coordinate index array, but we do
+      // have texture coordinates, assume the VRML writer meant to
+      // imply a one-to-one mapping.  This works around a broken formZ
+      // VRML file writer.
+      for (size_t i = 0; i < uv_list.size(); i++) {
+	VrmlFieldValue fv;
+	fv._sfint32 = i;
+	(*texCoordIndex).push_back(fv);
+      }
+    }
+
+    // It's possible that this .wrl file indexes texture coordinates
+    // directly into the vertex array, instead of into the polygon
+    // list.  Check for this possibility.  This can only happen if the
+    // number of texture coordinate indices exactly matches the number
+    // of vertices, and none of the indices is -1.
+    bool linear_list = (texCoordIndex->size() == _coord_values.size());
+    for (ci = texCoordIndex->begin(); 
+	 ci != texCoordIndex->end() && linear_list; 
+	 ++ci) {
+      linear_list = ((*ci)._sfint32 >= 0);
+    }
+
+    if (linear_list) {
+      // Ok, we do have such a list.  This .wrl file seems to store
+      // its texture coordinates one per vertex, instead of one per
+      // polygon vertex.
+      _per_vertex_uvs.reserve(_coord_values.size());
+
+      for (ci = texCoordIndex->begin(); ci != texCoordIndex->end(); ++ci) {
+	size_t vi = (*ci)._sfint32;
+	nassertr(vi >= 0, false);
+	if (vi >= uv_list.size()) {
+	  cerr << "Invalid texCoord index: " << vi << "\n";
+	  return false;
+	}
+	_per_vertex_uvs.push_back(uv_list[vi]);
+      }
+      nassertr(_per_vertex_uvs.size() == _coord_values.size(), false);
+
+    } else {
+      // This is a "correct" .wrl file that stores its texture
+      // coordinates one per polygon vertex.  This allows a shared
+      // vertex to contain two different texture coordinate values in
+      // differing polygons (meaning it's not actually shared).
+
+      size_t pi = 0;
+      size_t pv = 0;
+      for (ci = texCoordIndex->begin(); ci != texCoordIndex->end(); ++ci) {
+	if ((*ci)._sfint32 < 0) {
+	  // End of poly.
+	  if (pv != _polys[pi]._verts.size()) {
+	    cerr << "texCoord indices don't match up!\n";
+	    return false;
+	  }
+	  pi++;
+	  pv = 0;
+	} else {
+	  if (pi >= _polys.size() || pv >= _polys[pi]._verts.size()) {
+	    cerr << "texCoord indices don't match up!\n";
+	    return false;
+	  }
+	  _polys[pi]._verts[pv]._attrib.set_uv(uv_list[(*ci)._sfint32]);
+	  pv++;
+	}
+      }
+      if (pi != _polys.size()) {
+	cerr << "Not enough texCoord indices!\n";
+	return false;
+      }
+    }
+    return true;
+  }
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IndexedFaceSet::assign_per_vertex_uvs
+//       Access: Private
+//  Description: Once the array of _per_vertex_uvs has been filled (by
+//               a broken .wrl file that indexes the uv's directly
+//               into the vertex array instead of per polygon vertex),
+//               go back through the polygons and assign the UV's by
+//               index number.
+////////////////////////////////////////////////////////////////////
+void IndexedFaceSet::
+assign_per_vertex_uvs() {
+  for (size_t pi = 0; pi < _polys.size(); pi++) {
+    for (size_t pv = 0; pv < _polys[pi]._verts.size(); pv++) {
+      VrmlVertex &vv = _polys[pi]._verts[pv];
+      if (vv._index >= 0 && vv._index < (int)_per_vertex_uvs.size()) {
+	const TexCoordd &d = _per_vertex_uvs[vv._index];
+	vv._attrib.set_uv(d);
+      }
+    }
+  }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: IndexedFaceSet::make_polys
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void IndexedFaceSet::
+make_polys(EggVertexPool *vpool, EggGroup *group, 
+	   const LMatrix4d &net_transform) {
+  bool ccw = _geometry->get_value("ccw")._sfbool;
+  bool solid = _geometry->get_value("solid")._sfbool;
+
+  for (size_t pi = 0; pi < _polys.size(); pi++) {
+    EggPolygon *poly = new EggPolygon;
+    group->add_child(poly);
+    poly->copy_attributes(_polys[pi]._attrib);
+
+    if (!poly->has_color() && _appearance._has_material) {
+      poly->set_color(_appearance._color);
+    }
+
+    if (_appearance._tex != NULL) {
+      poly->set_texture(_appearance._tex);
+    }
+
+    if (!solid) {
+      poly->set_bface_flag(true);
+    }
+
+    if (ccw) {
+      // The vertices are counterclockwise, same as Egg.
+      for (int pv = 0; pv < (int)_polys[pi]._verts.size(); pv++) {
+	EggVertex vert(_polys[pi]._verts[pv]._attrib);
+	Vertexd pos = 
+	  _polys[pi]._verts[pv]._pos * net_transform;
+	vert.set_pos(pos);
+	
+	poly->add_vertex(vpool->create_unique_vertex(vert));
+      }
+    } else {
+      // The vertices are clockwise, so add 'em in reverse order.
+      for (int pv = (int)_polys[pi]._verts.size() - 1; pv >= 0; pv--) {
+	EggVertex vert(_polys[pi]._verts[pv]._attrib);
+	Vertexd pos = 
+	  _polys[pi]._verts[pv]._pos * net_transform;
+	vert.set_pos(pos);
+	
+	poly->add_vertex(vpool->create_unique_vertex(vert));
+      }
+    }
+  }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: IndexedFaceSet::compute_normals
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void IndexedFaceSet::
+compute_normals(EggGroup *group) {
+  const VrmlNode *normal = _geometry->get_value("normal")._sfnode._p;
+  if (normal == NULL) {
+    // Compute normals.
+    double creaseAngle = _geometry->get_value("creaseAngle")._sffloat;
+    if (creaseAngle == 0.0) {
+      group->recompute_polygon_normals();
+    } else {
+      group->recompute_vertex_normals(rad_2_deg(creaseAngle));
+    }
+  }
+}

+ 84 - 0
pandatool/src/vrmlegg/indexedFaceSet.h

@@ -0,0 +1,84 @@
+// Filename: indexedFaceSet.h
+// Created by:  drose (24Jun99)
+// 
+////////////////////////////////////////////////////////////////////
+// Copyright (C) 1992,93,94,95,96,97  Walt Disney Imagineering, Inc.
+// 
+// These  coded  instructions,  statements,  data   structures   and
+// computer  programs contain unpublished proprietary information of
+// Walt Disney Imagineering and are protected by  Federal  copyright
+// law.  They may  not be  disclosed to third  parties  or copied or
+// duplicated in any form, in whole or in part,  without  the  prior
+// written consent of Walt Disney Imagineering Inc.
+////////////////////////////////////////////////////////////////////
+
+#ifndef INDEXEDFACESET_H
+#define INDEXEDFACESET_H
+
+#include "pandatoolbase.h"
+#include "pvector.h"
+#include "pset.h"
+#include "eggPolygon.h"
+#include "eggVertex.h"
+#include "eggAttributes.h"
+
+class VrmlNode;
+class EggData;
+class EggGroup;
+class EggVertexPool;
+class VRMLAppearance;
+class LMatrix4d;
+
+////////////////////////////////////////////////////////////////////
+//       Class : IndexedFaceSet
+// Description : Decodes the vertices and faces in a VRML indexed face
+//               set, and creates the corresponding egg geometry.
+////////////////////////////////////////////////////////////////////
+class IndexedFaceSet {
+public:
+  IndexedFaceSet(const VrmlNode *geometry, const VRMLAppearance &appearance);
+
+  void convert_to_egg(EggGroup *group, const LMatrix4d &net_transform);
+
+private:
+  void get_coord_values();
+  void get_polys();
+  void get_vrml_colors(const VrmlNode *color_node, double transparency,
+		       pvector<Colorf> &color_list);
+  void get_vrml_normals(const VrmlNode *normal_node, 
+			pvector<Normald> &normal_list);
+  void get_vrml_uvs(const VrmlNode *texCoord_node, 
+		    pvector<TexCoordd> &uv_list);
+
+  bool get_colors();
+  bool get_normals();
+  void assign_per_vertex_normals();
+  bool get_uvs();
+  void assign_per_vertex_uvs();
+  void make_polys(EggVertexPool *vpool, EggGroup *group,
+		  const LMatrix4d &net_transform);
+  void compute_normals(EggGroup *group);
+
+  class VrmlVertex {
+  public:
+    int _index;
+    Vertexd _pos;
+    EggVertex _attrib;
+  };
+  class VrmlPolygon {
+  public:
+    EggPolygon _attrib;
+    pvector<VrmlVertex> _verts;
+  };
+  pvector<Vertexd> _coord_values;
+  pvector<VrmlPolygon> _polys;
+  pvector<TexCoordd> _per_vertex_uvs;
+  pvector<Normald> _per_vertex_normals;
+
+  bool _has_normals;
+
+  const VrmlNode *_geometry;
+  const VRMLAppearance &_appearance;
+};
+
+#endif

+ 46 - 0
pandatool/src/vrmlegg/vrmlAppearance.cxx

@@ -0,0 +1,46 @@
+// Filename: vrmlAppearance.cxx
+// Created by:  drose (24Jun99)
+// 
+////////////////////////////////////////////////////////////////////
+// Copyright (C) 1992,93,94,95,96,97  Walt Disney Imagineering, Inc.
+// 
+// These  coded  instructions,  statements,  data   structures   and
+// computer  programs contain unpublished proprietary information of
+// Walt Disney Imagineering and are protected by  Federal  copyright
+// law.  They may  not be  disclosed to third  parties  or copied or
+// duplicated in any form, in whole or in part,  without  the  prior
+// written consent of Walt Disney Imagineering Inc.
+////////////////////////////////////////////////////////////////////
+
+#include "vrmlAppearance.h"
+#include "vrmlNode.h"
+
+VRMLAppearance::
+VRMLAppearance(const VrmlNode *appearance) {
+  _has_material = false;
+  _transparency = 0.0;
+  _color.set(1.0f, 1.0f, 1.0f, 1.0f);
+
+  if (appearance != NULL) {
+    const VrmlNode *material = appearance->get_value("material")._sfnode._p;
+    if (material != NULL) {
+      _has_material = true;
+      const double *c = material->get_value("diffuseColor")._sfvec;
+      _transparency = material->get_value("transparency")._sffloat;
+      _color.set(c[0], c[1], c[2], 1.0 - _transparency);
+    }
+
+    const VrmlNode *texture = appearance->get_value("texture")._sfnode._p;
+    if (texture != NULL) {
+      if (strcmp(texture->_type->getName(), "ImageTexture") == 0) {
+	MFArray *url = texture->get_value("url")._mf;
+	if (!url->empty()) {
+	  const char *filename = (*url->begin())._sfstring;
+	  _tex = new EggTexture("tref", filename);
+	}
+      }
+    }
+  }
+}
+
+  

+ 34 - 0
pandatool/src/vrmlegg/vrmlAppearance.h

@@ -0,0 +1,34 @@
+// Filename: vrmlAppearance.h
+// Created by:  drose (24Jun99)
+// 
+////////////////////////////////////////////////////////////////////
+// Copyright (C) 1992,93,94,95,96,97  Walt Disney Imagineering, Inc.
+// 
+// These  coded  instructions,  statements,  data   structures   and
+// computer  programs contain unpublished proprietary information of
+// Walt Disney Imagineering and are protected by  Federal  copyright
+// law.  They may  not be  disclosed to third  parties  or copied or
+// duplicated in any form, in whole or in part,  without  the  prior
+// written consent of Walt Disney Imagineering Inc.
+////////////////////////////////////////////////////////////////////
+
+#ifndef VRMLAPPEARANCE_H
+#define VRMLAPPEARANCE_H
+
+#include "pandatoolbase.h"
+#include "eggTexture.h"
+#include "pt_EggTexture.h"
+
+class VrmlNode;
+
+class VRMLAppearance {
+public:
+  VRMLAppearance(const VrmlNode *vrmlAppearance);
+
+  bool _has_material;
+  Colorf _color;
+  double _transparency;
+  PT_EggTexture _tex;
+};
+
+#endif

+ 411 - 0
pandatool/src/vrmlegg/vrmlToEggConverter.cxx

@@ -0,0 +1,411 @@
+// Filename: vrmlToEggConverter.cxx
+// Created by:  drose (01Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "vrmlToEggConverter.h"
+#include "vrmlAppearance.h"
+#include "indexedFaceSet.h"
+#include "vrmlNodeType.h"
+#include "parse_vrml.h"
+#include "vrmlParser.h"
+#include "eggGroupNode.h"
+#include "eggGroup.h"
+#include "eggData.h"
+#include "deg_2_rad.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: VRMLToEggConverter::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+VRMLToEggConverter::
+VRMLToEggConverter() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VRMLToEggConverter::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+VRMLToEggConverter::
+VRMLToEggConverter(const VRMLToEggConverter &copy) :
+  SomethingToEggConverter(copy)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VRMLToEggConverter::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+VRMLToEggConverter::
+~VRMLToEggConverter() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VRMLToEggConverter::make_copy
+//       Access: Public, Virtual
+//  Description: Allocates and returns a new copy of the converter.
+////////////////////////////////////////////////////////////////////
+SomethingToEggConverter *VRMLToEggConverter::
+make_copy() {
+  return new VRMLToEggConverter(*this);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: VRMLToEggConverter::get_name
+//       Access: Public, Virtual
+//  Description: Returns the English name of the file type this
+//               converter supports.
+////////////////////////////////////////////////////////////////////
+string VRMLToEggConverter::
+get_name() const {
+  return "VRML";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VRMLToEggConverter::get_extension
+//       Access: Public, Virtual
+//  Description: Returns the common extension of the file type this
+//               converter supports.
+////////////////////////////////////////////////////////////////////
+string VRMLToEggConverter::
+get_extension() const {
+  return "wrl";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VRMLToEggConverter::convert_file
+//       Access: Public, Virtual
+//  Description: Handles the reading of the input file and converting
+//               it to egg.  Returns true if successful, false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+bool VRMLToEggConverter::
+convert_file(const Filename &filename) {
+  VrmlScene *scene = parse_vrml(filename);
+  if (scene == (VrmlScene *)NULL) {
+    return false;
+  }
+
+  if (_egg_data->get_coordinate_system() == CS_default) {
+    _egg_data->set_coordinate_system(CS_yup_right);
+  }
+
+  // First, resolve all the DEF/USE references, and count the number
+  // of times each node is USEd.
+  Nodes nodes;
+  VrmlScene::iterator si;
+  for (si = scene->begin(); si != scene->end(); ++si) {
+    get_all_defs((*si)._node, nodes);
+  }
+
+  // Now go through the hierarchy again, and this time actually
+  // build the egg structure.
+  VrmlScene::const_iterator csi;
+  for (csi = scene->begin(); csi != scene->end(); ++csi) {
+    vrml_node((*csi)._node, &get_egg_data(), LMatrix4d::ident_mat());
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VRMLToEggConverter::get_all_defs
+//       Access: Private
+//  Description: Makes a first pass through the VRML hierarchy,
+//               identifying all nodes marked with a DEF code, and
+//               also counting the times each one is referenced by
+//               USE.  Later, we'll need this information: if a node
+//               is referenced at least once, we need to define it as
+//               an instance node.
+////////////////////////////////////////////////////////////////////
+void VRMLToEggConverter::
+get_all_defs(SFNodeRef &vrml, VRMLToEggConverter::Nodes &nodes) {
+  Nodes::iterator ni;
+  
+  switch (vrml._type) {
+  case SFNodeRef::T_def:
+    // If this is a node definition, add it to the map.
+    nassertv(vrml._name != NULL);
+    nassertv(vrml._p != NULL);
+    /*
+      This happens too often to bother yelling about it.
+    ni = nodes.find(vrml._name);
+    if (ni != nodes.end()) {
+      cerr << "Warning: node name " << vrml._name 
+	   << " appears multiple times.\n";
+    }
+    */
+    nodes[vrml._name] = vrml._p;
+    break;
+
+  case SFNodeRef::T_use:
+    // If it's a reference, resolve it.
+    nassertv(vrml._name != NULL);
+    ni = nodes.find(vrml._name);
+    if (ni == nodes.end()) {
+      cerr << "Unknown node reference: " << vrml._name << "\n";
+    } else {
+      // Increment the use count of the node.
+      (*ni).second->_use_count++;
+
+      // Store the pointer itself in the reference, so we don't have
+      // to do this again later.
+      vrml._p = (*ni).second;
+    }
+    return;
+  }
+
+  VrmlNode *node = vrml._p;
+  if (node != NULL) {
+    VrmlNode::Fields::iterator fi;
+    for (fi = node->_fields.begin(); fi != node->_fields.end(); ++fi) {
+      if ((*fi)._type->type == SFNODE) {
+	get_all_defs((*fi)._value._sfnode, nodes);
+      } else if ((*fi)._type->type == MFNODE) {
+	MFArray *children = (*fi)._value._mf;
+	MFArray::iterator ci;
+	for (ci = children->begin(); ci != children->end(); ++ci) {
+	  get_all_defs((*ci)._sfnode, nodes);
+	}
+      }
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VRMLToEggConverter::vrml_node
+//       Access: Public
+//  Description: Processes a single VRML node, converting it to egg
+//               and adding it to the egg file, if appropriate, or
+//               doing whatever else should be done.
+////////////////////////////////////////////////////////////////////
+void VRMLToEggConverter::
+vrml_node(const SFNodeRef &vrml, EggGroupNode *egg, 
+	  const LMatrix4d &net_transform) {
+  const VrmlNode *node = vrml._p;
+  if (node != NULL) {
+    // Now add it to the egg file at this point.
+    if (strcmp(node->_type->getName(), "Group") == 0) {
+      vrml_grouping_node(vrml, egg, net_transform, 
+                         &VRMLToEggConverter::vrml_group);
+    } else if (strcmp(node->_type->getName(), "Transform") == 0) {
+      vrml_grouping_node(vrml, egg, net_transform, 
+                         &VRMLToEggConverter::vrml_transform);
+    } else if (strcmp(node->_type->getName(), "Shape") == 0) {
+      vrml_grouping_node(vrml, egg, net_transform, 
+                         &VRMLToEggConverter::vrml_shape);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VRMLToEggConverter::vrml_grouping_node
+//       Access: Public
+//  Description: Begins initial processing of a grouping-type node;
+//               that is, any node (like Group, Transform, or Shape)
+//               that maps to a <Group> or <Instance> in egg.  This
+//               create the group and does any instance-munging
+//               necessary, then calls the indicated method with the
+//               new parameters.
+////////////////////////////////////////////////////////////////////
+void VRMLToEggConverter::
+vrml_grouping_node(const SFNodeRef &vrml, EggGroupNode *egg,
+		   const LMatrix4d &net_transform,
+		   void (VRMLToEggConverter::*process_func)
+		   (const VrmlNode *node, EggGroup *group,
+		    const LMatrix4d &net_transform)) {
+  const VrmlNode *node = vrml._p;
+  nassertv(node != NULL);
+  string name;
+  if (vrml._name != NULL) {
+    name = vrml._name;
+  }
+
+  /*
+    The following code fragment was used in the old DWD-style egg
+    library.  Currently, the Panda egg library doesn't support
+    instance references, so we deal with VRML instances by copying.
+
+  if (vrml._type == SFNodeRef::T_use) {
+    // If this is an instancing reference, just add the reference and
+    // return; no need for further processing on the node.
+    Instances::const_iterator fi = _instances.find(node);
+    assert(fi != _instances.end());
+    EggInstance *inst = _data.CreateInstance(egg);
+    inst->AddGroupRef((*fi).second);
+    return;
+  }
+    */
+
+  PT(EggGroup) group = new EggGroup(name);
+  egg->add_child(group);
+
+  LMatrix4d next_transform = net_transform;
+
+  if (node->_use_count > 0) {
+    // If this node is referenced one or more times later in the file,
+    // we must make it an instance node.
+    group->set_group_type(EggGroup::GT_instance);
+    next_transform = LMatrix4d::ident_mat();
+
+    // And define the instance for future references.
+    //    _instances[node] = group;
+  }
+
+  (this->*process_func)(node, group, next_transform);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: VRMLToEggConverter::vrml_group
+//       Access: Public
+//  Description: Creates an Egg group corresponding to the VRML group.
+////////////////////////////////////////////////////////////////////
+void VRMLToEggConverter::
+vrml_group(const VrmlNode *node, EggGroup *group,
+	   const LMatrix4d &net_transform) {
+  const MFArray *children = node->get_value("children")._mf;
+  MFArray::const_iterator ci;
+  for (ci = children->begin(); ci != children->end(); ++ci) {
+    vrml_node((*ci)._sfnode, group, net_transform);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VRMLToEggConverter::vrml_transform
+//       Access: Public
+//  Description: Creates an Egg group with a transform corresponding
+//               to the VRML group.
+////////////////////////////////////////////////////////////////////
+void VRMLToEggConverter::
+vrml_transform(const VrmlNode *node, EggGroup *group,
+	       const LMatrix4d &net_transform) {
+  const double *scale = node->get_value("scale")._sfvec;
+  const double *rotation = node->get_value("rotation")._sfvec;
+  const double *translation = node->get_value("translation")._sfvec;
+
+  const double *center = node->get_value("center")._sfvec;
+  const double *o = node->get_value("scaleOrientation")._sfvec;
+
+  LMatrix4d local_transform = LMatrix4d::ident_mat();
+
+  bool any_transform = false;
+
+  if (scale[0] != 1.0 || scale[1] != 1.0 || scale[2] != 1.0) {
+    any_transform = true;
+    if (center[0] != 0.0 || center[1] != 0.0 || center[2] != 0.0) {
+      local_transform *=
+        LMatrix4d::translate_mat(-center[0], -center[1], -center[2]);
+
+      if (o[3] != 0.0) {
+	local_transform *= 
+          LMatrix4d::rotate_mat(rad_2_deg(-o[3]), LVector3d(o[0], o[1], o[2]));
+	local_transform *=
+          LMatrix4d::scale_mat(scale[0], scale[1], scale[2]);
+	local_transform *= 
+          LMatrix4d::rotate_mat(rad_2_deg(o[3]), LVector3d(o[0], o[1], o[2]));
+
+      } else {
+	local_transform *=
+          LMatrix4d::scale_mat(scale[0], scale[1], scale[2]);
+      }
+      local_transform *= 
+        LMatrix4d::translate_mat(center[0], center[1], center[2]);
+
+    } else {
+      if (o[3] != 0.0) {
+	local_transform *= 
+          LMatrix4d::rotate_mat(rad_2_deg(-o[3]), LVector3d(o[0], o[1], o[2]));
+	local_transform *=
+          LMatrix4d::scale_mat(scale[0], scale[1], scale[2]);
+	local_transform *= 
+          LMatrix4d::rotate_mat(rad_2_deg(o[3]), LVector3d(o[0], o[1], o[2]));
+
+      } else {
+	local_transform *=
+          LMatrix4d::scale_mat(scale[0], scale[1], scale[2]);
+      }
+    }      
+  }
+
+  if (rotation[3] != 0.0) {
+    any_transform = true;
+    if (center[0] != 0.0 || center[1] != 0.0 || center[2] != 0.0) {
+      local_transform *= 
+        LMatrix4d::translate_mat(-center[0], -center[1], -center[2]);
+      local_transform *= 
+        LMatrix4d::rotate_mat(rad_2_deg(rotation[3]),
+			      LVector3d(rotation[0], rotation[1], rotation[2]));
+      local_transform *=
+        LMatrix4d::translate_mat(center[0], center[1], center[2]);
+
+    } else {
+      local_transform *=
+        LMatrix4d::rotate_mat(rad_2_deg(rotation[3]),
+			      LVector3d(rotation[0], rotation[1], rotation[2]));
+    }
+  }
+
+  if (translation[0] != 0.0 ||
+      translation[1] != 0.0 ||
+      translation[2] != 0.0) {
+    any_transform = true;
+    local_transform *=
+      LMatrix4d::translate_mat(translation[0], translation[1], translation[2]);
+  }
+
+  if (any_transform) {
+    group->set_transform(local_transform);
+  }
+
+  LMatrix4d next_transform = local_transform * net_transform;
+
+  const MFArray *children = node->get_value("children")._mf;
+  MFArray::const_iterator ci;
+  for (ci = children->begin(); ci != children->end(); ++ci) {
+    vrml_node((*ci)._sfnode, group, next_transform);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VRMLToEggConverter::vrml_shape
+//       Access: Public
+//  Description: Creates an Egg group corresponding a VRML shape.
+//               This will probably contain a vertex pool and a number
+//               of polygons.
+////////////////////////////////////////////////////////////////////
+void VRMLToEggConverter::
+vrml_shape(const VrmlNode *node, EggGroup *group,
+	   const LMatrix4d &net_transform) {
+  const VrmlNode *geometry = node->get_value("geometry")._sfnode._p;
+
+  double transparency = 0.0;
+
+  if (geometry != NULL) {
+    VRMLAppearance appearance(node->get_value("appearance")._sfnode._p);
+
+    if (strcmp(geometry->_type->getName(), "IndexedFaceSet") == 0) {
+      IndexedFaceSet ifs(geometry, appearance);
+      ifs.convert_to_egg(group, net_transform);
+    } else {
+      cerr << "Ignoring " << geometry->_type->getName() << "\n";
+    }
+  }
+}

+ 73 - 0
pandatool/src/vrmlegg/vrmlToEggConverter.h

@@ -0,0 +1,73 @@
+// Filename: vrmlToEggConverter.h
+// Created by:  drose (01Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef VRMLTOEGGCONVERTER_H
+#define VRMLTOEGGCONVERTER_H
+
+#include "pandatoolbase.h"
+
+#include "somethingToEggConverter.h"
+#include "pmap.h"
+
+class VrmlNode;
+struct SFNodeRef;
+class EggGroupNode;
+class EggGroup;
+class LMatrix4d;
+
+////////////////////////////////////////////////////////////////////
+//       Class : VRMLToEggConverter
+// Description : This class supervises the construction of an EggData
+//               structure from a VRML file.
+////////////////////////////////////////////////////////////////////
+class VRMLToEggConverter : public SomethingToEggConverter {
+public:
+  VRMLToEggConverter();
+  VRMLToEggConverter(const VRMLToEggConverter &copy);
+  ~VRMLToEggConverter();
+
+  virtual SomethingToEggConverter *make_copy();
+
+  virtual string get_name() const;
+  virtual string get_extension() const;
+
+  virtual bool convert_file(const Filename &filename);
+
+private:
+  typedef pmap<string, VrmlNode *> Nodes;
+
+  void get_all_defs(SFNodeRef &vrml, Nodes &nodes);
+  void vrml_node(const SFNodeRef &vrml, EggGroupNode *egg, 
+                 const LMatrix4d &net_transform);
+
+  void vrml_grouping_node(const SFNodeRef &vrml, EggGroupNode *egg,
+                          const LMatrix4d &net_transform,
+                          void (VRMLToEggConverter::*process_func)
+                          (const VrmlNode *node, EggGroup *group,
+                           const LMatrix4d &net_transform));
+  void vrml_group(const VrmlNode *node, EggGroup *group,
+                  const LMatrix4d &net_transform);
+  void vrml_transform(const VrmlNode *node, EggGroup *group,
+                      const LMatrix4d &net_transform);
+  void vrml_shape(const VrmlNode *node, EggGroup *group,
+                  const LMatrix4d &net_transform);
+};
+
+#endif
+
+

+ 28 - 0
pandatool/src/vrmlprogs/Sources.pp

@@ -0,0 +1,28 @@
+#begin bin_target
+  #define TARGET vrml2egg
+  #define LOCAL_LIBS pvrml vrmlegg eggbase progbase
+
+  #define OTHER_LIBS \
+    egg:c pandaegg:m \
+    linmath:c pnmimagetypes:c pnmimage:c putil:c mathutil:c event:c panda:m \
+    express:c pandaexpress:m \
+    dtoolutil:c dtoolbase:c dconfig:c dtoolconfig:m dtool:m pystub
+
+  #define SOURCES \
+    vrmlToEgg.cxx vrmlToEgg.h
+
+#end bin_target
+
+#begin bin_target
+  #define TARGET vrml-trans
+  #define LOCAL_LIBS \
+    progbase pvrml
+  #define OTHER_LIBS \
+    linmath:c panda:m \
+    express:c pandaexpress:m \
+    dtoolutil:c dtoolbase:c dconfig:c dtoolconfig:m dtool:m pystub
+
+  #define SOURCES \
+    vrmlTrans.cxx vrmlTrans.h
+
+#end bin_target

+ 80 - 0
pandatool/src/vrmlprogs/vrmlToEgg.cxx

@@ -0,0 +1,80 @@
+// Filename: vrmlToEgg.cxx
+// Created by:  drose (01Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "vrmlToEgg.h"
+
+#include "vrmlToEggConverter.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: VRMLToEgg::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+VRMLToEgg::
+VRMLToEgg() :
+  SomethingToEgg("VRML", ".wrl")
+{
+  add_units_options();
+  add_normals_options();
+  add_transform_options();
+
+  set_program_description
+    ("This program converts VRML 2.0 model files to egg.  Animated files, "
+     "and VRML 1.0 files, are not supported.");
+
+  redescribe_option
+    ("cs",
+     "Specify the coordinate system of the input " + _format_name +
+     " file.  Normally, this is y-up.");
+
+  _coordinate_system = CS_yup_right;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VRMLToEgg::run
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+void VRMLToEgg::
+run() {
+  nout << "Reading " << _input_filename << "\n";
+
+  _data.set_coordinate_system(_coordinate_system);
+
+  VRMLToEggConverter converter;
+  converter.set_egg_data(&_data, false);
+  converter._allow_errors = _allow_errors;
+
+  apply_parameters(converter);
+
+  if (!converter.convert_file(_input_filename)) {
+    nout << "Errors in conversion.\n";
+    exit(1);
+  }
+
+  write_egg_file();
+  nout << "\n";
+}
+
+
+int main(int argc, char *argv[]) {
+  VRMLToEgg prog;
+  prog.parse_command_line(argc, argv);
+  prog.run();
+  return 0;
+}

+ 41 - 0
pandatool/src/vrmlprogs/vrmlToEgg.h

@@ -0,0 +1,41 @@
+// Filename: vrmlToEgg.h
+// Created by:  drose (01Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+ 
+#ifndef VRMLTOEGG_H
+#define VRMLTOEGG_H
+
+#include "pandatoolbase.h"
+
+#include "somethingToEgg.h"
+#include "vrmlToEggConverter.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : VRMLToEgg
+// Description : A program to read a VRML file and generate an egg
+//               file.
+////////////////////////////////////////////////////////////////////
+class VRMLToEgg : public SomethingToEgg {
+public:
+  VRMLToEgg();
+
+  void run();
+};
+
+#endif
+
+

+ 104 - 0
pandatool/src/vrmlprogs/vrmlTrans.cxx

@@ -0,0 +1,104 @@
+// Filename: vrmlTrans.cxx
+// Created by:  drose (01Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "vrmlTrans.h"
+#include "parse_vrml.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: VRMLTrans::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+VRMLTrans::
+VRMLTrans() :
+  WithOutputFile(true, true, false)
+{
+  // Indicate the extension name we expect the user to supply for
+  // output files.
+  _preferred_extension = ".wrl";
+
+  set_program_description
+    ("This program reads a VRML 2.0 file (.wrl) and writes an "
+     "essentially equivalent .wrl file.  It is primarily useful for "
+     "debugging the VRML parser that is part of the Pandatool library.");
+
+  clear_runlines();
+  add_runline("[opts] input.wrl > output.wrl");
+  add_runline("[opts] input.wrl output.wrl");
+  add_runline("[opts] -o output.wrl input.wrl");
+
+  add_option
+    ("o", "filename", 0,
+     "Specify the filename to which the resulting .wrl file will be written.  "
+     "If this option is omitted, the last parameter name is taken to be the "
+     "name of the output file.",
+     &VRMLTrans::dispatch_filename, &_got_output_filename, &_output_filename);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: VRMLTrans::run
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+void VRMLTrans::
+run() {
+  nout << "Reading " << _input_filename << "\n";
+
+  VrmlScene *scene = parse_vrml(_input_filename);
+  if (scene == (VrmlScene *)NULL) {
+    nout << "Unable to read.\n";
+    exit(1);
+  }
+
+  get_output() << *scene << "\n";
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: VRMLTrans::handle_args
+//       Access: Protected, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+bool VRMLTrans::
+handle_args(ProgramBase::Args &args) {
+  if (!check_last_arg(args, 1)) {
+    return false;
+  }
+
+  if (args.empty()) {
+    nout << "You must specify the .wrl file to read on the command line.\n";
+    return false;
+
+  } else if (args.size() != 1) {
+    nout << "You must specify only one .wrl file to read on the command line.\n";
+    return false;
+  }
+
+  _input_filename = args[0];
+
+  return true;
+}
+
+
+int main(int argc, char *argv[]) {
+  VRMLTrans prog;
+  prog.parse_command_line(argc, argv);
+  prog.run();
+  return 0;
+}

+ 46 - 0
pandatool/src/vrmlprogs/vrmlTrans.h

@@ -0,0 +1,46 @@
+// Filename: vrmlTrans.h
+// Created by:  drose (01Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef VRMLTRANS_H
+#define VRMLTRANS_H
+
+#include "pandatoolbase.h"
+
+#include "programBase.h"
+#include "withOutputFile.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : VRMLTrans
+// Description : A program to read a VRML file and output an
+//               essentially similar VRML file.  This is mainly useful
+//               to test the VRML parser used in Panda.
+////////////////////////////////////////////////////////////////////
+class VRMLTrans : public ProgramBase, public WithOutputFile {
+public:
+  VRMLTrans();
+
+  void run();
+
+protected:
+  virtual bool handle_args(Args &args);
+
+  Filename _input_filename;
+};
+
+#endif
+