From c5dc6f45c7a563f21e4c1a90d7ca2cdb083788c2 Mon Sep 17 00:00:00 2001 From: David Rose Date: Fri, 1 Oct 2004 23:20:09 +0000 Subject: [PATCH] port vrml2egg from DWDTOOL --- pandatool/src/dxfegg/dxfToEggConverter.cxx | 4 + pandatool/src/ptloader/Sources.pp | 2 +- pandatool/src/ptloader/config_ptloader.cxx | 4 + pandatool/src/vrml/Sources.pp | 21 + pandatool/src/vrml/parse_vrml.cxx | 142 ++ pandatool/src/vrml/parse_vrml.h | 24 + pandatool/src/vrml/standardNodes.wrl | 488 +++++++ pandatool/src/vrml/standardNodes.wrl.c | 1340 ++++++++++++++++++ pandatool/src/vrml/standardNodes.wrl.pz.c | 271 ++++ pandatool/src/vrml/standard_nodes.cxx | 52 + pandatool/src/vrml/standard_nodes.h | 32 + pandatool/src/vrml/vrml2egg.cxx | 436 ++++++ pandatool/src/vrml/vrml2egg.h | 78 + pandatool/src/vrml/vrmlLexer.lxx | 574 ++++++++ pandatool/src/vrml/vrmlLexerDefs.h | 33 + pandatool/src/vrml/vrmlNode.cxx | 81 ++ pandatool/src/vrml/vrmlNode.h | 71 + pandatool/src/vrml/vrmlNodeType.cxx | 333 +++++ pandatool/src/vrml/vrmlNodeType.h | 108 ++ pandatool/src/vrml/vrmlParser.yxx | 570 ++++++++ pandatool/src/vrml/vrmlParserDefs.h | 28 + pandatool/src/vrmlegg/Sources.pp | 20 + pandatool/src/vrmlegg/indexedFaceSet.cxx | 582 ++++++++ pandatool/src/vrmlegg/indexedFaceSet.h | 84 ++ pandatool/src/vrmlegg/vrmlAppearance.cxx | 46 + pandatool/src/vrmlegg/vrmlAppearance.h | 34 + pandatool/src/vrmlegg/vrmlToEggConverter.cxx | 411 ++++++ pandatool/src/vrmlegg/vrmlToEggConverter.h | 73 + pandatool/src/vrmlprogs/Sources.pp | 28 + pandatool/src/vrmlprogs/vrmlToEgg.cxx | 80 ++ pandatool/src/vrmlprogs/vrmlToEgg.h | 41 + pandatool/src/vrmlprogs/vrmlTrans.cxx | 104 ++ pandatool/src/vrmlprogs/vrmlTrans.h | 46 + 33 files changed, 6240 insertions(+), 1 deletion(-) create mode 100644 pandatool/src/vrml/Sources.pp create mode 100644 pandatool/src/vrml/parse_vrml.cxx create mode 100644 pandatool/src/vrml/parse_vrml.h create mode 100644 pandatool/src/vrml/standardNodes.wrl create mode 100644 pandatool/src/vrml/standardNodes.wrl.c create mode 100644 pandatool/src/vrml/standardNodes.wrl.pz.c create mode 100644 pandatool/src/vrml/standard_nodes.cxx create mode 100644 pandatool/src/vrml/standard_nodes.h create mode 100644 pandatool/src/vrml/vrml2egg.cxx create mode 100644 pandatool/src/vrml/vrml2egg.h create mode 100644 pandatool/src/vrml/vrmlLexer.lxx create mode 100644 pandatool/src/vrml/vrmlLexerDefs.h create mode 100644 pandatool/src/vrml/vrmlNode.cxx create mode 100644 pandatool/src/vrml/vrmlNode.h create mode 100644 pandatool/src/vrml/vrmlNodeType.cxx create mode 100644 pandatool/src/vrml/vrmlNodeType.h create mode 100644 pandatool/src/vrml/vrmlParser.yxx create mode 100644 pandatool/src/vrml/vrmlParserDefs.h create mode 100644 pandatool/src/vrmlegg/Sources.pp create mode 100644 pandatool/src/vrmlegg/indexedFaceSet.cxx create mode 100644 pandatool/src/vrmlegg/indexedFaceSet.h create mode 100644 pandatool/src/vrmlegg/vrmlAppearance.cxx create mode 100644 pandatool/src/vrmlegg/vrmlAppearance.h create mode 100644 pandatool/src/vrmlegg/vrmlToEggConverter.cxx create mode 100644 pandatool/src/vrmlegg/vrmlToEggConverter.h create mode 100644 pandatool/src/vrmlprogs/Sources.pp create mode 100644 pandatool/src/vrmlprogs/vrmlToEgg.cxx create mode 100644 pandatool/src/vrmlprogs/vrmlToEgg.h create mode 100644 pandatool/src/vrmlprogs/vrmlTrans.cxx create mode 100644 pandatool/src/vrmlprogs/vrmlTrans.h diff --git a/pandatool/src/dxfegg/dxfToEggConverter.cxx b/pandatool/src/dxfegg/dxfToEggConverter.cxx index 11b7ed572d..62266837ad 100644 --- a/pandatool/src/dxfegg/dxfToEggConverter.cxx +++ b/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; } diff --git a/pandatool/src/ptloader/Sources.pp b/pandatool/src/ptloader/Sources.pp index 40e8e8ad60..29e783da76 100644 --- a/pandatool/src/ptloader/Sources.pp +++ b/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 \ diff --git a/pandatool/src/ptloader/config_ptloader.cxx b/pandatool/src/ptloader/config_ptloader.cxx index cc037d684c..da2079a08e 100644 --- a/pandatool/src/ptloader/config_ptloader.cxx +++ b/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(); diff --git a/pandatool/src/vrml/Sources.pp b/pandatool/src/vrml/Sources.pp new file mode 100644 index 0000000000..2f5b937225 --- /dev/null +++ b/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 diff --git a/pandatool/src/vrml/parse_vrml.cxx b/pandatool/src/vrml/parse_vrml.cxx new file mode 100644 index 0000000000..5681181db9 --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +/************************************************** + * 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 diff --git a/pandatool/src/vrml/parse_vrml.h b/pandatool/src/vrml/parse_vrml.h new file mode 100644 index 0000000000..57eea07a5a --- /dev/null +++ b/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 diff --git a/pandatool/src/vrml/standardNodes.wrl b/pandatool/src/vrml/standardNodes.wrl new file mode 100644 index 0000000000..1764f41f67 --- /dev/null +++ b/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 "" +] { } + diff --git a/pandatool/src/vrml/standardNodes.wrl.c b/pandatool/src/vrml/standardNodes.wrl.c new file mode 100644 index 0000000000..41e3b7c758 --- /dev/null +++ b/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; + diff --git a/pandatool/src/vrml/standardNodes.wrl.pz.c b/pandatool/src/vrml/standardNodes.wrl.pz.c new file mode 100644 index 0000000000..2bc1593412 --- /dev/null +++ b/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; + diff --git a/pandatool/src/vrml/standard_nodes.cxx b/pandatool/src/vrml/standard_nodes.cxx new file mode 100644 index 0000000000..62cafd41b5 --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#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 diff --git a/pandatool/src/vrml/standard_nodes.h b/pandatool/src/vrml/standard_nodes.h new file mode 100644 index 0000000000..6e5721c93f --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#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 + diff --git a/pandatool/src/vrml/vrml2egg.cxx b/pandatool/src/vrml/vrml2egg.cxx new file mode 100644 index 0000000000..c41215aecf --- /dev/null +++ b/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 +#include + +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 or 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; +} diff --git a/pandatool/src/vrml/vrml2egg.h b/pandatool/src/vrml/vrml2egg.h new file mode 100644 index 0000000000..a3e8abc6f8 --- /dev/null +++ b/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 + +#include +#include + +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 Nodes; + + void get_all_defs(SFNodeRef &vrml, Nodes &nodes); + + void DoIt(); + + typedef map Instances; + Instances _instances; + + string _filename; +}; + + +#endif diff --git a/pandatool/src/vrml/vrmlLexer.lxx b/pandatool/src/vrml/vrmlLexer.lxx new file mode 100644 index 0000000000..5c78e09a84 --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// +*/ + +/************************************************** + * 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 = ∈ + 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 */ +"#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. */ +PROTO { return PROTO; } +EXTERNPROTO { return EXTERNPROTO; } +DEF { return DEF; } +USE { return USE; } +TO { return TO; } +IS { return IS; } +ROUTE { return ROUTE; } +NULL { return SFN_NULL; } +eventIn { return EVENTIN; } +eventOut { return EVENTOUT; } +field { return FIELD; } +exposedField { return EXPOSEDFIELD; } + + /* Legal identifiers: */ +{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. */ +[0-9]{idRestChar}* { + vrmlyylval.string = strdup(yytext); + return IDENTIFIER; +} + + /* All fields may have an IS declaration: */ +IS { + BEGIN NODE; + expectToken = 0; + yyless(0); +} + +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: */ +\[ { + if (parsing_mf) vrmlyyerror("Double ["); + parsing_mf = 1; + mfarray = new MFArray; +} + +\] { + if (!parsing_mf) vrmlyyerror("Unmatched ]"); + int fieldType = expectToken; + BEGIN NODE; + parsing_mf = 0; + expectToken = 0; + vrmlyylval.fv._mf = mfarray; + return fieldType; +} + +TRUE { + BEGIN NODE; + expectToken = 0; + vrmlyylval.fv._sfbool = true; + return SFBOOL; +} + +FALSE { + BEGIN NODE; + expectToken = 0; + vrmlyylval.fv._sfbool = false; + return SFBOOL; +} + +{int} { + BEGIN NODE; + expectToken = 0; + vrmlyylval.fv._sfint32 = extract_int(); + return SFINT32; +} + +{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: */ +{float} { + BEGIN NODE; + expectToken = 0; + vrmlyylval.fv._sffloat = extract_float(); + return SFFLOAT; +} + +{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; + } +} + +{float}{ws}{float} { + BEGIN NODE; + expectToken = 0; + extract_vec(vrmlyylval.fv._sfvec, 2); + return SFVEC2F; +} + +{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; + } +} + +({float}{ws}){2}{float} { + BEGIN NODE; + expectToken = 0; + extract_vec(vrmlyylval.fv._sfvec, 3); + return SFVEC3F; +} + +({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; + } +} + +({float}{ws}){3}{float} { + BEGIN NODE; + expectToken = 0; + extract_vec(vrmlyylval.fv._sfvec, 4); + return SFROTATION; +} + +({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; + } +} + +({float}{ws}){2}{float} { + BEGIN NODE; + expectToken = 0; + extract_vec(vrmlyylval.fv._sfvec, 3); + return SFCOLOR; +} + +({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; + } +} + +{float} { + BEGIN NODE; + expectToken = 0; + vrmlyylval.fv._sffloat = extract_float(); + return SFTIME; +} + + /* SFString/MFString */ +\" { + BEGIN IN_SFS; + quoted_string = ""; +} + +\" { + BEGIN IN_MFS; + quoted_string = ""; +} + + /* Anything besides open-quote (or whitespace) is an error: */ +[^ \"\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: */ +[^ \[\]\"\t\r\,\n]+ { + vrmlyyerror("String missing open-quote"); + BEGIN NODE; + expectToken = 0; + return MFSTRING; +} + + /* Backslashed-quotes are OK: */ +\\\" { + 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. */ +[^\"\n]+ { + quoted_string += yytext; +} + + /* Quote ends the string: */ +\" { + BEGIN NODE; + expectToken = 0; + vrmlyylval.fv._sfstring = strdup(quoted_string.c_str()); + return SFSTRING; +} + +\" { + 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: */ +{int}{ws}{int} { int w, h; + sscanf(yytext, "%d %d", &w, &h); + sfImageIntsExpected = 1+w*h; + sfImageIntsParsed = 0; + BEGIN 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]; } + diff --git a/pandatool/src/vrml/vrmlLexerDefs.h b/pandatool/src/vrml/vrmlLexerDefs.h new file mode 100644 index 0000000000..36e56d9c07 --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#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 diff --git a/pandatool/src/vrml/vrmlNode.cxx b/pandatool/src/vrml/vrmlNode.cxx new file mode 100644 index 0000000000..df5d4070be --- /dev/null +++ b/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; +} diff --git a/pandatool/src/vrml/vrmlNode.h b/pandatool/src/vrml/vrmlNode.h new file mode 100644 index 0000000000..0b05498850 --- /dev/null +++ b/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 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 VrmlScene; + +ostream &operator << (ostream &out, const VrmlScene &scene); + +#endif diff --git a/pandatool/src/vrml/vrmlNodeType.cxx b/pandatool/src/vrml/vrmlNodeType.cxx new file mode 100644 index 0000000000..e1b552b783 --- /dev/null +++ b/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::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::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::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::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 &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 &recs, const char *name) const +{ + plist::const_iterator i; + for (i = recs.begin(); i != recs.end(); i++) { + if (strcmp((*i)->name, name) == 0) + return (*i); + } + return NULL; +} + diff --git a/pandatool/src/vrml/vrmlNodeType.h b/pandatool/src/vrml/vrmlNodeType.h new file mode 100644 index 0000000000..5d3261d148 --- /dev/null +++ b/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 *_mf; +}; + +typedef pvector 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 &,const char *,int, const VrmlFieldValue *dflt); + const NameTypeRec *has(const plist &,const char *) const; + + char *name; + + // Node types are stored in this data structure: + static plist typeList; + + plist eventIns; + plist eventOuts; + plist fields; +}; + +#endif diff --git a/pandatool/src/vrml/vrmlParser.yxx b/pandatool/src/vrml/vrmlParser.yxx new file mode 100644 index 0000000000..e1e1fa2573 --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +// ******************************************************* +// 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 + +//#define YYDEBUG 1 + +// Currently-being-define proto. Prototypes may be nested, so a stack +// is needed: + +stack< VrmlNodeType*, plist > 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 > currentField; + +// Similarly for the node entries (which contain the actual values for +// the fields as they are encountered): + +stack< VrmlNode*, plist > 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 fieldValue +%type node +%type nodeDeclaration +%type mfnodeValue nodes +%type declarations + +/* + * And types that will be needed by a true VRML implementation: + * %type vrmlscene declarations + */ + +%token IDENTIFIER +%token DEF USE PROTO EXTERNPROTO TO IS ROUTE SFN_NULL +%token EVENTIN EVENTOUT FIELD EXPOSEDFIELD + +%token SFBOOL SFCOLOR SFFLOAT SFIMAGE SFINT32 SFNODE SFROTATION +%token SFSTRING SFTIME SFVEC2F SFVEC3F +%token MFCOLOR MFFLOAT MFINT32 MFROTATION MFSTRING MFVEC2F MFVEC3F +%token 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; +} + diff --git a/pandatool/src/vrml/vrmlParserDefs.h b/pandatool/src/vrml/vrmlParserDefs.h new file mode 100644 index 0000000000..cfb01d6a43 --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#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 diff --git a/pandatool/src/vrmlegg/Sources.pp b/pandatool/src/vrmlegg/Sources.pp new file mode 100644 index 0000000000..82aadcdf34 --- /dev/null +++ b/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 diff --git a/pandatool/src/vrmlegg/indexedFaceSet.cxx b/pandatool/src/vrmlegg/indexedFaceSet.cxx new file mode 100644 index 0000000000..91b75fee73 --- /dev/null +++ b/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 &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 &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 &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 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 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 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)); + } + } +} diff --git a/pandatool/src/vrmlegg/indexedFaceSet.h b/pandatool/src/vrmlegg/indexedFaceSet.h new file mode 100644 index 0000000000..3b5f1fac8d --- /dev/null +++ b/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 &color_list); + void get_vrml_normals(const VrmlNode *normal_node, + pvector &normal_list); + void get_vrml_uvs(const VrmlNode *texCoord_node, + pvector &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 _verts; + }; + pvector _coord_values; + pvector _polys; + pvector _per_vertex_uvs; + pvector _per_vertex_normals; + + bool _has_normals; + + const VrmlNode *_geometry; + const VRMLAppearance &_appearance; +}; + +#endif diff --git a/pandatool/src/vrmlegg/vrmlAppearance.cxx b/pandatool/src/vrmlegg/vrmlAppearance.cxx new file mode 100644 index 0000000000..6079c663bd --- /dev/null +++ b/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); + } + } + } + } +} + + diff --git a/pandatool/src/vrmlegg/vrmlAppearance.h b/pandatool/src/vrmlegg/vrmlAppearance.h new file mode 100644 index 0000000000..7972b709f3 --- /dev/null +++ b/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 diff --git a/pandatool/src/vrmlegg/vrmlToEggConverter.cxx b/pandatool/src/vrmlegg/vrmlToEggConverter.cxx new file mode 100644 index 0000000000..9ce43a57d5 --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#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 ©) : + 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 or 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"; + } + } +} diff --git a/pandatool/src/vrmlegg/vrmlToEggConverter.h b/pandatool/src/vrmlegg/vrmlToEggConverter.h new file mode 100644 index 0000000000..bea1ef724c --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#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 ©); + ~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 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 + + diff --git a/pandatool/src/vrmlprogs/Sources.pp b/pandatool/src/vrmlprogs/Sources.pp new file mode 100644 index 0000000000..ee06efff9b --- /dev/null +++ b/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 diff --git a/pandatool/src/vrmlprogs/vrmlToEgg.cxx b/pandatool/src/vrmlprogs/vrmlToEgg.cxx new file mode 100644 index 0000000000..45dec5a4ec --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#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; +} diff --git a/pandatool/src/vrmlprogs/vrmlToEgg.h b/pandatool/src/vrmlprogs/vrmlToEgg.h new file mode 100644 index 0000000000..ad770d6476 --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#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 + + diff --git a/pandatool/src/vrmlprogs/vrmlTrans.cxx b/pandatool/src/vrmlprogs/vrmlTrans.cxx new file mode 100644 index 0000000000..b6b51bf659 --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#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; +} diff --git a/pandatool/src/vrmlprogs/vrmlTrans.h b/pandatool/src/vrmlprogs/vrmlTrans.h new file mode 100644 index 0000000000..d0e413fe0e --- /dev/null +++ b/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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#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 +