From 2a1a8d70abbecc4ec159ae34f34ea694a35fb95e Mon Sep 17 00:00:00 2001 From: Chien Si Harriman Date: Mon, 11 Jan 2016 22:31:31 -0500 Subject: [PATCH 1/3] Code with Unit Conversions in Progress Conversions not yet completed for Surface Tests --- .gitattributes | 22 + .gitignore | 215 + XMLValidatorWeb.jmconfig | 1 + XMLValidatorWeb.sln | 20 + .../DOEgbXMLClass/DOEgbXMLBasics.cs | 188 + .../DOEgbXMLClass/DOEgbXMLParser.cs | 5849 ++++++++++++ .../DOEgbXMLClass/DOEgbXMLReportingObj.cs | 75 + .../DOEgbXMLClass/DOEgbXMLSurface.cs | 28 + .../DOEgbXMLTestCriteriaObject.cs | 318 + .../DOEgbXMLClass/DOEgbXMLTestDetail.cs | 124 + .../DOEgbXMLClass/DOEgbXMLValidator.cs | 76 + XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLenum.cs | 43 + XMLValidatorWeb/DOEgbXMLClass/Vector.cs | 86 + XMLValidatorWeb/DOEgbXMLClass/gbXML2IDF.cs | 39 + XMLValidatorWeb/DOEgbXMLClass/gbXMLMatches.cs | 19 + XMLValidatorWeb/Default.aspx | 10 + XMLValidatorWeb/Default.aspx.cs | 22 + XMLValidatorWeb/Default.aspx.designer.cs | 24 + XMLValidatorWeb/GreenBuildingXML_Ver5.10.xsd | 6478 +++++++++++++ XMLValidatorWeb/Images/TmpImage.gif | Bin 0 -> 6820 bytes XMLValidatorWeb/Images/header01.jpg | Bin 0 -> 51337 bytes XMLValidatorWeb/Images/header_new.png | Bin 0 -> 21124 bytes XMLValidatorWeb/MasterPage.Master | 34 + XMLValidatorWeb/MasterPage.Master.cs | 17 + XMLValidatorWeb/MasterPage.Master.designer.cs | 60 + .../Pages/PrintFriendlyTablePage.aspx | 18 + .../Pages/PrintFriendlyTablePage.aspx.cs | 26 + .../PrintFriendlyTablePage.aspx.designer.cs | 33 + XMLValidatorWeb/Pages/TestDetailPage.aspx | 18 + XMLValidatorWeb/Pages/TestDetailPage.aspx.cs | 103 + .../Pages/TestDetailPage.aspx.designer.cs | 51 + XMLValidatorWeb/Pages/TestPage.aspx | 52 + XMLValidatorWeb/Pages/TestPage.aspx.cs | 234 + .../Pages/TestPage.aspx.designer.cs | 105 + XMLValidatorWeb/Properties/AssemblyInfo.cs | 35 + XMLValidatorWeb/Scripts/jquery-1.4.1-vsdoc.js | 8061 +++++++++++++++++ XMLValidatorWeb/Scripts/jquery-1.4.1.js | 6111 +++++++++++++ XMLValidatorWeb/Scripts/jquery-1.4.1.min.js | 167 + XMLValidatorWeb/SupportFiles/Conversions.cs | 363 + .../TestFiles/Test Case 1 - Standard File.xml | 2541 ++++++ .../TestFiles/Test Case 2 - Standard File.xml | Bin 0 -> 106294 bytes .../Test Case 25 - Standard File.xml | Bin 0 -> 215912 bytes .../Test Case 28 - Standard File.xml | Bin 0 -> 130294 bytes .../TestFiles/Test Case 3 - Standard File.xml | Bin 0 -> 223036 bytes .../TestFiles/Test Case 4 - Standard File.xml | Bin 0 -> 367706 bytes .../TestFiles/Test Case 5 - Standard File.xml | Bin 0 -> 126526 bytes .../TestFiles/Test Case 7 - Standard File.xml | Bin 0 -> 132990 bytes .../TestFiles/Test Case 8 - Standard File.xml | Bin 0 -> 126846 bytes .../XSD/GreenBuildingXML_Ver5.10.xsd | 6478 +++++++++++++ XMLValidatorWeb/Web.Debug.config | 30 + XMLValidatorWeb/Web.Release.config | 31 + XMLValidatorWeb/XMLValidatorWeb.csproj | 201 + .../bootstrap/css/bootstrap-responsive.css | 1092 +++ .../css/bootstrap-responsive.min.css | 9 + XMLValidatorWeb/bootstrap/css/bootstrap.css | 6039 ++++++++++++ .../bootstrap/css/bootstrap.min.css | 9 + .../img/glyphicons-halflings-white.png | Bin 0 -> 8777 bytes .../bootstrap/img/glyphicons-halflings.png | Bin 0 -> 12799 bytes XMLValidatorWeb/bootstrap/js/bootstrap.js | 2159 +++++ XMLValidatorWeb/bootstrap/js/bootstrap.min.js | 6 + XMLValidatorWeb/css/gbXML.css | 31 + XMLValidatorWeb/web.config | 38 + 62 files changed, 47789 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 XMLValidatorWeb.jmconfig create mode 100644 XMLValidatorWeb.sln create mode 100644 XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLBasics.cs create mode 100644 XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLParser.cs create mode 100644 XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLReportingObj.cs create mode 100644 XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLSurface.cs create mode 100644 XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLTestCriteriaObject.cs create mode 100644 XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLTestDetail.cs create mode 100644 XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLValidator.cs create mode 100644 XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLenum.cs create mode 100644 XMLValidatorWeb/DOEgbXMLClass/Vector.cs create mode 100644 XMLValidatorWeb/DOEgbXMLClass/gbXML2IDF.cs create mode 100644 XMLValidatorWeb/DOEgbXMLClass/gbXMLMatches.cs create mode 100644 XMLValidatorWeb/Default.aspx create mode 100644 XMLValidatorWeb/Default.aspx.cs create mode 100644 XMLValidatorWeb/Default.aspx.designer.cs create mode 100644 XMLValidatorWeb/GreenBuildingXML_Ver5.10.xsd create mode 100644 XMLValidatorWeb/Images/TmpImage.gif create mode 100644 XMLValidatorWeb/Images/header01.jpg create mode 100644 XMLValidatorWeb/Images/header_new.png create mode 100644 XMLValidatorWeb/MasterPage.Master create mode 100644 XMLValidatorWeb/MasterPage.Master.cs create mode 100644 XMLValidatorWeb/MasterPage.Master.designer.cs create mode 100644 XMLValidatorWeb/Pages/PrintFriendlyTablePage.aspx create mode 100644 XMLValidatorWeb/Pages/PrintFriendlyTablePage.aspx.cs create mode 100644 XMLValidatorWeb/Pages/PrintFriendlyTablePage.aspx.designer.cs create mode 100644 XMLValidatorWeb/Pages/TestDetailPage.aspx create mode 100644 XMLValidatorWeb/Pages/TestDetailPage.aspx.cs create mode 100644 XMLValidatorWeb/Pages/TestDetailPage.aspx.designer.cs create mode 100644 XMLValidatorWeb/Pages/TestPage.aspx create mode 100644 XMLValidatorWeb/Pages/TestPage.aspx.cs create mode 100644 XMLValidatorWeb/Pages/TestPage.aspx.designer.cs create mode 100644 XMLValidatorWeb/Properties/AssemblyInfo.cs create mode 100644 XMLValidatorWeb/Scripts/jquery-1.4.1-vsdoc.js create mode 100644 XMLValidatorWeb/Scripts/jquery-1.4.1.js create mode 100644 XMLValidatorWeb/Scripts/jquery-1.4.1.min.js create mode 100644 XMLValidatorWeb/SupportFiles/Conversions.cs create mode 100644 XMLValidatorWeb/SupportFiles/TestFiles/Test Case 1 - Standard File.xml create mode 100644 XMLValidatorWeb/SupportFiles/TestFiles/Test Case 2 - Standard File.xml create mode 100644 XMLValidatorWeb/SupportFiles/TestFiles/Test Case 25 - Standard File.xml create mode 100644 XMLValidatorWeb/SupportFiles/TestFiles/Test Case 28 - Standard File.xml create mode 100644 XMLValidatorWeb/SupportFiles/TestFiles/Test Case 3 - Standard File.xml create mode 100644 XMLValidatorWeb/SupportFiles/TestFiles/Test Case 4 - Standard File.xml create mode 100644 XMLValidatorWeb/SupportFiles/TestFiles/Test Case 5 - Standard File.xml create mode 100644 XMLValidatorWeb/SupportFiles/TestFiles/Test Case 7 - Standard File.xml create mode 100644 XMLValidatorWeb/SupportFiles/TestFiles/Test Case 8 - Standard File.xml create mode 100644 XMLValidatorWeb/SupportFiles/XSD/GreenBuildingXML_Ver5.10.xsd create mode 100644 XMLValidatorWeb/Web.Debug.config create mode 100644 XMLValidatorWeb/Web.Release.config create mode 100644 XMLValidatorWeb/XMLValidatorWeb.csproj create mode 100644 XMLValidatorWeb/bootstrap/css/bootstrap-responsive.css create mode 100644 XMLValidatorWeb/bootstrap/css/bootstrap-responsive.min.css create mode 100644 XMLValidatorWeb/bootstrap/css/bootstrap.css create mode 100644 XMLValidatorWeb/bootstrap/css/bootstrap.min.css create mode 100644 XMLValidatorWeb/bootstrap/img/glyphicons-halflings-white.png create mode 100644 XMLValidatorWeb/bootstrap/img/glyphicons-halflings.png create mode 100644 XMLValidatorWeb/bootstrap/js/bootstrap.js create mode 100644 XMLValidatorWeb/bootstrap/js/bootstrap.min.js create mode 100644 XMLValidatorWeb/css/gbXML.css create mode 100644 XMLValidatorWeb/web.config diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..412eeda --- /dev/null +++ b/.gitattributes @@ -0,0 +1,22 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp +*.sln merge=union +*.csproj merge=union +*.vbproj merge=union +*.fsproj merge=union +*.dbproj merge=union + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b9d6bd9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,215 @@ +################# +## Eclipse +################# + +*.pydevproject +.project +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + + +################# +## Visual Studio +################# + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +build/ +[Bb]in/ +[Oo]bj/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml +*.pubxml + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +#packages/ + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml +*.pfx +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +############# +## Windows detritus +############# + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac crap +.DS_Store + + +############# +## Python +############# + +*.py[co] + +# Packages +*.egg +*.egg-info +dist/ +build/ +eggs/ +parts/ +var/ +sdist/ +develop-eggs/ +.installed.cfg + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.tox + +#Translations +*.mo + +#Mr Developer +.mr.developer.cfg diff --git a/XMLValidatorWeb.jmconfig b/XMLValidatorWeb.jmconfig new file mode 100644 index 0000000..10eea63 --- /dev/null +++ b/XMLValidatorWeb.jmconfig @@ -0,0 +1 @@ +false \ No newline at end of file diff --git a/XMLValidatorWeb.sln b/XMLValidatorWeb.sln new file mode 100644 index 0000000..a252c91 --- /dev/null +++ b/XMLValidatorWeb.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XMLValidatorWeb", "XMLValidatorWeb\XMLValidatorWeb.csproj", "{D9E0A2E6-768A-4377-AF62-675D156F8813}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D9E0A2E6-768A-4377-AF62-675D156F8813}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D9E0A2E6-768A-4377-AF62-675D156F8813}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D9E0A2E6-768A-4377-AF62-675D156F8813}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D9E0A2E6-768A-4377-AF62-675D156F8813}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLBasics.cs b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLBasics.cs new file mode 100644 index 0000000..4cfe40f --- /dev/null +++ b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLBasics.cs @@ -0,0 +1,188 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Xml; + +namespace DOEgbXML +{ + public class DOEgbXMLBasics + { + public static bool SliversAllowed = true; + + public enum MeasurementUnits + { + cubicft, + sqft, + ft, + spaces, + levels, + } + + public class Tolerances + { + public const double ToleranceDefault = -999; + public const double VolumeTolerance = 1.0; + public const double AreaTolerance = 1.0; + public const double SpaceAreaPercentageTolerance = 0.025; + + //Level (aka - story) height difference tolerance in feet + public const double LevelHeightTolerance = 0.1; + public const double VectorAngleTolerance = 2.5; + public const double SpaceAreaTolerance = 1; + //all count tolerances + public const double SpaceCountTolerance = 0; + public const double LevelCountTolerance = 0; + public const double SurfaceCountTolerance = 0; + public const double ExteriorWallCountTolerance = 0; + public const double InteriorWallCountTolerance = 0; + public const double InteriorFloorCountTolerance = 0; + public const double RoofCountTolerance = 0; + public const double AirWallCountTolerance = 0; + public const double OpeningCountTolerance = 0; + public const double FixedWindowCountTolerance = 0; + public const double OperableWindowCountTolerance = 0; + public const double FixedSkylightCountTolerance = 0; + public const double OperableSkylightCountTolerance = 0; + public const double SlidingDoorCountTolerance = 0; + public const double NonSlidingDoorCountTolerance = 0; + public const double AirOpeningCountTolerance = 0; + + //surface tolerances + public const double SurfaceHeightTolerance = 0.5; //feet + public const double SurfaceWidthTolerance = 0.5; //feet + public const double SurfaceTiltTolerance = 2.5; // degrees + public const double SurfaceAzimuthTolerance = 2.5; //degrees + public const double SurfaceInsPtXTolerance = 0.5; //feet + public const double SurfaceInsPtYTolerance = 0.5; //feet + public const double SurfaceInsPtZTolerance = 0.5; //feet + public const double SurfacePLCoordTolerance = 0.5; //feet (3 inches) + public const double SliverDimensionTolerance = 0.25; //feet + public const double SurfaceAreaPercentageTolerance = 0.025; + + //opening tolerances + public const double OpeningHeightTolerance = 0.5; //feet + public const double OpeningWidthTolerance = 0.5; //feet + public const double OpeningSurfaceInsPtXTolerance = 0.5; //feet + public const double OpeningSurfaceInsPtYTolerance = 0.5; //feet + public const double OpeningSurfaceInsPtZTolerance = 0.5; //feet + public const double OpeningAreaPercentageTolerance = 0.025; + } + + public class Conversions + { + //the idea is, it searches through the document and finds items to switch out + //it is called when needed by a user or programmer + public XmlDocument ConvertFtToMeter(XmlDocument origdoc, XmlNamespaceManager gbXMLns1) + { + //number of feet in a meter + double convrate = 3.280839895; + + XmlDocument retdoc = (XmlDocument)origdoc.Clone(); + //by default, I will always change these nodes because they are the minimum that must be presented + + + //surface polyloop + //surface lower left hand corner + //building storeys + XmlNodeList nodes = retdoc.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:BuildingStorey", gbXMLns1); + if (nodes.Count > 0) + { + foreach (XmlNode Node in nodes) + { + XmlNodeList childnodes = Node.ChildNodes; + foreach (XmlNode childnode in childnodes) + { + if (childnode.Name == "Level") + { + childnode.Value = Convert.ToString(Convert.ToDouble(childnode.Value) / convrate); + } + else if (childnode.Name == "PlanarGeometry") + { + //change the planar geometry + foreach (XmlNode PolyLoops in childnode) + { + //gathers all the cartesian points in a given polyloop + foreach (XmlNode cartesianPoints in PolyLoops) + { + foreach (XmlNode coordinate in cartesianPoints) + { + if (coordinate.Name == "Coordinate") + { + coordinate.Value = Convert.ToString(Convert.ToDouble(coordinate.Value) / convrate); + } + else + { + //this is bad, should terminate somehow + } + } + } + } + } + } + } + } + //space planar geometry + //space shell geometry + //space space boundaries + XmlNodeList spacenodes = retdoc.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Spaces", gbXMLns1); + if (nodes.Count > 0) + { + foreach (XmlNode Node in nodes) + { + XmlNodeList childnodes = Node.ChildNodes; + foreach (XmlNode childnode in childnodes) + { + if (childnode.Name == "PlanarGeometry") + { + //change the planar geometry + foreach (XmlNode PolyLoops in childnode) + { + //gathers all the cartesian points in a given polyloop + foreach (XmlNode cartesianPoints in PolyLoops) + { + foreach (XmlNode coordinate in cartesianPoints) + { + if (coordinate.Name == "Coordinate") + { + coordinate.Value = Convert.ToString(Convert.ToDouble(coordinate.Value) / convrate); + } + else + { + //this is bad, should terminate somehow + } + } + } + } + } + else if (childnode.Name == "ShellGeometry") + { + //this should always be the ClosedShell element + XmlNode closedShell = childnode.FirstChild; + foreach (XmlNode PolyLoops in childnode) + { + //gathers all the cartesian points in a given polyloop + foreach (XmlNode cartesianPoints in PolyLoops) + { + foreach (XmlNode coordinate in cartesianPoints) + { + if (coordinate.Name == "Coordinate") + { + coordinate.Value = Convert.ToString(Convert.ToDouble(coordinate.Value) / convrate); + } + else + { + //this is bad, should terminate somehow + } + } + } + } + } + } + } + } + return retdoc; + } + } + } +} \ No newline at end of file diff --git a/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLParser.cs b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLParser.cs new file mode 100644 index 0000000..2b557ea --- /dev/null +++ b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLParser.cs @@ -0,0 +1,5849 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Xml; +using System.Xml.XPath; +using System.Text.RegularExpressions; +using VectorMath; +using System.Web; +using DOEgbXML; +using UnitConversions; + +namespace DOEgbXML +{ + class OpeningDefinitions + { + //creates instances of an object that store information about surfaces in a gbXML file + public string OpeningType; + public string OpeningId; + public string ParentSurfaceId; + public double ParentAzimuth; + public double ParentTilt; + public double Azimuth; + public double Tilt; + public double Height; + public double Width; + public double surfaceArea; + public Vector.CartCoord InsertionPoint; + public List PlCoords; + public Vector.CartVect PlRHRVector; + } + + class XMLParser + { + + //this is the output string + public string output; + public string log; + public string table; + bool overallPassTest = true; + DOEgbXMLTestCriteriaObject TestCriteria; + DOEgbXMLTestDetail TestDetail; + gbXMLMatches globalMatchObject; + string TestToRun; + XmlDocument gbXMLStandardFile; + XmlDocument gbXMLTestFile; + public string summaryTable; + public List ReportList; + + //a List of strings with all the test files that I want to test + //eventually this will be a dynamically created list based on what has been uploaded. + //this list should be the list of all the test + + static Dictionary filepaths = new Dictionary() + { + {"Test1" ,Path.Combine(HttpRuntime.AppDomainAppPath,"SupportFiles/TestFiles/Test Case 1 - Standard File.xml")}, + {"Test2" ,Path.Combine(HttpRuntime.AppDomainAppPath,"SupportFiles/TestFiles/Test Case 2 - Standard File.xml")}, + {"Test3" ,Path.Combine(HttpRuntime.AppDomainAppPath,"SupportFiles/TestFiles/Test Case 3 - Standard File.xml")}, + {"Test4" ,Path.Combine(HttpRuntime.AppDomainAppPath,"SupportFiles/TestFiles/Test Case 4 - Standard File.xml")}, + {"Test5" ,Path.Combine(HttpRuntime.AppDomainAppPath,"SupportFiles/TestFiles/Test Case 5 - Standard File.xml")}, + {"Test7" ,Path.Combine(HttpRuntime.AppDomainAppPath,"SupportFiles/TestFiles/Test Case 7 - Standard File.xml")}, + {"Test8" ,Path.Combine(HttpRuntime.AppDomainAppPath,"SupportFiles/TestFiles/Test Case 8 - Standard File.xml")}, + {"Test25" ,Path.Combine(HttpRuntime.AppDomainAppPath,"SupportFiles/TestFiles/Test Case 25 - Standard File.xml")}, + {"Test28" ,Path.Combine(HttpRuntime.AppDomainAppPath,"SupportFiles/TestFiles/Test Case 28 - Standard File.xml")}, + }; + + + //Shell Geometry RHR Dictionaries + static Dictionary> TFShellGeomRHRes = new Dictionary>(); + static Dictionary> SFShellGeomRHRes = new Dictionary>(); + + //minimum number of points to define a plane + static int minPlanePoints = 3; + //value to hold, starting arbitrarily large + static double StoryHeightMin = 100.0; + + #region Test Report + public void StartTest(XmlReader xmldoc, string testToRun, string username) + { + Conversions c = new Conversions(); + + TestToRun = testToRun; + globalMatchObject = new gbXMLMatches(); + globalMatchObject.Init(); + + //first create a list of lists that is indexed identically to the drop down list the user selects + TestDetail = new DOEgbXMLTestDetail(); + //then populate the list of lists. All indexing is done "by hand" in InitializeTestResultStrings() + TestDetail.InitializeTestResultStrings(); + + //create report list reportlist will store all the test result + ReportList = new List(); + + //Load an XML File for the test at hand + gbXMLTestFile = new XmlDocument(); + gbXMLTestFile.Load(xmldoc); + + gbXMLStandardFile = new XmlDocument(); + // gbXMLStandardFile.Load(filepaths[testToRun]); + + if (!TestFileIsAvailable()) + return; + + //Define the namespace + XmlNamespaceManager gbXMLns1 = new XmlNamespaceManager(gbXMLTestFile.NameTable); + gbXMLns1.AddNamespace("gbXMLv5", "http://www.gbxml.org/schema"); + XmlNamespaceManager gbXMLns2 = new XmlNamespaceManager(gbXMLStandardFile.NameTable); + gbXMLns2.AddNamespace("gbXMLv5", "http://www.gbxml.org/schema"); + + //is the test file metric or not? + bool isMetric = false; + XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML", gbXMLns1); + Conversions.volumeUnitEnum testVol = Conversions.volumeUnitEnum.CubicFeet; + Conversions.volumeUnitEnum standardVol = Conversions.volumeUnitEnum.CubicFeet; + Conversions.areaUnitEnum testArea = Conversions.areaUnitEnum.SquareFeet; + Conversions.areaUnitEnum standardArea = Conversions.areaUnitEnum.SquareFeet; + Conversions.lengthUnitEnum testLength = Conversions.lengthUnitEnum.Feet; + Conversions.lengthUnitEnum standardLength = Conversions.lengthUnitEnum.Feet; + double lengthConversion = 1; + double areaConversion = 1; + double volumeConversion = 1; + foreach (XmlNode Node in nodes) + { + XmlAttributeCollection spaceAtts = Node.Attributes; + foreach (XmlAttribute at in spaceAtts) + { + if (at.Name == "volumeUnit") + { + string type = at.Value; + testVol = (Conversions.volumeUnitEnum)System.Enum.Parse(typeof(Conversions.volumeUnitEnum), type, true); + //we know the test files are in cubic feet + volumeConversion = c.GetVolumeUnitConversion(testVol,Conversions.volumeUnitEnum.CubicFeet); + if(volumeConversion == -999) + { + //return with an error message stating contact system administrator with a code + } + + } + else if (at.Name == "areaUnit") + { + string type = at.Value; + testArea = (Conversions.areaUnitEnum)System.Enum.Parse(typeof(Conversions.areaUnitEnum), type, true); + areaConversion = c.GetAreaConversion(testArea,Conversions.areaUnitEnum.SquareFeet); + if(areaConversion == -999) + { + //return with an error message stating contact system administrator with a code + } + } + else if (at.Name == "lengthUnit") + { + string type = at.Value; + testLength = (Conversions.lengthUnitEnum)System.Enum.Parse(typeof(Conversions.lengthUnitEnum), type, true); + lengthConversion = c.GetLengthConversion(testLength,Conversions.lengthUnitEnum.Feet); + if (lengthConversion == -999) + { + //return with an error message stating contact system administrator with a code + } + } + } + } + + //if isMetric is true, then we would like to convert the test file's numbers to US-IP units + if(isMetric) gbXMLTestFile = ConvertMetricToUS(gbXMLTestFile); + + List gbXMLdocs = new List(); + gbXMLdocs.Add(gbXMLTestFile); + gbXMLdocs.Add(gbXMLStandardFile); + List gbXMLnsm = new List(); + gbXMLnsm.Add(gbXMLns1); + gbXMLnsm.Add(gbXMLns2); + + //Create a Log file that logs the success or failure of each test. + //Eventually maybe I want to create a little HTML factory + + output = ""; + log = ""; + table += "
" + + "

" + "Test Sections" + "

"; + table += ""; + table += "" + + "" + + "" + + "" + + "" + + "" + + ""; + + string units; + DOEgbXMLReportingObj report = new DOEgbXMLReportingObj(); + report.standResult = new List(); + report.testResult = new List(); + report.idList = new List(); + report.MessageList = new List(); + report.TestPassedDict = new Dictionary(); + + //Set up the Global Pass/Fail criteria for the test case file + TestCriteria = new DOEgbXMLTestCriteriaObject(); + TestCriteria.InitializeTestCriteriaWithTestName(testToRun); + + //Test 2 execute + report.tolerance = DOEgbXMLBasics.Tolerances.AreaTolerance; + report.testType = TestType.Building_Area; + units = DOEgbXMLBasics.MeasurementUnits.sqft.ToString(); + report = GetBuildingArea(gbXMLdocs, gbXMLnsm, report, standardArea, testArea, areaConversion); + AddToOutPut("Building Area Test Passed: ", report, true); + + //Test 3 execute + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.SpaceCountTolerance; + report.testType = TestType.Space_Count; + units = DOEgbXMLBasics.MeasurementUnits.spaces.ToString(); + report = GetBuildingSpaceCount(gbXMLdocs, gbXMLnsm, report, units); + AddToOutPut("Building Space Quantity Count Test Passed: ", report, true); + + + ////Test 4 execute + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.LevelCountTolerance; + report.testType = TestType.Building_Story_Count; + units = DOEgbXMLBasics.MeasurementUnits.levels.ToString(); + report = GetBuildingStoryCount(gbXMLdocs, gbXMLnsm, report, units); + AddToOutPut("Building Story Count Test Passed: ", report, true); + + + //Test 5 execute + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.LevelHeightTolerance; + report.testType = TestType.Building_Story_Z_Height; + units = DOEgbXMLBasics.MeasurementUnits.ft.ToString(); + report = GetStoryHeights(gbXMLdocs, gbXMLnsm, report, standardLength, testLength, lengthConversion); + AddToOutPut("Building Story Z-Height Test: ", report, true); + + + //Test 6 execute + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.VectorAngleTolerance; + report.testType = TestType.Building_Story_PolyLoop_RHR; + units = "degrees"; + report = TestBuildingStoryRHR(gbXMLdocs, gbXMLnsm, report, units); + AddToOutPut("Building Story PolyLoop Right Hand Rule Test Result:", report, true); + + + //String spShellGeometrySurfaceNum = TestShellGeomSurfaceNum(gbXMLTestFile, gbXMLns); + + //Space Tests ............................................................. + //Test 7 execute + //only needs to test the test file + report.Clear(); + report.testType = TestType.SpaceId_Match_Test; + report = UniqueSpaceIdTest(gbXMLdocs, gbXMLnsm, report); + AddToOutPut("SpaceId Match Test: ", report, true); + + + //Test 8 execute + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.SpaceAreaTolerance; + report.testType = TestType.Space_Area; + units = DOEgbXMLBasics.MeasurementUnits.sqft.ToString(); + report = TestSpaceAreas(gbXMLdocs, gbXMLnsm, report, standardArea,testArea,areaConversion); + AddToOutPut("Space Areas Test: ", report, true); + + + //Test 9 execute + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.VolumeTolerance; + report.testType = TestType.Space_Volume; + units = DOEgbXMLBasics.MeasurementUnits.cubicft.ToString(); + report = TestSpaceVolumes(gbXMLdocs, gbXMLnsm, report, units); + AddToOutPut("Space Volumes Test: ", report, true); + + + //Test 10 Execute + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.VectorAngleTolerance; + report.testType = TestType.Shell_Geom_RHR; + units = "degrees"; + report = TestShellGeomPLRHR(gbXMLdocs, gbXMLnsm, report, units); + //AddToOutPut("Shell Geometry RHR Test: ",report); + + //Surface Element tests + //Test 11 Execute + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.SurfaceCountTolerance; + report.testType = TestType.Total_Surface_Count; + units = ""; + report = GetSurfaceCount(gbXMLdocs, gbXMLnsm, report, units); + AddToOutPut("Surface Count Test Result: ", report, true); + + + //Surface Element tests + //Test 12 Execute + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.ExteriorWallCountTolerance; + report.testType = TestType.Exterior_Wall_Surface_Count; + units = ""; + report = GetEWSurfaceCount(gbXMLdocs, gbXMLnsm, report, units); + AddToOutPut("Exterior Wall Surface Count Test Result: ", report, true); + + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.SurfaceCountTolerance; + report.testType = TestType.Underground_Surface_Count; + units = ""; + report = GetUGSurfaceCount(gbXMLdocs, gbXMLnsm, report, units); + AddToOutPut("Underground Wall Count Test Result: ", report, true); + + //Surface Element tests + //Test 13 Execute + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.InteriorWallCountTolerance; + report.testType = TestType.Interior_Wall_Surface_Count; + units = ""; + report = GetIWSurfaceCount(gbXMLdocs, gbXMLnsm, report, units); + AddToOutPut("Interior Wall Surface Count Test Result: ", report, true); + + //Surface Element tests + //Test 13 Execute + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.InteriorFloorCountTolerance; + report.testType = TestType.Interior_Floor_Surface_Count; + units = ""; + report = GetIFSurfaceCount(gbXMLdocs, gbXMLnsm, report, units); + AddToOutPut("Interior Floor Surface Count Test Result: ", report, true); + + + //Surface Element tests + //Test 14 Execute + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.InteriorWallCountTolerance; + report.testType = TestType.Roof_Surface_Count; + units = ""; + report = GetRoofSurfaceCount(gbXMLdocs, gbXMLnsm, report, units); + AddToOutPut("Roof Surface Count Test Result: ", report, true); + + + //Surface Element tests + //Test 15 Execute + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.InteriorWallCountTolerance; + report.testType = TestType.Shading_Surface_Count; + units = ""; + report = GetShadeSurfaceCount(gbXMLdocs, gbXMLnsm, report, units); + AddToOutPut("Shading Surface Count Test Result: ", report, true); + + + //Test 16 Execute + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.AirWallCountTolerance; + report.testType = TestType.Air_Surface_Count; + units = ""; + report = GetAirSurfaceCount(gbXMLdocs, gbXMLnsm, report, units); + AddToOutPut("Air Surface Count Test Result: ", report, true); + + + #region surface detailed test + //Jan 31-2012: We may not want to perform these if the surface counts fail, but for now, we will include these tests + //Detailed Surface Checks + //Store Surface Element Information + List TestSurfaces = new List(); + XmlDocument TestFile = gbXMLdocs[0]; + XmlNamespaceManager TestNSM = gbXMLnsm[0]; + List StandardSurfaces = new List(); + XmlDocument StandardFile = gbXMLdocs[1]; + XmlNamespaceManager StandardNSM = gbXMLnsm[1]; + TestSurfaces = GetFileSurfaceDefs(TestFile, TestNSM); + StandardSurfaces = GetFileSurfaceDefs(StandardFile, StandardNSM); + string TestSurfaceTable = "
" + "Test Section Name" + "" + "Standard Result" + "" + "Test File Result" + "" + "Tolerances" + "" + "Pass/Fail" + "
"; + TestSurfaceTable += "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""; + //Test Surfaces Planar Test + //all polyloops must be such that the surface defined by the coordinates is planar + report.Clear(); + report.testType = TestType.Surface_Planar_Test; + report = TestSurfacePlanarTest(TestSurfaces, report); + + if (!report.passOrFail) + { + AddToOutPut("Test File Planar Surface Check: ", report, true); + report.Clear(); + } + //only run detailed surface checks if the surfaces are planar + else + { + // + //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation + //Execute Tests + + + // globalMatchObject.MatchedSurfaceIds = new Dictionary>(); + int i = 1; + + foreach (SurfaceDefinitions surface in StandardSurfaces) + { + report.Clear(); + //multiple tolerances used + report.testType = TestType.Detailed_Surface_Checks; + report.subTestIndex = i; + + //multiple units used, so ignore units + report = GetPossibleSurfaceMatches(surface, TestSurfaces, report); + + AddToOutPut("Test 17 for Surface number " + i + " Result: ", report, false); + + foreach (SurfaceDefinitions ts in TestSurfaces) + { + if (globalMatchObject.MatchedSurfaceIds.ContainsKey(surface.SurfaceId)) + { + foreach (string id in globalMatchObject.MatchedSurfaceIds[surface.SurfaceId]) + { + if (ts.SurfaceId == id) + { + if (report.passOrFail) + TestSurfaceTable += "" + + "" + + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""; + } + + } + + } + } + //if didn't find match means it failed the test + if (!report.passOrFail) + TestSurfaceTable += "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""; + i += 1; + } + + TestSurfaceTable += "
" + "Test Section Name" + "" + "Stand Surface ID" + "" + "Test Surface ID" + "" + "Stand Surface Tilt" + "" + "Test Surface Tilt" + "" + "Stand Surface Azimuth" + "" + "Test Surface Azimuth" + "" + "Stand Surface Height" + "" + "Test Surface Height" + "" + "Stand Surface Width" + "" + "Test Surface Width" + "" + "Pass/Fail" + "
" + "" + + "Detailed Surface Checks " + report.subTestIndex + "" + "" + surface.SurfaceId + "" + ts.SurfaceId + "" + String.Format("{0:#,0.00}", surface.Tilt) + "" + String.Format("{0:#,0.00}", ts.Tilt) + "" + String.Format("{0:#,0.00}", surface.Azimuth) + "" + String.Format("{0:#,0.00}", ts.Azimuth) + "" + String.Format("{0:#,0.00}", surface.Height) + "" + String.Format("{0:#,0.00}", ts.Height) + "" + String.Format("{0:#,0.00}", surface.Width) + "" + String.Format("{0:#,0.00}", ts.Width) + "" + "Pass" + "
" + "" + + "Detailed Surface Checks " + report.subTestIndex + "" + "" + surface.SurfaceId + "" + "---" + String.Format("{0:#,0.00}", surface.Tilt) + "" + "---" + String.Format("{0:#,0.00}", surface.Azimuth) + "" + "---" + String.Format("{0:#,0.00}", surface.Height) + "" + "---" + String.Format("{0:#,0.00}", surface.Width) + "" + "---" + "Fail" + "

"; + } + #endregion + + //test 18 CountFixedWindows + //Test 18 Execute + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.FixedWindowCountTolerance; + report.testType = TestType.Fixed_Windows_Count; + units = ""; + report = CountFixedWindows(gbXMLdocs, gbXMLnsm, report, units); + AddToOutPut("Fixed Windows Count Test Result: ", report, true); + + //test 19 CountOperableWindows + //Test 19 Execute + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.OperableWindowCountTolerance; + report.testType = TestType.Operable_Windows_Count; + units = ""; + report = CountOperableWindows(gbXMLdocs, gbXMLnsm, report, units); + AddToOutPut("Operable Windows Count Test Result: ", report, true); + + //test 20 CountFixedSkylights + //Test 20 Execute + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.FixedSkylightCountTolerance; + report.testType = TestType.Fixed_Skylight_Count; + units = ""; + report = CountFixedSkylights(gbXMLdocs, gbXMLnsm, report, units); + AddToOutPut("Fixed Skylight Count Test Result: ", report, true); + + //test 21 CountOperableSkylights + //Test 21 Execute + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.OperableSkylightCountTolerance; + report.testType = TestType.Operable_Skylight_Count; + units = ""; + report = CountOperableSkylights(gbXMLdocs, gbXMLnsm, report, units); + AddToOutPut("Operable Skylight Count Test Result: ", report, true); + + + //test 22 CountSlidingDoors + //Test 22 Execute + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.SlidingDoorCountTolerance; + report.testType = TestType.Sliding_Doors_Count; + units = ""; + report = CountSlidingDoors(gbXMLdocs, gbXMLnsm, report, units); + AddToOutPut("Sliding Doors Count Test Result: ", report, true); + + //test 23 CountNonSlidingDoors + //Test 23 Execute + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.NonSlidingDoorCountTolerance; + report.testType = TestType.Non_Sliding_Doors_Count; + units = ""; + report = CountNonSlidingDoors(gbXMLdocs, gbXMLnsm, report, units); + AddToOutPut("Non Sliding Doors Count Test Result: ", report, true); + + //test 24 CountAirOpenings + //Test 24 Execute + report.Clear(); + report.tolerance = DOEgbXMLBasics.Tolerances.AirOpeningCountTolerance; + report.testType = TestType.Air_Openings_Count; + units = ""; + report = CountAirOpenings(gbXMLdocs, gbXMLnsm, report, units); + AddToOutPut("Air Openings Count Test Result: ", report, true); + + + #region opending detailed test + //openings detailed tests + List TestOpenings = new List(); + XmlDocument testFile = gbXMLdocs[0]; + XmlNamespaceManager testNSM = gbXMLnsm[0]; + List StandardOpenings = new List(); + XmlDocument standardFile = gbXMLdocs[1]; + XmlNamespaceManager standardNSM = gbXMLnsm[1]; + TestOpenings = GetFileOpeningDefs(TestFile, TestNSM); + StandardOpenings = GetFileOpeningDefs(StandardFile, StandardNSM); + + string TestOpeningTable = ""; + report.Clear(); + report.testType = TestType.Opening_Planar_Test; + report = TestOpeningPlanarTest(TestOpenings, report); + + if (!report.passOrFail) + { + AddToOutPut("Test File Planar Opening Check: ", report, true); + report.Clear(); + } + //only run detailed opening checks if the opening are planar + else + { + TestOpeningTable = "
"; + TestOpeningTable += "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""; + + globalMatchObject.MatchedOpeningIds = new Dictionary>(); + int i = 1; + //if no openings remove the table. + if (StandardOpenings.Count < 1) + TestOpeningTable = ""; + //compare the openings + foreach (OpeningDefinitions opening in StandardOpenings) + { + report.Clear(); + + report.testType = TestType.Detailed_Opening_Checks; + report.subTestIndex = i; + + report = GetPossibleOpeningMatches(opening, TestOpenings, report); + + AddToOutPut("Test 17 for Opening number " + i + " Result: ", report, false); + + foreach (OpeningDefinitions to in TestOpenings) + { + if (globalMatchObject.MatchedOpeningIds.ContainsKey(opening.OpeningId)) + { + foreach (string id in globalMatchObject.MatchedOpeningIds[opening.OpeningId]) + { + if (to.OpeningId == id) + { + if (report.passOrFail) + TestOpeningTable += "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""; + } + + } + + } + } + //if didn't find match means it failed the test + if (!report.passOrFail) + TestOpeningTable += "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""; + i += 1; + + } + } + TestOpeningTable += "
" + "Test Section Name" + "" + "Standard Opening Id" + "" + "Test Opening Id" + "" + "Standard Parent Surface Id" + "" + "Test Parent Surface Id" + "" + "Standard Parent Azimuth" + "" + "Test Parent Azimuth" + "" + "Standard Parent Tilt" + "" + "Test Parent Tilt" + "" + "Standard Surface Area" + "" + "Test Surface Area" + "" + "Pass/Fail" + "
" + "" + + "Detailed Opening Checks " + report.subTestIndex + "" + "" + opening.OpeningId + "" + to.OpeningId + "" + opening.ParentSurfaceId + "" + to.ParentSurfaceId + "" + String.Format("{0:#,0.00}", opening.ParentAzimuth) + "" + String.Format("{0:#,0.00}", to.ParentAzimuth) + "" + String.Format("{0:#,0.00}", opening.ParentTilt) + "" + String.Format("{0:#,0.00}", to.ParentTilt) + "" + String.Format("{0:#,0.00}", opening.surfaceArea) + "" + String.Format("{0:#,0.00}", to.surfaceArea) + "" + "Pass" + "
" + "" + + "Detailed Opening Checks " + report.subTestIndex + "" + "" + opening.OpeningId + "" + "---" + "" + opening.ParentSurfaceId + "" + "---" + "" + String.Format("{0:#,0.00}", opening.ParentAzimuth) + "" + "---" + "" + String.Format("{0:#,0.00}", opening.ParentTilt) + "" + "---" + "" + String.Format("{0:#,0.00}", opening.surfaceArea) + "" + "---" + "" + "Fail" + "

"; + #endregion + + //close table + table += "
"; + //add TestSurfaceTable + table += TestSurfaceTable + TestOpeningTable; + + CreateSummaryTable(); + + } + private void AddToOutPut(string title, DOEgbXMLReportingObj report, bool createTable) + { + //add report to report list + //have to deep copy the report before put report in the list + DOEgbXMLReportingObj tmpreport = report.Copy(); + ReportList.Add(tmpreport); + + //title + output += "

" + title + "

"; + log += title + System.Environment.NewLine; + + //message + var passTest = report.TestPassedDict.Values; + bool individualTestBool = true; + foreach (bool testResult in passTest) + { + if (testResult == false) + { + individualTestBool = false; + break; + } + } + if (report.passOrFail && individualTestBool) + output += "

" + report.longMsg + "

"; + else + { + output += "

" + report.longMsg + "

"; + overallPassTest = false; + } + + log += report.longMsg + System.Environment.NewLine; + + //message list, print out each message in the list if there are any + if (report.MessageList.Count > 0) + for (int i = 0; i < report.MessageList.Count; i++) + { + output += "

" + report.MessageList[i] + "

"; + log += report.MessageList[i] + System.Environment.NewLine; + } + + output += "
"; + log += System.Environment.NewLine; + + //create table row + if (createTable) + { + + if (report.standResult.Count == 0) + { + report.standResult.Add("---"); + report.testResult.Add("---"); + report.idList.Add(""); + } + + //for eachout put + for (int i = 0; i < report.standResult.Count; i++) + { + bool sameString = false; + if (report.standResult[i] == report.testResult[i]) + sameString = true; + + //check if test pass or fail + if ((report.passOrFail && individualTestBool) || sameString) + table += ""; + else + { + table += ""; + overallPassTest = false; + } + + table += "" + "" + title + " " + report.idList[i] + "" + ""; + + if ((report.passOrFail && individualTestBool) || sameString) + { + table += "" + report.standResult[i] + " " + report.unit + "" + + "" + report.testResult[i] + " " + report.unit + "" + + "" + "±" + report.tolerance + " " + report.unit + "" + + "Pass" + + ""; + } + else + table += "" + report.standResult[i] + " " + report.unit + "" + + "" + report.testResult[i] + " " + report.unit + "" + + "" + "±" + report.tolerance + " " + report.unit + "" + + "Fail" + + ""; + + } + } + + } + private void CreateSummaryTable() + { + //create overall summary table + //find the right testdetail + //check if the user pass the test + bool passTest = true; + bool aceTest = true; + foreach (DOEgbXMLReportingObj tmpreport in ReportList) + { + if (TestCriteria.TestCriteriaDictionary.ContainsKey(tmpreport.testType)) + { + if (TestCriteria.TestCriteriaDictionary[tmpreport.testType] && !tmpreport.passOrFail) + passTest = false; + if (!TestCriteria.TestCriteriaDictionary[tmpreport.testType] && !tmpreport.passOrFail) + aceTest = false; + } + else if (tmpreport.testType == TestType.Detailed_Surface_Checks) + { + + } + + else + { + + } + } + foreach (DOEgbXMLTestDetail detail in TestDetail.TestDetailList) + if (detail.testName == TestToRun) + { + summaryTable = "

Result Summary

"; + summaryTable += "
"; + + summaryTable += "" + + "" + + "" + + "" + + ""; + + if (passTest && aceTest) + summaryTable += ""; + else if (passTest) + summaryTable += ""; + else + summaryTable += ""; + + summaryTable += "" + + ""; + + if (passTest && aceTest) + summaryTable += "" + ""; + else if (passTest) + summaryTable += "" + ""; + else + summaryTable += "" + ""; + + summaryTable += "
" + "gbXML schema Test" + "" + "" + "" + "Pass" + "
" + "gbXML Test" + "" + detail.shortTitle + "" + detail.passString + "
" + "You pass the test with minor errors" + "
" + detail.failString + "

"; + break; + } + } + private bool TestFileIsAvailable() + { + //check if the file available + if (filepaths.ContainsKey(TestToRun)) + { + gbXMLStandardFile.Load(filepaths[TestToRun]); + return true; + } + else + { + //create overall summary table + summaryTable = "

Result Summary

"; + summaryTable += "
"; + + summaryTable += "" + + "" + + "" + + "" + + ""; + + summaryTable += ""; + + summaryTable += "" + + ""; + + summaryTable += "" + ""; + + summaryTable += "
" + "gbXML schema Test" + "" + "" + "" + "Pass" + "
" + "gbXML Test" + "" + "Test File Currently Not available" + "" + "Error Error Error" + "

"; + return false; + } + } + #endregion + + private XmlDocument ConvertMetricToUS(XmlDocument mdoc) + { + XmlDocument ipdoc = new XmlDocument(); + + return ipdoc; + } + + + + #region Test Functions + private DOEgbXMLReportingObj GetUGSurfaceCount(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units) + { + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Mar 14 2013 + report.testSummary = "This test compares the total number of Surface elements with the SurfaceType=\"UndergroundWall\" in the test"; + report.testSummary += " and standard files. It does this by"; + report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this SurfaceType in both files."; + report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. "; + report.testSummary += "The tolerance is zero for this test. In other words, the surface counts are the same, or the test fails."; + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Feb 13 2013 + + + report.unit = Units; + //assuming that this will be plenty large for now + string[] resultsArray = new string[50]; + int nodecount = 0; + for (int i = 0; i < gbXMLDocs.Count; i++) + { + nodecount = 0; + try + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + + XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface", gbXMLns); + foreach (XmlNode surfaceNode in nodes) + { + XmlAttributeCollection spaceAtts = surfaceNode.Attributes; + foreach (XmlAttribute at in spaceAtts) + { + if (at.Name == "surfaceType") + { + string type = at.Value; + if (type == "UndergroundWall") + { + nodecount++; + } + break; + } + } + } + + //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result + resultsArray[i] = nodecount.ToString(); + if (i % 2 != 0) + { + //setup standard result and test result + report.standResult.Add(resultsArray[i]); + report.testResult.Add(resultsArray[i - 1]); + report.idList.Add(""); + + double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)])); + if (difference == 0) + { + report.longMsg = "The Test File's" + report.testType + " matches the Standard File exactly, the difference is zero."; + report.passOrFail = true; + return report; + } + else if (difference <= report.tolerance) + { + report.longMsg = "The Test File's " + report.testType + " matches Standard File within the allowable tolerance, the difference between the two files is " + report.tolerance.ToString() + " " + Units; + report.passOrFail = true; + return report; + } + else + { + report.longMsg = "The Test File's " + report.testType + " does not match Standard File, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference + + ". " + resultsArray[i] + " exterior wall surfaces in the Standard File and " + resultsArray[i - 1] + " exterior wall surfaces in the Test File."; + report.passOrFail = false; + return report; + } + } + else { continue; } + + } + catch (Exception e) + { + report.MessageList.Add(e.ToString()); + report.longMsg = " Failed to locate " + report.testType + " in the XML file."; + report.passOrFail = false; + return report; + } + } + report.longMsg = "Fatal " + report.testType + " Test Failure"; + report.passOrFail = false; + return report; + } + + private DOEgbXMLReportingObj GetPossibleOpeningMatches(OpeningDefinitions standardOpening, List TestOpenings, DOEgbXMLReportingObj report) + { + report.testSummary = "This test checks the geometric accuracy of each opening in your test file against the standard file."; + report.testSummary += " For each opening (window, door, skylight) this validator seeks out a similar opening in your test file and"; + //match surfaces at this stage so we know which surface is associated with the window + report.testSummary += " The validator first seeks to find all openings that have a parent surface (roof, external wall, etc.) with"; + report.testSummary += " the same azimuth and tilt. If it finds more than one opening candidate that matches the parent surface tilt and azimuth,"; + report.testSummary += " the validator will make all of these openings possible candidates."; + report.testSummary += " The validator then takes these candidates and looks at their polyloop coordinates. "; + report.testSummary += " and will keep only those openings that have similar polyLoop coordinates"; + report.testSummary += " Next it matches the area, then the width and height, if applicable, and finally checks the insertion"; + report.testSummary += " point coordinates. If all of these come back within tolerance, the opening has found a match."; + report.testSummary += " Otherwise, the test will fail."; + report.testSummary += " The summary at the bottom of the page will show the logic of how the test arrived at its conclusion."; + + + bool matchedParentAz = false; + bool matchedParentTilt = false; + bool matchedPolyLoopCoords = false; + + List possibleMatches = new List(); + List possibleMatches2 = new List(); + try + { + //find match of parent surface + //try matching based on the surface matches + //if that does not work, then just try to match the parent tilt and parent azimuth to one another + int i = 0; + report.MessageList.Add("Starting Parent Azimuth and Tilt Match test...."); + report.MessageList.Add("
"); + while (true) + { + //reset + matchedParentAz = false; + matchedParentTilt = false; + OpeningDefinitions testOpening = TestOpenings[i]; + if (testOpening.ParentAzimuth == standardOpening.ParentAzimuth && testOpening.ParentTilt == standardOpening.ParentTilt) + { + report.MessageList.Add("Candidate Found. Test file opening has EXACTLY matched its parent surface azimuth and tilt with the standard opening parent surface azimuth and tilt."); + report.MessageList.Add("Test Opening " + testOpening.OpeningId + "'s [parent, azimuth, tilt]: [" + testOpening.ParentSurfaceId + ", " + testOpening.ParentAzimuth + ", " + testOpening.ParentTilt + "]"); + report.MessageList.Add("Standard Opening " + standardOpening.OpeningId + "'s [parent, azimuth, tilt]: [" + standardOpening.ParentSurfaceId + "," + standardOpening.ParentAzimuth + ", " + standardOpening.ParentTilt + "]"); + + matchedParentAz = true; + matchedParentTilt = true; + } + else + { + double azDifference = Math.Abs(testOpening.ParentAzimuth - standardOpening.ParentAzimuth); + double tiltDifference = Math.Abs(testOpening.ParentTilt - standardOpening.ParentTilt); + if (azDifference < DOEgbXMLBasics.Tolerances.SurfaceAzimuthTolerance && tiltDifference < DOEgbXMLBasics.Tolerances.SurfaceTiltTolerance) + { + report.MessageList.Add("Candidate found. Test file opening HAS matched WITHIN ALLOWABLE TOLERANCE its parent surface azimuth and tilt with the standard opening parent surface azimuth and tilt."); + report.MessageList.Add("Test Opening " + testOpening.OpeningId + "'s [parent, azimuth, tilt]: [" + testOpening.ParentSurfaceId + ", " + testOpening.ParentAzimuth + ", " + testOpening.ParentTilt + "]"); + report.MessageList.Add("Standard Opening " + standardOpening.OpeningId + "'s [parent, azimuth, tilt]: [" + standardOpening.ParentSurfaceId + "," + standardOpening.ParentAzimuth + ", " + standardOpening.ParentTilt + "]"); + + matchedParentAz = true; + matchedParentTilt = true; + } + else + { + report.MessageList.Add("Candidate rejected. Test file opening HAS NOT matched WITHIN ALLOWABLE TOLERANCE its parent surface azimuth and tilt with the standard opening parent surface azimuth and tilt."); + report.MessageList.Add("Test Opening " + testOpening.OpeningId + "'s [parent, azimuth, tilt]: [" + testOpening.ParentSurfaceId + ", " + testOpening.ParentAzimuth + ", " + testOpening.ParentTilt + "]"); + report.MessageList.Add("Standard Opening " + standardOpening.OpeningId + "'s [parent, azimuth, tilt]: [" + standardOpening.ParentSurfaceId + "," + standardOpening.ParentAzimuth + ", " + standardOpening.ParentTilt + "]"); + report.MessageList.Add("
"); + } + } + + if (matchedParentAz && matchedParentTilt) + { + possibleMatches.Add(testOpening); + report.MessageList.Add("Successful Match Candidate Identified."); + report.MessageList.Add("
"); + } + i++; + + if (i == TestOpenings.Count) + { + if (possibleMatches.Count == 0) + { + //no candidates found + report.MessageList.Add("No candidates found in the test file to match standard file opening " + standardOpening.OpeningId); + report.passOrFail = false; + report.longMsg = "Test to find suitable opening candidate in the test file has failed. Parent Tilt and Azimuth matches could not be established."; + //no need to go further + return report; + } + break; + } + + } + report.MessageList.Add("
"); + report.MessageList.Add("Starting Opening PolyLoop Coordinate Match test........."); + i = 0; + while (true) + { + OpeningDefinitions testOpening = possibleMatches[i]; + //continue to next test + + //continue the next batch of tests + //polyloop absolute coordinates + //check the polyLoop coordinates + foreach (Vector.CartCoord standardPolyLoopCoord in standardOpening.PlCoords) + { + report = GetOpeningPolyLoopCoordMatch(standardPolyLoopCoord, testOpening, report, standardOpening.OpeningId); + if (report.passOrFail) + { + matchedPolyLoopCoords = true; + continue; + } + else + { + report.MessageList.Add("Could not find a coordinate match in the test opening polyloop."); + matchedPolyLoopCoords = false; + break; + } + } + //if matchePolyLoopCoords comes back true, then a candidate has been found that matches all polyloop coords within tolerance + if (matchedPolyLoopCoords == true) + { + possibleMatches2.Add(testOpening); + } + i++; + + if (i == possibleMatches.Count) + { + if (possibleMatches2.Count == 0) + { + report.MessageList.Add("No candidates found in the test file to match standard file opening " + standardOpening.OpeningId); + report.passOrFail = false; + report.longMsg = "Test to find suitable opening candidate in the test file has failed. Parent Tilt and Azimuth matches were established, but these candidates did not produce good polyLoop coordinate matches."; + //no need to go further + return report; + } + break; + } + } + //next set of tests + //polyloop area tests + report.MessageList.Add("
"); + report.MessageList.Add("Starting Opening Surface Area Match test........."); + possibleMatches.Clear(); + i = 0; + while (true) + { + #region + OpeningDefinitions testOpening = possibleMatches2[i]; + + if (Math.Abs(standardOpening.PlRHRVector.X) == 1 && standardOpening.PlRHRVector.Y == 0 && standardOpening.PlRHRVector.Z == 0) + { + List coordList = new List(); + foreach (Vector.CartCoord coord in standardOpening.PlCoords) + { + //only take the Y and Z coordinates and throw out the X because we can assume that they are all the same + coord.X = 0; + coordList.Add(coord); + + } + double area = Math.Abs(GetAreaFrom2DPolyLoop(coordList)); + standardOpening.surfaceArea = area; + if (area == -999) + { + //these messages should never occur and are a sign of some sort of serious, as of yet unknown error + //March 20 2013 + report.MessageList.Add("The coordinates of the standard file polyloop has been incorrectly defined."); + report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); + report.MessageList.Add("Test may be inaccurate and requires gbXML.org support"); + report.longMsg = "Fatal error. Please contact gbXML administrator"; + report.passOrFail = false; + return report; + + } + double testOpeningArea = 0; + + if (Math.Abs(testOpening.PlRHRVector.X) == 1 && testOpening.PlRHRVector.Y == 0 && + testOpening.PlRHRVector.Z == 0) + { + List testCoordList = new List(); + foreach (Vector.CartCoord coord in testOpening.PlCoords) + { + coord.X = 0; + testCoordList.Add(coord); + } + testOpeningArea = Math.Abs(GetAreaFrom2DPolyLoop(testCoordList)); + testOpening.surfaceArea = testOpeningArea; + if (testOpeningArea == -999) + { + //these messages should never occur and are a sign of some sort of serious, as of yet unknown error + //March 20 2013 + report.MessageList.Add("The coordinates of the test file polyloop has been incorrectly defined."); + report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); + report.longMsg = "Fatal error. Please contact gbXML administrator"; + report.passOrFail = false; + return report; + } + double difference = Math.Abs(area) - Math.Abs(testOpeningArea); + if (difference < Math.Abs(area) * DOEgbXMLBasics.Tolerances.OpeningAreaPercentageTolerance) + { + + if (difference == 0) + { + //then it perfectly matches, go on to check the poly loop coordinates + //then check the insertion point + report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard opening: " + standardOpening.OpeningId + " exactly."); + possibleMatches.Add(testOpening); + } + else + { + report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard opening: " + standardOpening.OpeningId + " within the allowable area percentage tolerance."); + possibleMatches.Add(testOpening); + } + } + else + { + report.MessageList.Add("The standard file opening cannot find a match for its surface area of opening: " + standardOpening.OpeningId + " through a comparison of its polyloop coordinates with test opening: " + testOpening.OpeningId); + //don't return here, it will be returned below + } + } + else + { + //by definition, the Window opening should always use coordinates that create a normal vector that points in the + //positive or negative X direction. If the test file does not do this, then this is in violation of the + //gbXML spec + report.longMsg = ("This test has failed because the test opening" + testOpening.OpeningId + "has polyloop coordinates "); + report.longMsg += (" that do not have the same normal vector as the standard opening."); + report.passOrFail = false; + } + } + else if (standardOpening.PlRHRVector.X == 0 && Math.Abs(standardOpening.PlRHRVector.Y) == 1 && standardOpening.PlRHRVector.Z == 0) + { + List coordList = new List(); + foreach (Vector.CartCoord coord in standardOpening.PlCoords) + { + //only take the Y and Z coordinates and throw out the X because we can assume that they are all the same + coord.Y = 0; + coordList.Add(coord); + + } + double area = Math.Abs(GetAreaFrom2DPolyLoop(coordList)); + standardOpening.surfaceArea = area; + if (area == -999) + { + //these messages should never occur and are a sign of some sort of serious, as of yet unknown error + //March 20 2013 + report.MessageList.Add("The coordinates of the standard file polyloop has been incorrectly defined."); + report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); + report.MessageList.Add("Test may be inaccurate and requires gbXML.org support"); + report.longMsg = "Fatal error. Please contact gbXML administrator"; + report.passOrFail = false; + return report; + + } + double testOpeningArea = 0; + + if (testOpening.PlRHRVector.X == 0 && Math.Abs(testOpening.PlRHRVector.Y) == 1 && + testOpening.PlRHRVector.Z == 0) + { + List testCoordList = new List(); + foreach (Vector.CartCoord coord in testOpening.PlCoords) + { + coord.Y = 0; + testCoordList.Add(coord); + } + testOpeningArea = Math.Abs(GetAreaFrom2DPolyLoop(testCoordList)); + testOpening.surfaceArea = testOpeningArea; + if (testOpeningArea == -999) + { + //these messages should never occur and are a sign of some sort of serious, as of yet unknown error + //March 20 2013 + report.MessageList.Add("The coordinates of the test file polyloop has been incorrectly defined."); + report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); + report.longMsg = "Fatal error. Please contact gbXML administrator"; + report.passOrFail = false; + return report; + } + double difference = Math.Abs(area) - Math.Abs(testOpeningArea); + if (difference < Math.Abs(area) * DOEgbXMLBasics.Tolerances.OpeningAreaPercentageTolerance) + { + + if (difference == 0) + { + //then it perfectly matches, go on to check the poly loop coordinates + //then check the insertion point + report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard Opening: " + standardOpening.OpeningId + " exactly."); + possibleMatches.Add(testOpening); + } + else + { + report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard Opening: " + standardOpening.OpeningId + " within the allowable area percentage tolerance."); + possibleMatches.Add(testOpening); + } + } + else + { + report.MessageList.Add("The standard file opening cannot find a match for its surface area of Opening: " + standardOpening.OpeningId + " through a comparison of its polyloop coordinates with test Opening: " + testOpening.OpeningId); + //don't return here, it will be returned below + } + } + else + { + //by definition, the Window opening should always use coordinates that create a normal vector that points in the + //positive or negative X direction. If the test file does not do this, then this is in violation of the + //gbXML spec + report.longMsg = ("This test has failed because the test opening" + testOpening.OpeningId + "has polyloop coordinates "); + report.longMsg += (" that do not have the same normal vector as the standard opening."); + report.passOrFail = false; + } + } + else if (standardOpening.PlRHRVector.X == 0 && standardOpening.PlRHRVector.Y == 0 && Math.Abs(standardOpening.PlRHRVector.Z) == 1) + { + List coordList = new List(); + foreach (Vector.CartCoord coord in standardOpening.PlCoords) + { + //only take the X and Y coordinates and throw out the Z because we can assume that they are all the same + coord.Z = 0; + coordList.Add(coord); + + } + double area = Math.Abs(GetAreaFrom2DPolyLoop(coordList)); + standardOpening.surfaceArea = area; + if (area == -999) + { + report.MessageList.Add("The coordinates of the standard file polyloop has been incorrectly defined."); + report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); + report.MessageList.Add("Test may be inaccurate and requires gbXML.org support"); + + } + double testOpeningArea = 0; + + if (testOpening.PlRHRVector.X == 0 && testOpening.PlRHRVector.Y == 0 && + Math.Abs(testOpening.PlRHRVector.Z) == 1) + { + List testCoordList = new List(); + foreach (Vector.CartCoord coord in testOpening.PlCoords) + { + coord.Z = 0; + testCoordList.Add(coord); + } + testOpeningArea = Math.Abs(GetAreaFrom2DPolyLoop(testCoordList)); + testOpening.surfaceArea = testOpeningArea; + if (testOpeningArea == -999) + { + //these messages should never occur and are a sign of some sort of serious, as of yet unknown error + //March 20 2013 + report.MessageList.Add("The coordinates of the test file polyloop has been incorrectly defined."); + report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); + report.longMsg = "Fatal error. Please contact gbXML administrator"; + report.passOrFail = false; + return report; + } + double difference = Math.Abs(area) - Math.Abs(testOpeningArea); + if (difference < Math.Abs(area) * DOEgbXMLBasics.Tolerances.OpeningAreaPercentageTolerance) + { + + if (difference == 0) + { + //then it perfectly matches, go on to check the poly loop coordinates + //then check the insertion point + report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard Opening: " + standardOpening.OpeningId + " exactly."); + possibleMatches.Add(testOpening); + } + else + { + report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard Opening: " + standardOpening.OpeningId + " within the allowable area percentage tolerance."); + possibleMatches.Add(testOpening); + } + } + else + { + report.MessageList.Add("The standard file opening cannot find a match for its surface area of Opening: " + standardOpening.OpeningId + " through a comparison of its polyloop coordinates with test Opening: " + testOpening.OpeningId); + //don't return here, it will be returned below + } + } + else + { + //by definition, the Window opening should always use coordinates that create a normal vector that points in the + //positive or negative X direction. If the test file does not do this, then this is in violation of the + //gbXML spec + report.longMsg = ("This test has failed because the test opening" + testOpening.OpeningId + "has polyloop coordinates "); + report.longMsg += (" that do not have the same normal vector as the standard opening."); + report.passOrFail = false; + } + + } + //the opening is not aligned along a reference frame axis + else + { + report.MessageList.Add("This standard Opening is not aligned along a reference plane axis, and will be rotated into a new coordinate frame."); + report.MessageList.Add("Commencing rotation to 2-D."); + //New Z Axis for this plane is the normal vector, does not need to be created + //Get New Y Axis which is the surface Normal Vector cross the original global reference X unit vector (all unit vectors please + Vector.CartVect localY = new Vector.CartVect(); + Vector.CartVect globalReferenceX = new Vector.CartVect(); + globalReferenceX.X = 1; + globalReferenceX.Y = 0; + globalReferenceX.Z = 0; + localY = Vector.CrossProduct(standardOpening.PlRHRVector, globalReferenceX); + localY = Vector.UnitVector(localY); + + //new X axis is the localY cross the surface normal vector + Vector.CartVect localX = new Vector.CartVect(); + localX = Vector.CrossProduct(localY, standardOpening.PlRHRVector); + localX = Vector.UnitVector(localX); + + //convert the polyloop coordinates to a local 2-D reference frame + //using a trick employed by video game programmers found here http://stackoverflow.com/questions/1023948/rotate-normal-vector-onto-axis-plane + List translatedCoordinates = new List(); + Vector.CartCoord newOrigin = new Vector.CartCoord(); + newOrigin.X = 0; + newOrigin.Y = 0; + newOrigin.Z = 0; + translatedCoordinates.Add(newOrigin); + for (int j = 1; j < standardOpening.PlCoords.Count; j++) + { + //randomly assigns the first polyLoop coordinate as the origin + Vector.CartCoord origin = standardOpening.PlCoords[0]; + //captures the components of a vector drawn from the new origin to the + Vector.CartVect distance = new Vector.CartVect(); + distance.X = standardOpening.PlCoords[j].X - origin.X; + distance.Y = standardOpening.PlCoords[j].Y - origin.Y; + distance.Z = standardOpening.PlCoords[j].Z - origin.Z; + Vector.CartCoord translatedPt = new Vector.CartCoord(); + //x coordinate is distance vector dot the new local X axis + translatedPt.X = distance.X * localX.X + distance.Y * localX.Y + distance.Z * localX.Z; + //y coordinate is distance vector dot the new local Y axis + translatedPt.Y = distance.X * localY.X + distance.Y * localY.Y + distance.Z * localY.Z; + translatedPt.Z = 0; + translatedCoordinates.Add(translatedPt); + + } + double area = GetAreaFrom2DPolyLoop(translatedCoordinates); + standardOpening.surfaceArea = area; + if (area == -999) + { + report.MessageList.Add("The coordinates of the standard file polyloop has been incorrectly defined."); + report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); + report.MessageList.Add("Test may be inaccurate and requires gbXML.org support"); + + } + //get the area of the test candidates using the polyloop coordinates + Vector.CartVect testlocalY = new Vector.CartVect(); + Vector.CartVect testglobalReferenceX = new Vector.CartVect(); + globalReferenceX.X = 1; + globalReferenceX.Y = 0; + globalReferenceX.Z = 0; + testlocalY = Vector.CrossProduct(testOpening.PlRHRVector, testglobalReferenceX); + testlocalY = Vector.UnitVector(testlocalY); + + //new X axis is the localY cross the surface normal vector + Vector.CartVect testlocalX = new Vector.CartVect(); + testlocalX = Vector.CrossProduct(testlocalY, testOpening.PlRHRVector); + testlocalX = Vector.UnitVector(testlocalX); + + //convert the polyloop coordinates to a local 2-D reference frame + //using a trick employed by video game programmers found here http://stackoverflow.com/questions/1023948/rotate-normal-vector-onto-axis-plane + List testtranslatedCoordinates = new List(); + Vector.CartCoord newOriginTest = new Vector.CartCoord(); + newOrigin.X = 0; + newOrigin.Y = 0; + newOrigin.Z = 0; + testtranslatedCoordinates.Add(newOriginTest); + for (int j = 1; j < testOpening.PlCoords.Count; j++) + { + //randomly assigns the first polyLoop coordinate as the origin + Vector.CartCoord origin = testOpening.PlCoords[0]; + //captures the components of a vector drawn from the new origin to the + Vector.CartVect distance = new Vector.CartVect(); + distance.X = testOpening.PlCoords[j].X - origin.X; + distance.Y = testOpening.PlCoords[j].Y - origin.Y; + distance.Z = testOpening.PlCoords[j].Z - origin.Z; + Vector.CartCoord translatedPt = new Vector.CartCoord(); + //x coordinate is distance vector dot the new local X axis + translatedPt.X = distance.X * localX.X + distance.Y * localX.Y + distance.Z * localX.Z; + //y coordinate is distance vector dot the new local Y axis + translatedPt.Y = distance.X * localY.X + distance.Y * localY.Y + distance.Z * localY.Z; + translatedPt.Z = 0; + testtranslatedCoordinates.Add(translatedPt); + + } + double testOpeningArea = GetAreaFrom2DPolyLoop(translatedCoordinates); + testOpening.surfaceArea = testOpeningArea; + if (testOpeningArea == -999) + { + report.MessageList.Add("The coordinates of the test file polyloop has been incorrectly defined."); + report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); + } + double difference = Math.Abs(area) - Math.Abs(testOpeningArea); + if (difference < Math.Abs(area) * DOEgbXMLBasics.Tolerances.OpeningAreaPercentageTolerance) + { + + if (difference == 0) + { + //then it perfectly matches, go on to check the poly loop coordinates + //then check the insertion point + report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard Opening: " + standardOpening.OpeningId + " exactly."); + possibleMatches.Add(testOpening); + } + else + { + report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " polyloop surface area matches the polyLoop surface area of the standard Opening: " + standardOpening.OpeningId + " within the allowable area percentage tolerance."); + possibleMatches.Add(testOpening); + } + } + else + { + report.MessageList.Add("The standard file opening cannot find a match for its surface area of Opening: " + standardOpening.OpeningId + " through a comparison of its polyloop coordinates with test Opening: " + testOpening.OpeningId); + //don't return here, it will be returned below + } + + } + i++; + if (i == possibleMatches2.Count) + { + if (possibleMatches.Count == 0) + { + report.MessageList.Add("No area match could be found for standard opening: " + standardOpening.OpeningId + "."); + report.longMsg = "The search routine has ended and could not find a match for opening: " + standardOpening.OpeningId + + ". Attempt to match the area of the standard file with test file openings failed."; + return report; + + } + else + { + //you are good to go with some more matches + report.MessageList.Add("Area matching SUCCESS for standard file Opening id: " + standardOpening.OpeningId); + report.MessageList.Add("Commencing comparisons of height, width, and insertion point."); + break; + } + } + + #endregion + } + //test the width and height, if applicable + report.MessageList.Add("
"); + report.MessageList.Add("Starting Width and Height Match test........."); + possibleMatches2.Clear(); + i = 0; + //surface area using the coordinates of the polyloop. We already assume that they are planar, as previously tested + while (true) + { + //see if the openings are regular + bool isStandardRegular = IsOpeningRegular(standardOpening); + bool isTestRegular = IsOpeningRegular(possibleMatches[i]); + //if they are...go ahead and use width and height, otherwise the values are not reliable + if (isStandardRegular) + { + //output something + if (isTestRegular) + { + //output something + //perform tests + + OpeningDefinitions testOpening = possibleMatches[i]; + double testWidth = testOpening.Width; + double standardWidth = standardOpening.Width; + double testHeight = testOpening.Height; + double standardHeight = standardOpening.Height; + double widthDifference = Math.Abs(testWidth - standardWidth); + double heightDiffefence = Math.Abs(testHeight - standardHeight); + + if (widthDifference <= DOEgbXMLBasics.Tolerances.OpeningWidthTolerance) + { + if (widthDifference == 0) + { + report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " reported Width value matches the Width value of the standard Opening: " + standardOpening.OpeningId + " exactly."); + } + else + { + report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " reported Width value matches the Width value of the standard Opening: " + standardOpening.OpeningId + " within the allowable tolerance."); + } + //check the height + if (heightDiffefence <= DOEgbXMLBasics.Tolerances.OpeningHeightTolerance) + { + if (heightDiffefence == 0) + { + report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " reported Height value matches the Height value of the standard Opening: " + standardOpening.OpeningId + " exactly."); + possibleMatches2.Add(testOpening); + } + else + { + report.MessageList.Add("The test Opening: " + testOpening.OpeningId + " reported Height value matches the Height value of the standard Opening: " + standardOpening.OpeningId + " within the allowable tolerance."); + possibleMatches2.Add(testOpening); + } + } + else + { + //fail, did not match height + report.MessageList.Add("The standard file Opening: " + standardOpening.OpeningId + "The standard file opening cannot find a match for its surface area of Opening: " + standardOpening.OpeningId + " after comparison its Height value with test opening: " + testOpening.OpeningId); + report.passOrFail = false; + continue; + } + } + else + { + //failed, did not match width + report.MessageList.Add("The standard file Opening: " + standardOpening.OpeningId + " cannot find a match for its width after comparison the width value of test Opening: " + testOpening.OpeningId); + report.passOrFail = false; + continue; + } + } + else + { + //let them know the the test opening is not a square or rectangle, but the standard file opening is + //go ahead and break out of the while loop because we aren't testing for width and height + report.MessageList.Add("The standard file Opening: " + standardOpening.OpeningId + " is a rectangle or square, but the test file Opening: " + standardOpening.OpeningId + " is not. Cannot test for a valid width and height."); + report.MessageList.Add("Searching for another test Opening."); + continue; + } + } + else + { + //tell them that the widths and Heights will Not be checked + //because the standard file opening is not a square or rectangle + report.MessageList.Add("Will not be testing for the Width and Height values for standard Opening: " + standardOpening.OpeningId + ". The Opening is not shaped like a rectangle or square."); + report.MessageList.Add("Going on to check insertion point accuracy."); + //needed to transfer values over to possibleMatches2, so deep copy + possibleMatches2 = new List(possibleMatches); + break; + } + i++; + if (possibleMatches.Count == i) + { + //means that there is no match for width and height + if (possibleMatches2.Count == 0) + { + report.MessageList.Add("There is no match found for the width and height for Opening: " + standardOpening.OpeningId); + report.passOrFail = false; + report.longMsg = "The opening test has ended at the search for width and height values equal to standard Opening: " + standardOpening.OpeningId; + return report; + } + break; + } + + } + report.MessageList.Add("
"); + report.MessageList.Add("Starting Insertion Point Coordinate Match test........."); + possibleMatches.Clear(); + //test the insertion point coordinates + i = 0; + while (true) + { + OpeningDefinitions testOpening = possibleMatches2[i]; + double diffX = Math.Abs(testOpening.InsertionPoint.X - standardOpening.InsertionPoint.X); + double diffY = Math.Abs(testOpening.InsertionPoint.Y - standardOpening.InsertionPoint.Y); + double diffZ = Math.Abs(testOpening.InsertionPoint.Z - standardOpening.InsertionPoint.Z); + + if (diffX <= DOEgbXMLBasics.Tolerances.OpeningSurfaceInsPtXTolerance && diffY <= DOEgbXMLBasics.Tolerances.OpeningSurfaceInsPtYTolerance && + diffZ <= DOEgbXMLBasics.Tolerances.OpeningSurfaceInsPtZTolerance) + { + if (diffX == 0) + { + //perfect X coordinate match + report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a perfect match for its insertion point X-Coordinate when compared with test Opening: " + testOpening.OpeningId); + if (diffY == 0) + { + //perfect Y coordinate match + report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a perfect match for its insertion point Y-Coordinate when compared with test Opening: " + testOpening.OpeningId); + if (diffZ == 0) + { + //perfect Z coordinate match + report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a perfect match for its insertion point Z-Coordinate when compared with test Opening: " + testOpening.OpeningId); + possibleMatches.Add(testOpening); + + } + else + { + // Z coordinate match + report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a match within allowable tolerances for its insertion point Z-Coordinate when compared with Test opening: " + testOpening.OpeningId); + //we continue because we search for other matches if there are any + possibleMatches.Add(testOpening); + + } + } + else + { + //y-coordinate is within tolerance + report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a match within allowable tolerances for its insertion point Y-Coordinate when compared with Test opening: " + testOpening.OpeningId); + if (diffZ == 0) + { + //perfect Z coordinate match + report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a perfect match for its insertion point Z-Coordinate when compared with Test opening: " + testOpening.OpeningId); + possibleMatches.Add(testOpening); + + } + else + { + //perfect Z coordinate match + report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a match within allowable tolerances for its insertion point Z-Coordinate when compared with test Opening: " + testOpening.OpeningId); + //we continue because we search for other matches if there are any + possibleMatches.Add(testOpening); + + } + } + + } + // X is within tolerance + else + { + report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a match within allowable tolerances for its insertion point X-Coordinate when compared with test Opening: " + testOpening.OpeningId); + if (diffY == 0) + { + //perfect Y coordinate match + report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a perfect match for its insertion point Y-Coordinate when compared with test Opening: " + testOpening.OpeningId); + if (diffZ == 0) + { + //perfect Z coordinate match + report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a perfect match for its insertion point Z-Coordinate when compared with test Opening: " + testOpening.OpeningId); + possibleMatches.Add(testOpening); + + } + else + { + //perfect Z coordinate match + report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a match within allowable tolerances for its insertion point Z-Coordinate when compared with test Opening: " + testOpening.OpeningId); + //we continue because we search for other matches if there are any + possibleMatches.Add(testOpening); + + } + } + else + { + //y-coordinate is within tolerance + report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a match within allowable tolerances for its insertion point Y-Coordinate when compared with test Opening: " + testOpening.OpeningId); + if (diffZ == 0) + { + //perfect Z coordinate match + report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a perfect match for its insertion point Z-Coordinate when compared with test Opening: " + testOpening.OpeningId); + possibleMatches.Add(testOpening); + + } + else + { + //perfect Z coordinate match + report.MessageList.Add("Standard Opening: " + standardOpening.OpeningId + " has found a match within allowable tolerances for its insertion point Z-Coordinate when compared with test Opening: " + testOpening.OpeningId); + //we continue because we search for other matches if there are any + possibleMatches.Add(testOpening); + + } + } + } + } + report.MessageList.Add("Standard Opening Ins Pt: (" + standardOpening.InsertionPoint.X.ToString() + "," + standardOpening.InsertionPoint.Y.ToString() + "," + standardOpening.InsertionPoint.Z.ToString() + ")"); + report.MessageList.Add("Test File Opening Ins Pt: (" + testOpening.InsertionPoint.X.ToString() + "," + testOpening.InsertionPoint.Y.ToString() + "," + testOpening.InsertionPoint.Z.ToString() + ")"); + i++; + if (possibleMatches2.Count == i) + { + if (possibleMatches.Count == 1) + { + List openingMatch = new List(); + openingMatch.Add(possibleMatches[0].OpeningId); + report.MessageList.Add("Standard file Opening: " + standardOpening.OpeningId + " is matched to test file Opening: " + testOpening.OpeningId); + globalMatchObject.MatchedOpeningIds.Add(standardOpening.OpeningId, openingMatch); + report.passOrFail = true; + return report; + } + else + { + if (possibleMatches.Count == 0) + { + report.MessageList.Add("Standard file Opening: " + standardOpening.OpeningId + " found no match for insertion point in the test file of the remaining candidates."); + report.passOrFail = false; + return report; + } + else + { + report.MessageList.Add("Standard file Opening: " + standardOpening.OpeningId + " is matched to multiple openings:"); + foreach (OpeningDefinitions opening in possibleMatches) + { + report.MessageList.Add("Test Opening:" + opening.OpeningId + "matched insertion point"); + } + //resolve by trying to match to the standard opening and test opening parent surfaces. + //for the standard opening + if (globalMatchObject.MatchedSurfaceIds.ContainsKey(standardOpening.ParentSurfaceId)) + { + List possibleSurfaceMatches = globalMatchObject.MatchedSurfaceIds[standardOpening.ParentSurfaceId]; + if (possibleSurfaceMatches.Count == 1) + { + //then a match was found originally during get possible surface matches. That is good, we only want one + foreach (OpeningDefinitions openingRemaining in possibleMatches) + { + if (openingRemaining.ParentSurfaceId == possibleSurfaceMatches[0]) + { + //this is the match we want + //else we would have to continue + report.MessageList.Add("The test Opening: " + openingRemaining.OpeningId + " has been matched to the standard Opening: " + standardOpening.OpeningId + + ". Their parent surface ids have been matched. Thus the conflict has been resolved. (Standard opening parent surface Id, test opening parent surface Id" + standardOpening.ParentSurfaceId + "," + openingRemaining.ParentSurfaceId); + report.passOrFail = true; + List openingMatch = new List(); + openingMatch.Add(possibleMatches[0].OpeningId); + globalMatchObject.MatchedOpeningIds.Add(standardOpening.OpeningId, openingMatch); + return report; + } + else + { + //do nothing. Maybe report that the parent Surface Id does not match the standard Opening + report.MessageList.Add("Test Opening:" + openingRemaining.OpeningId + " does not match the standard Opening: " + standardOpening.OpeningId + + ". Their parent surface ids do not coincide. (Standard Opening parent surface id, test Opening parent surface id)" + standardOpening.ParentSurfaceId + "," + openingRemaining.ParentSurfaceId); + } + } + } + } + report.passOrFail = false; + return report; + } + } + } + + } + + //finished + + } + catch (Exception e) + { + report.longMsg = e.ToString(); + } + return report; + } + + private List GetFileOpeningDefs(XmlDocument TestFile, XmlNamespaceManager TestNSM) + { + List openings = new List(); + try + { + + XmlNodeList nodes = TestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface/gbXMLv5:Opening", TestNSM); + foreach (XmlNode openingNode in nodes) + { + //initialize a new instance of the class + OpeningDefinitions openingDef = new OpeningDefinitions(); + + openingDef.PlCoords = new List(); + openingDef.InsertionPoint = new Vector.CartCoord(); + openingDef.PlRHRVector = new Vector.CartVect(); + + //get parent id + XmlAttributeCollection parentSurfaceAttributes = openingNode.ParentNode.Attributes; + foreach (XmlAttribute parentAt in parentSurfaceAttributes) + { + if (parentAt.Name == "id") + { + openingDef.ParentSurfaceId = parentAt.Value; + break; + } + } + //get Parent Azimuth and Tilt + XmlNode surfaceParentNode = openingNode.ParentNode; + if (surfaceParentNode.HasChildNodes) + { + XmlNodeList surfaceParentNodesChillun = surfaceParentNode.ChildNodes; + foreach (XmlNode chileNode in surfaceParentNodesChillun) + { + if (chileNode.Name == "RectangularGeometry") + { + if (chileNode.HasChildNodes) + { + foreach (XmlNode grandchileNode in chileNode) + { + if (grandchileNode.Name == "Tilt") { openingDef.ParentTilt = Convert.ToDouble(grandchileNode.InnerText); } + else if (grandchileNode.Name == "Azimuth") { openingDef.ParentAzimuth = Convert.ToDouble(grandchileNode.InnerText); } + } + } + } + } + } + else + { + + } + //get surface Id and Opening Type + XmlAttributeCollection openingAtts = openingNode.Attributes; + foreach (XmlAttribute at in openingAtts) + { + if (at.Name == "id") + { + openingDef.OpeningId = at.Value; + } + else if (at.Name == "openingType") + { + openingDef.OpeningType = at.Value; + } + } + if (openingNode.HasChildNodes) + { + XmlNodeList surfChildNodes = openingNode.ChildNodes; + foreach (XmlNode node in surfChildNodes) + { + + if (node.Name == "RectangularGeometry") + { + if (node.HasChildNodes) + { + XmlNodeList rectGeomChildren = node.ChildNodes; + foreach (XmlNode rgChildNode in rectGeomChildren) + { + if (rgChildNode.Name == "Azimuth") { openingDef.Azimuth = Convert.ToDouble(rgChildNode.InnerText); } + else if (rgChildNode.Name == "CartesianPoint") + { + if (rgChildNode.HasChildNodes) + { + XmlNodeList coordinates = rgChildNode.ChildNodes; + int pointCount = 1; + foreach (XmlNode coordinate in coordinates) + { + switch (pointCount) + { + case 1: + openingDef.InsertionPoint.X = Convert.ToDouble(coordinate.InnerText); + break; + case 2: + openingDef.InsertionPoint.Y = Convert.ToDouble(coordinate.InnerText); + break; + case 3: + openingDef.InsertionPoint.Z = Convert.ToDouble(coordinate.InnerText); + break; + } + pointCount++; + } + } + } + else if (rgChildNode.Name == "Tilt") { openingDef.Tilt = Convert.ToDouble(rgChildNode.InnerText); } + else if (rgChildNode.Name == "Height") { openingDef.Height = Convert.ToDouble(rgChildNode.InnerText); } + else if (rgChildNode.Name == "Width") { openingDef.Width = Convert.ToDouble(rgChildNode.InnerText); } + } + } + } + else if (node.Name == "PlanarGeometry") + { + XmlNode polyLoop = node.FirstChild; + if (polyLoop.HasChildNodes) + { + XmlNodeList cartesianPoints = polyLoop.ChildNodes; + foreach (XmlNode coordinatePt in cartesianPoints) + { + Vector.CartCoord coord = new Vector.CartCoord(); + if (coordinatePt.HasChildNodes) + { + XmlNodeList coordinates = coordinatePt.ChildNodes; + int pointCount = 1; + foreach (XmlNode coordinate in coordinatePt) + { + + switch (pointCount) + { + case 1: + coord.X = Convert.ToDouble(coordinate.InnerText); + break; + case 2: + coord.Y = Convert.ToDouble(coordinate.InnerText); + break; + case 3: + coord.Z = Convert.ToDouble(coordinate.InnerText); + break; + } + pointCount++; + } + openingDef.PlCoords.Add(coord); + } + } + } + } + } + } + Vector.CartVect plRHRVect = GetPLRHR(openingDef.PlCoords); + openingDef.PlRHRVector = plRHRVect; + //may want to forego the above since the orientation is embedded in the parent object. It may be smarter to just include the azimuth and tilt of the parent object? + openings.Add(openingDef); + } + + return openings; + } + catch (Exception e) + { + return openings; + } + } + + private DOEgbXMLReportingObj TestSurfacePlanarTest(List TestSurfaces, DOEgbXMLReportingObj report) + { + //ensure that each set of RHR tests result in parallel or anti-parallel resultant vectors, or else fail the test + + foreach (SurfaceDefinitions ts in TestSurfaces) + { + Dictionary> surfaceXProducts = new Dictionary>(); + List xProducts = new List(); + for (int i = 0; i < ts.PlCoords.Count - 2; i++) + { + //Get the Cross Product + VectorMath.Vector.CartVect v1 = VectorMath.Vector.CreateVector(ts.PlCoords[i], ts.PlCoords[i + 1]); + VectorMath.Vector.CartVect v2 = VectorMath.Vector.CreateVector(ts.PlCoords[i + 1], ts.PlCoords[i + 2]); + Vector.CartVect xProd = Vector.CrossProduct(v1, v2); + xProd = Vector.UnitVector(xProd); + xProducts.Add(xProd); + } + surfaceXProducts.Add(ts.SurfaceId, xProducts); + for (int j = 0; j < xProducts.Count - 1; j++) + { + //parallel and anti parallel + if (xProducts[j].X == xProducts[j + 1].X && xProducts[j].Y == xProducts[j + 1].Y && xProducts[j].Z == xProducts[j + 1].Z) + { + continue; + } + //anti-parallel + else if (xProducts[j].X == -1 * xProducts[j + 1].X && xProducts[j].Y == -1 * xProducts[j + 1].Y && xProducts[j].Z == -1 * xProducts[j + 1].Z) + { + continue; + } + else if (Math.Abs(xProducts[j].X) - Math.Abs(xProducts[j + 1].X) < .0001 && Math.Abs(xProducts[j].Y) - Math.Abs(xProducts[j + 1].Y) < .0001 && + Math.Abs(xProducts[j].Z) - Math.Abs(xProducts[j + 1].Z) < 0.0001) + { + continue; + } + else + { + report.MessageList.Add("Test file's Surface, id: " + ts.SurfaceId + " has polyLoop coordinates that do not form a planar surface. This fails the detailed surface tests and will not continue."); + report.passOrFail = false; + report.longMsg = "Detailed surface test failed during the planar surface checks. Without planar surfaces, this test cannot be safely executed."; + return report; + } + } + } + report.MessageList.Add("All test file's surfaces have polyloop descriptions that describe a planar surface. Planar surface test succeeded."); + report.passOrFail = true; + return report; + + } + + private DOEgbXMLReportingObj TestOpeningPlanarTest(List TestOpenings, DOEgbXMLReportingObj report) + { + //ensure that each set of RHR tests result in parallel or anti-parallel resultant vectors, or else fail the test + + foreach (OpeningDefinitions to in TestOpenings) + { + Dictionary> surfaceXProducts = new Dictionary>(); + List xProducts = new List(); + for (int i = 0; i < to.PlCoords.Count - 2; i++) + { + //Get the Cross Product + VectorMath.Vector.CartVect v1 = VectorMath.Vector.CreateVector(to.PlCoords[i], to.PlCoords[i + 1]); + VectorMath.Vector.CartVect v2 = VectorMath.Vector.CreateVector(to.PlCoords[i + 1], to.PlCoords[i + 2]); + Vector.CartVect xProd = Vector.CrossProduct(v1, v2); + xProd = Vector.UnitVector(xProd); + xProducts.Add(xProd); + } + surfaceXProducts.Add(to.OpeningId, xProducts); + for (int j = 0; j < xProducts.Count - 1; j++) + { + //parallel + if (xProducts[j].X == xProducts[j + 1].X && xProducts[j].Y == xProducts[j + 1].Y && xProducts[j].Z == xProducts[j + 1].Z) + { + continue; + } + //anti-parallel + else if (xProducts[j].X == -1 * xProducts[j + 1].X && xProducts[j].Y == -1 * xProducts[j + 1].Y && xProducts[j].Z == -1 * xProducts[j + 1].Z) + { + continue; + } + else + { + report.MessageList.Add("Test file's Opening, id: " + to.OpeningId + + " has polyLoop coordinates that do not form a planar surface. This fails the detailed surface tests and will not continue."); + report.passOrFail = false; + report.longMsg = "Detailed opening test failed during the planar surface checks. Without planar polygons, this test cannot be safely executed."; + return report; + } + } + } + report.MessageList.Add("All test file's surfaces have polyloop descriptions that describe a plana polygon. Planar opening test succeeded."); + report.passOrFail = true; + return report; + + } + + public static DOEgbXMLReportingObj GetBuildingArea(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, Conversions.areaUnitEnum standardUnits,Conversions.areaUnitEnum testUnits, double conversion) + { + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Feb 13 2013 + report.testSummary = "This test compares the values stored in the Building Area node of the standard and test gbXML files."; + report.testSummary += " This Building area is the sum total of the areas of all spaces created in gbXML."; + report.testSummary += " For example, if a small building has five spaces of area = 100 square feet each, then the sum of that area is"; + report.testSummary += " 5 x 100 = 500 square feet. The building area value would be 500 square feet."; + report.testSummary += " We have built a tolerance in this test, meaning the building areas do not need to match perfectly in the"; + report.testSummary += " standard file and test file. As long as your test file's value for Building Area is +/- this tolerance, the"; + report.testSummary += " test will pass. Using the previous example, if the allowable tolerance is 1% (1% of 500 is 5 sf), then the test file may have a building area ranging from 495 to 505 square feet, and will still be declared to pass this test."; + + report.unit = standardUnits.ToString(); + string testUOM = testUnits.ToString(); + //assuming that this will be plenty large for now + string[] resultsArray = new string[50]; + for (int i = 0; i < gbXMLDocs.Count; i++) + { + try + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + + var node = gbXMLDocs[i].SelectSingleNode("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Area", gbXMLnsm[i]); + string area = node.InnerText; + //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result + resultsArray[i] = area; + if (i % 2 != 0) + { + //setup standard result and test result + if(conversion != 1) { report.MessageList.Add("Converted the test file from " + testUOM + " to " + report.unit + "."); } + //apply the conversion factor on the test file always, regardless. + double standardArea = Convert.ToDouble(resultsArray[i]); + double testArea = Convert.ToDouble(resultsArray[(i - 1)]) * conversion; + report.standResult.Add(String.Format("{0:#,0.00}", standardArea.ToString())); + report.testResult.Add(String.Format("{0:#,0.00}", testArea.ToString())); + report.idList.Add(""); + + + double difference = standardArea - testArea; + if (Math.Abs(difference) == 0) + { + report.longMsg = "The test file's " + report.testType + "matches the standard file Building Area exactly."; + report.passOrFail = true; + return report; + } + + else if (Math.Abs(difference) <= report.tolerance) + { + report.longMsg = "The test file's " + report.testType + " is within the allowable tolerance of = " + report.tolerance.ToString() + " " + report.unit; + report.passOrFail = true; + return report; + } + else + { + report.longMsg = "The test file's " + report.testType + " is not within the allowable tolerance of " + report.tolerance.ToString() + " " + report.unit + "The difference between the standard and test file is " + difference.ToString() + "."; + report.passOrFail = false; + return report; + } + } + else { continue; } + } + catch (Exception e) + { + report.MessageList.Add(e.ToString()); + report.longMsg = " Failed to locate " + report.testType + " in the XML file."; + report.passOrFail = false; + return report; + } + } + report.longMsg = "Fatal " + report.testType + " Test Failure"; + report.passOrFail = false; + return report; + } + + public static DOEgbXMLReportingObj GetBuildingSpaceCount(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units) + { + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Feb 13 2013 + report.testSummary = "This test compares the number of spaces (it counts them) in the standard and test files. It does this"; + report.testSummary = " by counting the number of occurrences of the Space element in the gbXML files. The number of spaces should"; + report.testSummary = " match exactly. If you test has failed, this is because it is required that the space count match. If the number"; + report.testSummary = " of spaces does not match, there could be a number of reasons for this, but most likely, the test file has"; + report.testSummary = " not been constructed as per the instructions provided by the gbXML Test Case Manual."; + + report.unit = Units; + //assuming that this will be plenty large for now + string[] resultsArray = new string[50]; + for (int i = 0; i < gbXMLDocs.Count; i++) + { + try + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + + XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Space", gbXMLns); + int nodecount = nodes.Count; + //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result + resultsArray[i] = nodecount.ToString(); + if (i % 2 != 0) + { + //setup standard result and test result + report.standResult.Add(resultsArray[i]); + report.testResult.Add(resultsArray[i - 1]); + report.idList.Add(""); + + double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)])); + if (difference == 0) + { + report.longMsg = " The test file's " + report.testType + " matches the standard file exactly."; + report.passOrFail = true; + return report; + } + else if (difference <= report.tolerance) + { + report.longMsg = " The test file's " + report.testType + " matches the standard file " + report.testType + ", the difference was within tolerance = " + report.tolerance.ToString() + " " + Units; + report.passOrFail = true; + return report; + } + else + { + report.longMsg = "The test file's " + report.testType + " is not within the allowable tolerance of " + report.tolerance.ToString() + " " + Units + " The difference between the standard and test file is " + difference.ToString() + " " + Units; + report.passOrFail = false; + return report; + } + } + else { continue; } + } + catch (Exception e) + { + report.MessageList.Add(e.ToString()); + report.longMsg = " Failed to locate Building " + report.testType + " in the XML file."; + report.passOrFail = false; + return report; + } + } + report.longMsg = "Fatal " + report.testType + " Test Failure"; + report.passOrFail = false; + return report; + } + + public static DOEgbXMLReportingObj GetBuildingStoryCount(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units) + { + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Feb 13 2013 + report.testSummary = "This test compares the number of stories (it counts them) in the standard and test files. It does so by"; + report.testSummary += " counting the number of occurances of a Building Storey element in the gbXML files."; + report.testSummary += " The number of stories should match exactly. If your test failed, the number of stories in your file does"; + report.testSummary += " not match the standard file. If the number of stories does not match, "; + report.testSummary += " most likely, the test file has not been constructed as per the instructions provided by the"; + report.testSummary += " gbXML Test Case Manual."; + report.testSummary += " In some instances, it is not required that the number of stories match. If you notice that the number"; + report.testSummary += " of stories do not match, but the test summary showed your file passed, then this is normal. Refer to the pass/fail"; + report.testSummary += " summary sheet for more information."; + + report.unit = Units; + + //assuming that this will be plenty large for now + string[] resultsArray = new string[50]; + for (int i = 0; i < gbXMLDocs.Count; i++) + { + try + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + + XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:BuildingStorey", gbXMLns); + int nodecount = nodes.Count; + //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result + resultsArray[i] = nodecount.ToString(); + if (i % 2 != 0) + { + //setup standard result and test result + report.standResult.Add(resultsArray[i]); + report.testResult.Add(resultsArray[i - 1]); + report.idList.Add(""); + + double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)])); + if (difference == 0) + { + report.longMsg = " The test file's " + report.testType + " matches the standard file exactly."; + report.passOrFail = true; + return report; + } + else if (difference <= report.tolerance) + { + report.longMsg = " The test file's " + report.testType + " matches the standard file " + report.testType + ", the difference was within tolerance = " + report.tolerance.ToString() + " " + Units; + report.passOrFail = true; + return report; + } + else + { + report.longMsg = "The test file's " + report.testType + " is not within the allowable tolerance of " + report.tolerance.ToString() + " " + Units + " The difference between the standard and test file is " + difference.ToString() + " " + Units; + report.passOrFail = false; + return report; + } + } + else { continue; } + } + catch (Exception e) + { + report.MessageList.Add(e.ToString()); + report.longMsg += " Failed to locate Building " + report.testType + " in the XML file."; + return report; + } + } + report.longMsg = "Fatal " + report.testType + " Test Failure"; + return report; + } + + public static DOEgbXMLReportingObj GetStoryHeights(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, Conversions.lengthUnitEnum standardLength, Conversions.lengthUnitEnum testLength, double conversion) + { + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added March 14 2013 + report.testSummary = "This test compares Z-coordinates in each one of the levels of the standard and test file. It does so by"; + report.testSummary += " gathering the Z-coordinate of a Building Storey element's PolyLoop in the gbXML files."; + report.testSummary += " The z-heights should match exactly. If this test has failed, then one of the z-heights in your file does"; + report.testSummary += " not match the standard file. There is no tolerance for error in this test. If any of the z-heights do not match, "; + report.testSummary += " most likely, the test file has not been constructed as per the instructions provided by the"; + report.testSummary += " gbXML Test Case Manual."; + report.testSummary += " In some instances, it is not required that the z-heights match. If you notice that this test has failed"; + report.testSummary += " but your file overall has still passed, then this is as designed. Refer to the pass/fail"; + report.testSummary += " summary sheet for more information."; + + report.unit = standardLength.ToString(); + string testUOM = testLength.ToString(); + //small dictionaries I make to keep track of the story level names and heights + //standard file + Dictionary standardStoryHeight = new Dictionary(); + //Test File + Dictionary testStoryHeight = new Dictionary(); + string key = null; + string val = null; + string standLevel = ""; + + + for (int i = 0; i < gbXMLDocs.Count; i++) + { + try + { + //assuming that this will be plenty large for now + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:BuildingStorey", gbXMLns); + int nodecount = nodes.Count; + foreach (XmlNode node in nodes) + { + XmlNodeList childNodes = node.ChildNodes; + foreach (XmlNode childNode in childNodes) + { + if (childNode.Name.ToString() == "Level") { key = childNode.InnerText; } + else if (childNode.Name.ToString() == "Name") { val = childNode.InnerText; } + else { continue; } + if (i % 2 != 0) + { + if (key != null && val != null) + { + double testlevelvalue = Convert.ToDouble(val) * conversion; + testStoryHeight.Add(key, testlevelvalue); + key = null; + val = null; + } + else + { + + } + } + else + { + if (key != null && val != null) + { + double standardlevelvalue = Convert.ToDouble(val); + standardStoryHeight.Add(key, standardlevelvalue); + key = null; + val = null; + } + else + { + + } + } + } + } + + //reporting + if (i % 2 != 0) + { + if (standardStoryHeight.Count == 0) + { + report.longMsg = "Test cannot be completed. Standard File Level Count returns Zero."; + report.passOrFail = false; + return report; + } + else if (testStoryHeight.Count == 0) + { + report.longMsg = "Test cannot be completed. Test File Level Count returns Zero."; + report.passOrFail = false; + return report; + } + else + { + //set pass to true + report.passOrFail = true; + int count = 0; + foreach (KeyValuePair standardPair2 in standardStoryHeight) + { + count++; + double difference; + StoryHeightMin = 10000; + string equivLevel = ""; + if (testStoryHeight.ContainsKey(standardPair2.Key)) + { + double matchkeydiff = Math.Abs(standardPair2.Value - testStoryHeight[standardPair2.Key]); + if(matchkeydiff == 0) + { + report.MessageList.Add("Matched Standard File's " + standardPair2.Value + " with Test File's " + testStoryHeight[standardPair2.Key] + " @ " + standardPair2.Key + report.unit + " Exactly"); + report.TestPassedDict.Add(standardPair2.Value.ToString(), true); + continue; + } + else if(matchkeydiff < report.tolerance) + { + report.MessageList.Add("Matched Standard File's " + standardPair2.Value + " with Test File's " + testStoryHeight[standardPair2.Key] + " @ " + standardPair2.Key + report.unit + " within allowable tolerance."); + report.TestPassedDict.Add(standardPair2.Value.ToString(), true); + continue; + } + else + { + report.MessageList.Add("Did NOT Match Standard File's " + standardPair2.Value + " with Test File's " + testStoryHeight[standardPair2.Key] + " @ " + standardPair2.Key + report.unit + " within allowable tolerance."); + report.TestPassedDict.Add(standardPair2.Value.ToString(), true); + continue; + } + + } + foreach (KeyValuePair testPair in testStoryHeight) + { + //setup standard result and test result + + report.standResult.Add(standardPair2.Key); + report.testResult.Add(testPair.Key); + report.idList.Add(Convert.ToString(count)); + + difference = Math.Abs(Convert.ToDouble(standardPair2.Key) - Convert.ToDouble(testPair.Key)*conversion); + //store all levels and the difference between them + if (StoryHeightMin > difference) + { + StoryHeightMin = difference; + standLevel = standardPair2.Value.ToString(); + } + } + if (StoryHeightMin < report.tolerance) + { + report.MessageList.Add("Matched Standard File's " + standardPair2.Value + " @ " + standardPair2.Key + report.unit + " within the Tolerance allowed"); + report.TestPassedDict.Add(standLevel, true); + } + else + { + report.MessageList.Add("Standard File's " + standardPair2.Value + " equivalent was not found in the test file. The closest level in the test file was found at " + equivLevel + " in the test file. The difference in heights was " + StoryHeightMin.ToString() + report.unit); + report.TestPassedDict.Add(standLevel, false); + } + + } + return report; + } + } + } + + catch (Exception e) + { + report.longMsg = e.ToString(); + report.MessageList.Add(" Failed to locate Building " + report.testType + " in the XML file."); + report.passOrFail = false; + return report; + } + + } + report.longMsg = "Fatal " + report.testType + " Test Failure"; + report.passOrFail = false; + return report; + } + + public static DOEgbXMLReportingObj TestBuildingStoryRHR(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units) + { + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Feb 13 2013 + report.testSummary = "This test analyzes each of the story PolyLoop coordinates in the standard and test files. These PolyLoop "; + report.testSummary += "coordinates define the z-height and orientation of each story plane. This test analyzes the normal vector "; + report.testSummary += "created by the PolyLoop coordinates. The PolyLoop coordinates must be sequenced in a counterclockwise manner "; + report.testSummary += " such that when the right hand rule is applied to this sequence of coordinates, a resultant normal vector "; + report.testSummary += " will point in the +z direction."; + report.testSummary += " If the PolyLoop coordinates do not form vectors that point in the +Z direction"; + report.testSummary += " (when the right hand rule is applied), then this test will fail. It is assumed that the vectors that define"; + report.testSummary += " the story plane will be parallel to the X-Y axis.The tolerance is always zero for this test, "; + report.testSummary += "meaning the resulting unit vector will point in the positive Z direction with no margin for error."; + + report.unit = Units; + + //stores the level's z heights + List LevelZs = new List(); + //stores the list of z heights for both files + List> fileLevelZz = new List>(); + //stores the RHR x product and the corresonding z height for a level + Dictionary levelVct = new Dictionary(); + //stores a list of the RHR x product and corresponding z height for both files + List> fileLevelVct = new List>(); + + VectorMath.Vector.CartVect vector = new VectorMath.Vector.CartVect(); + + int errorCount = 0; + for (int i = 0; i < gbXMLDocs.Count; i++) + { + + + try + { + //refresh + LevelZs.Clear(); + levelVct.Clear(); + + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + //maybe it would be good if the test result spits out the name of the story? TBD + XmlNodeList PlanarGeometry = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:BuildingStorey/gbXMLv5:PlanarGeometry", gbXMLns); + XmlNodeList PolyLoops = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:BuildingStorey/gbXMLv5:PlanarGeometry/gbXMLv5:PolyLoop", gbXMLns); + int nodecount = PolyLoops.Count; + //get the normals for each level in the Standard File + //get the z-coordinate for each level (we assume that the levels are going to be parallel to Z + LevelZs = GetLevelZs(PlanarGeometry, LevelZs); + foreach (string level in LevelZs) + { + //a simple attempt to filter out exceptions, which could be returned in some instances + if (level.Length < 10) + { + vector = GetPolyLoopXProduct(PlanarGeometry, level, report.testType); + string levelValue = level; + //if (i == 0) { levelValue += "-T"; } + //else { levelValue += "-S"; } + levelVct.Add(levelValue, vector); + } + } + fileLevelZz.Add(LevelZs); + fileLevelVct.Add(levelVct); + + //reporting + if (i % 2 != 0) + { + Dictionary standDict = fileLevelVct[1]; + Dictionary testDict = fileLevelVct[0]; + foreach (KeyValuePair pair in standDict) + { + + if (testDict.ContainsKey(pair.Key)) + { + report.MessageList.Add("While searching for matching building levels, there has been a Successful match. Building Story Level " + pair.Key + " in the Standard file found a match in the Test File."); + report.passOrFail = true; + //perform cross product again of the two vectors in question. The result should be a zero since they should be parallel + VectorMath.Vector.CartVect rhrTestVector = VectorMath.Vector.CrossProduct(testDict[pair.Key], standDict[pair.Key]); + if (rhrTestVector.X == 0 && rhrTestVector.Y == 0 && rhrTestVector.Z == 0) + { + report.MessageList.Add("For this level match, there is Normal Vector Test Success. The right hand rule test identified a parallel normal vector for Level " + pair.Key + " in both the Standard and Test gbXML Files."); + report.passOrFail = true; + } + else + { + VectorMath.Vector.CartVect rhrTestVectorU = VectorMath.Vector.UnitVector(rhrTestVector); + //create a test to determine the angular difference between the two vectors is within tolerance + //|A||B|cos theta = A x B + + //if the angle is within the allowable tolerance, then pass the test with a note that the vectors + //were not parallel + } + + } + else + { + report.MessageList.Add("The right hand rule test for Level " + pair.Key + " in the Standard File could not be completed. A match for this level could not be found in the test file."); + report.passOrFail = false; + errorCount++; + } + } + + } + else { continue; } + + //need to comapre and have if then statement depending on the outcome of the accuracy tests + if (errorCount == 0) + { + report.longMsg = "Test Success: Building Stories RHR in the Test File match the RHR in the Standard File for all Levels."; + } + else + { + report.longMsg = "Not all levels in the Standard File found equivalent levels and normal vectors in the Test File."; + } + return report; + } + catch (Exception e) + { + report.MessageList.Add(e.ToString()); + report.longMsg = " Failed to complete RHR Test for the Building Storey Nodes. Exception noted."; + report.passOrFail = false; + return report; + } + } + report.longMsg = "Fatal " + report.testType + " Test Failure"; + return report; + } + + //this is a support function used by the GetLevelHeights function above. It is not directly, + //iteslf, a test + private static List GetLevelZs(XmlNodeList PlanarGeometry, List LevelZs) + { + string result = ""; + int polyLoopCount = 0; + try + { + int nodecount = PlanarGeometry.Count; + VectorMath.Vector.CartCoord[] vCoords = new VectorMath.Vector.CartCoord[nodecount]; + foreach (XmlNode PolyLoops in PlanarGeometry) + { + //gathers all the cartesian points in a given polyloop + foreach (XmlNode cartesianPoints in PolyLoops) + { + + //test the polyloop RHR convention + //count the total number of cartesian coordinates + int coordcount = cartesianPoints.ChildNodes.Count; + //I may want to test the number of coordinates to make sure it matches + //I do want to ensure I have a minimum number of coords + if (coordcount < minPlanePoints) + { + result += "Insufficient number of cartesian points to define a plane"; + LevelZs.Add(result); + return LevelZs; + } + else + { + int cartPtCount = 0; + //gets a set of XYZ coordinates, one at a time + foreach (XmlNode coordinates in cartesianPoints.ChildNodes) + { + //I will only test one Z-coordinate in each set of coordinates + if (cartPtCount < 1) + { + VectorMath.Vector.CartCoord vC = new VectorMath.Vector.CartCoord(); + vCoords[polyLoopCount] = vC; + } + else { break; } + + int crdCount = 1; + //gets each coordinate one at a time + foreach (XmlNode coordinate in coordinates.ChildNodes) + { + double coord = Convert.ToDouble(coordinate.InnerText); + switch (crdCount) + { + case 1: + vCoords[polyLoopCount].X = coord; + break; + case 2: + vCoords[polyLoopCount].Y = coord; + break; + case 3: + vCoords[polyLoopCount].Z = coord; + break; + default: + break; + } + crdCount++; + } + cartPtCount++; + } + } + + } + polyLoopCount++; + } + //create the List that holds the z-values of each level + for (int z = 0; z < nodecount; z++) + { + LevelZs.Add(vCoords[z].Z.ToString()); + } + + return LevelZs; + } + + catch (Exception e) + { + result += e.ToString(); + LevelZs.Add(result); + return LevelZs; + } + } + //this is a simple way to get the polyLoop X product. + //this is a support function used by the Function TestBuildingStory RHR above + //This X Product routine is the first attempt to produce a X product from coordinates Since the coordinates used to define + //a level plane never create an irregular polygon, this scheme worked. + //it will only assuredly work properly for a triangle, square, or rectangle. Shapes other than these should use subsequent XProduct + //functions as created below. + //Created by CHarriman, Senior Product Manager Carmel Software + //Nov 2012 + public static VectorMath.Vector.CartVect GetPolyLoopXProduct(XmlNodeList PlanarGeometry, string level, TestType testType) + { + int cartPtCount = 0; + VectorMath.Vector.CartVect xProd = new VectorMath.Vector.CartVect(); + //gathers all the cartesian points in a given polyloop + int nodecount = PlanarGeometry.Count; + VectorMath.Vector.CartCoord[] vCoords = new VectorMath.Vector.CartCoord[3]; + foreach (XmlNode PolyLoops in PlanarGeometry) + { + foreach (XmlNode cartesianPoints in PolyLoops) + { + + //test the polyloop RHR convention + //count the total number of cartesian coordinates + int coordcount = cartesianPoints.ChildNodes.Count; + //I may want to test the number of coordinates to make sure it matches, or if it has a minimum number of coords + if (coordcount < minPlanePoints) + { + //result += "Insufficient number of cartesian points to define a plane"; + return xProd; + } + else + { + cartPtCount = 0; + //gets a set of XYZ coordinates, one at a time + foreach (XmlNode coordinates in cartesianPoints.ChildNodes) + { + if (cartPtCount < 3) + { + VectorMath.Vector.CartCoord vC = new VectorMath.Vector.CartCoord(); + vCoords[cartPtCount] = vC; + } + else { break; } + + int crdCount = 1; + //gets each coordinate one at a time + //filtering through the inner children of the PolyLoop + foreach (XmlNode coordinate in coordinates.ChildNodes) + { + double coord = Convert.ToDouble(coordinate.InnerText); + switch (crdCount) + { + case 1: + vCoords[cartPtCount].X = coord; + break; + case 2: + vCoords[cartPtCount].Y = coord; + break; + case 3: + vCoords[cartPtCount].Z = coord; + break; + default: + break; + } + if (vCoords[cartPtCount].Z.ToString() == level) { break; }; + crdCount++; + } + + cartPtCount++; + } + + } + } + if (vCoords[(cartPtCount - 1)].Z.ToString() == level) { break; } + } + //Get the Cross Product + VectorMath.Vector.CartVect v1 = VectorMath.Vector.CreateVector(vCoords[0], vCoords[1]); + VectorMath.Vector.CartVect v2 = VectorMath.Vector.CreateVector(vCoords[1], vCoords[2]); + xProd = VectorMath.Vector.CrossProduct(v1, v2); + xProd = Vector.UnitVector(xProd); + return xProd; + + } + + //this test was originally invented for the case where the proposed and test cases did not have to be identical + //it was designed simply to ensure that only the TEST file had unique SpaceId values. + //Created by CHarriman Senior Product Manager Carmel Software + //Nov 2012 + public static DOEgbXMLReportingObj UniqueSpaceIdTest(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report) + { + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Feb 13 2013 + report.testSummary = "This test reviews the test file's Space id values, and ensures that they are all unique. If there are any duplicate Space id values, then this test will fail. If there are duplicates, the remainder of the tests in the testbed are not executed and the test will end here until the test file is properly updated. Each Space id must be unique for the test bed to successfully execute. If you have failed this test, please review the documents for this test and resubmit the test."; + + report.MessageList = new List(); + report.TestPassedDict = new Dictionary(); + List standardIdList = new List(); + List testIDList = new List(); + report.standResult = new List(); + report.testResult = new List(); + report.idList = new List(); + // report.testType = "UniqueId"; + try + { + for (int i = 0; i < gbXMLDocs.Count; i++) + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + + XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Space", gbXMLns); + foreach (XmlNode node in nodes) + { + //looks to see if the spaceId is already included in the list of space IDs being generated + string spaceId; + if (i % 2 != 0) + { + spaceId = node.Attributes[0].Value.ToString(); + testIDList.Add(spaceId); + } + else + { + spaceId = node.Attributes[0].Value.ToString(); + standardIdList.Add(spaceId); + } + } + } + //now that I have all of the spaceIds, I will loop through and make sure I have perfect matches + //the order of the spaces is not enforced + //create a list that holds the index of the standardIdList when a match is found + //the list should be the same length as standardIdlist and each value should be unique + List indexFound = new List(); + for (int j = 0; j < standardIdList.Count; j++) + { + string standardId = standardIdList[j]; + foreach (string testspaceId in testIDList) + { + if (testspaceId == standardId) + { + indexFound.Add(j); + report.MessageList.Add("The standard file space id: " + standardId + "has found a spaceId match in the test file."); + } + } + } + //search the list to make sure that it is unique and has the proper count + if (indexFound.Count == standardIdList.Count) + { + report.MessageList.Add("The standard file has found a match only once in the test file. All spaceIds have been matched."); + report.passOrFail = true; + report.longMsg = "SpaceId Match test has passed."; + return report; + } + else + { + report.passOrFail = false; + string index = ""; + foreach (int p in indexFound) + { + index += p.ToString() + ", "; + } + report.MessageList.Add(index); + report.longMsg = "SpaceId Match test has failed."; + return report; + } + + //if (standardIdList.Contains(spaceId)) + //{ + // report.testResult.Add("Not Unique"); + + // report.longMsg = "Unique SpaceID Test Failed. " + spaceId + " is already included once in the test file."; + // report.passOrFail = false; + // report.TestPassedDict[spaceId] = false; + // return report; + //} + //else + //{ + // report.testResult.Add("Is Unique"); + + // spaceId = node.Attributes[0].Value.ToString(); + // standardIdList.Add(spaceId); + // report.passOrFail = true; + // report.TestPassedDict.Add(spaceId, true); + // report.MessageList.Add(spaceId + " is unique."); + //} + } + catch (Exception e) + { + report.longMsg = e.ToString(); + report.passOrFail = false; + return report; + } + return report; + } + + public static DOEgbXMLReportingObj TestSpaceAreas(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, Conversions.areaUnitEnum standardUnits, Conversions.areaUnitEnum testUnits, double conversion) + { + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Feb 13 2013 + report.testSummary = "This test compares the square footage of spaces in the test and standard files. It does this by searching"; + report.testSummary += "for a unique Space id in both the test and standard files, and finding a match. Once a match is found, it then"; + report.testSummary += " finds the square footage reported for the Space area, and compares them to ensure they are the same or"; + report.testSummary += " within tolerance. For example, if the standard file has a Space with id = \"Space-1\" with an area of"; + report.testSummary += "250 square feet, then this test searches through the test file for a Space with the identical id."; + report.testSummary += " Once this space has been located, the test then compares the Area to 250 square feet. "; + report.testSummary += "If they are identical, the test is done, and passes. We have built a tolerance in this test, meaning the"; + report.testSummary += " areas do not need to match perfectly in the standard file and test file. As long as your test file's value"; + report.testSummary += " for Space Area is +/- this tolerance, the test will pass. Using the previous example, if the allowable"; + report.testSummary += " tolerance is 1% (1% of 250 is 2.5 sf), then the test file may have a space area ranging from 247.5 to 252.5"; + report.testSummary += " square feet, and the test will still delcare \"Pass\"."; + + + report.unit = standardUnits.ToString(); + report.passOrFail = true; + string spaceId = ""; + //assuming that this will be plenty large for now + Dictionary standardFileAreaDict = new Dictionary(); + Dictionary testFileAreaDict = new Dictionary(); + + try + { + + for (int i = 0; i < gbXMLDocs.Count; i++) + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + + XmlNodeList spaceNodes = gbXMLDocs[i].SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Space/gbXMLv5:Area", gbXMLnsm[i]); + //make lists of the areas in each project + foreach (XmlNode spaceNode in spaceNodes) + { + string area = spaceNode.InnerText; + if (i % 2 != 0) + { + spaceId = spaceNode.ParentNode.Attributes[0].Value; + //no conversion necessary + standardFileAreaDict.Add(spaceId, Convert.ToDouble(area)); + } + else + { + spaceId = spaceNode.ParentNode.Attributes[0].Value; + double convertedArea = Convert.ToDouble(area) * conversion; + testFileAreaDict.Add(spaceId, convertedArea); + } + } + } + var standardKeys = standardFileAreaDict.Keys; + + foreach (string key in standardKeys) + { + if (testFileAreaDict.ContainsKey(key)) + { + double testFileSpaceArea = testFileAreaDict[key]; + double standardFileSpaceArea = standardFileAreaDict[key]; + + + report.standResult.Add(String.Format("{0:#,0.00}",Convert.ToString(standardFileSpaceArea))); + report.testResult.Add(String.Format("{0:#,0.00}", Convert.ToString(testFileSpaceArea))); + report.idList.Add(key); + + double difference = Math.Abs(testFileSpaceArea - standardFileSpaceArea); + if (difference == 0) + { + report.MessageList.Add("For Space Id: " + key + ". Success finding matching space area. The Standard File and the Test File both have a space with an area = " + String.Format("{0:#,0.00}", testFileSpaceArea.ToString()) + " " + report.unit + ". "); + report.TestPassedDict.Add(key, true); + } + else if (difference < report.tolerance) + { + report.MessageList.Add("For Space Id: " + key + ". Success finding matching space area. The Standard File space area of " + String.Format("{0:#,0.00}", standardFileSpaceArea.ToString()) + " and the Test File space area of " + String.Format("{0:#,0.00}", testFileSpaceArea.ToString()) + " " + report.unit + " is within the allowable tolerance of " + report.tolerance.ToString() + " " + report.unit); + report.TestPassedDict.Add(key, true); + } + else + { + report.MessageList.Add("For space Id: " + key + ". Failure to find an space area match. THe area equal to = " + String.Format("{0:#,0.00}", standardFileSpaceArea.ToString()) + " " + report.unit + " in the Standard File could not be found in the Test File. "); + report.TestPassedDict.Add(key, false); + } + } + else + { + report.standResult.Add("---"); + report.testResult.Add("Could not be matched"); + report.idList.Add(key); + //failure to match spaceIds + report.MessageList.Add("Test File and Standard File space names could not be matched. SpaceId: " + key + " could not be found in the test file."); + report.passOrFail = false; + return report; + } + } + return report; + } + + catch (Exception e) + { + report.MessageList.Add(e.ToString()); + report.longMsg = "Failed to complete the " + report.testType + ". See exceptions noted."; + report.passOrFail = false; + return report; + } + report.longMsg = "Fatal " + report.testType + " Test Failure"; + report.passOrFail = false; + return report; + } + + public static DOEgbXMLReportingObj TestSpaceVolumes(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units) + { + report.passOrFail = true; + string spaceId = ""; + report.unit = Units; + //assuming that this will be plenty large for now + Dictionary standardFileVolumeDict = new Dictionary(); + Dictionary testFileVolumeDict = new Dictionary(); + + try + { + for (int i = 0; i < gbXMLDocs.Count; i++) + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + + XmlNodeList spaceNodes = gbXMLDocs[i].SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Space/gbXMLv5:Volume", gbXMLnsm[i]); + //make lists of the areas in each project + foreach (XmlNode spaceNode in spaceNodes) + { + string volume = spaceNode.InnerText; + if (i % 2 != 0) + { + spaceId = spaceNode.ParentNode.Attributes[0].Value; + testFileVolumeDict.Add(spaceId, Convert.ToDouble(volume)); + } + else + { + spaceId = spaceNode.ParentNode.Attributes[0].Value; + standardFileVolumeDict.Add(spaceId, Convert.ToDouble(volume)); + } + } + } + var standardKeys = standardFileVolumeDict.Keys; + foreach (string key in standardKeys) + { + if (testFileVolumeDict.ContainsKey(key)) + { + double standardFileVolume = standardFileVolumeDict[key]; + double testFileVolume = testFileVolumeDict[key]; + + report.standResult.Add(Convert.ToString(standardFileVolume)); + report.testResult.Add(Convert.ToString(testFileVolume)); + report.idList.Add(key); + + double difference = Math.Abs(testFileVolume - standardFileVolume); + if (difference == 0) + { + report.MessageList.Add("For Space Id: " + key + ". Success finding matching space volume. The Standard and Test Files both have identical volumes: " + testFileVolume + " " + Units + "for Space Id: " + key); + report.TestPassedDict.Add(key, true); + } + else if (difference < report.tolerance) + { + report.MessageList.Add("For Space Id: " + key + ". Success finding matching space volume. The Standard Files space volume of " + standardFileVolume.ToString() + " " + Units + "and the Test File space volume: " + testFileVolume + " are within the allowed tolerance of" + report.tolerance.ToString() + " " + Units + "."); + report.TestPassedDict.Add(key, true); + } + else + { + //at the point of failure, the test will return with details about which volume failed. + report.MessageList.Add("For Space Id: " + key + ". Failure to find a volume match. The Volume in the Test File equal to: " + testFileVolume.ToString() + " " + Units + " was not within the allowed tolerance. SpaceId: " + key + " in the Standard file has a volume: " + standardFileVolume.ToString() + " ."); + report.TestPassedDict.Add(key, false); + } + } + else + { + report.standResult.Add("Space Id: " + key); + report.testResult.Add("Could not be matched"); + report.idList.Add(""); + + //at the point of failure, the test will return with details about which volume failed. + report.MessageList.Add("Test File and Standard File space names could not be matched. SpaceId: " + key + " could not be found in the test file."); + report.passOrFail = false; + return report; + } + } + return report; + } + + catch (Exception e) + { + report.MessageList.Add(e.ToString()); + report.longMsg = " Failed to complete the " + report.testType + ". See exceptions noted."; + report.passOrFail = false; + return report; + } + + report.longMsg = "Fatal " + report.testType + " Test Failure"; + report.passOrFail = false; + return report; + } + + //this function was abandoned until the second phase + //Created Dec 2012 by CHarriman Senior Product Manager Carmel Software Corp + + public static DOEgbXMLReportingObj TestShellGeomPLRHR(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units) + { + string result = ""; + string floorarea = ""; + report.unit = Units; + List VectList = new List(); + + //keeps a dictionary of the shell geometry points for each space of the test file key = spaceId, value = List of Coordinates + Dictionary> shellGeomPtsTF = new Dictionary>(); + //keeps a dictionary of the shell geometry points for each space of the standard file key = spaceId, value = List of Coordinates + Dictionary> shellGeomPtsSF = new Dictionary>(); + //keeps a dictinary of the RHR vectors of the Test file + Dictionary> shellGeomRHRTF = new Dictionary>(); + //keeps a dictionary of the RHR vectors of the Standard file + Dictionary> shellGeomRHRSF = new Dictionary>(); + + for (int i = 0; i < gbXMLDocs.Count; i++) + { + try + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + //for each space, gather some kind of qualifying information + XmlNodeList spaceNodes = gbXMLDocs[i].SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Space", gbXMLns); + foreach (XmlNode space in spaceNodes) + { + XmlNodeList spaceChildren = space.ChildNodes; + foreach (XmlNode spaceChild in spaceChildren) + { + if (spaceChild.Name == "ShellGeometry") + { + XmlNode closedShell = spaceChild.FirstChild; + switch (i) + { + case 0: + shellGeomPtsTF = GetShellGeomPts(closedShell); + break; + case 1: + shellGeomPtsSF = GetShellGeomPts(closedShell); + break; + default: + break; + } + //Determine if matches found everywhere + + //Test the two sets of data points to find matches return the coordinate matches in the same order they + //are presented in the gbXML file + + switch (i) + { + case 0: + shellGeomRHRTF = GetShellGeomPolyRHR(shellGeomPtsTF); + break; + case 1: + shellGeomRHRSF = GetShellGeomPolyRHR(shellGeomPtsSF); + break; + default: + break; + + } + + } + + } + } + + + } + catch (Exception e) + { + + } + return report; + } + return report; + } + //this is a support tool for TestShellGeomPLRHR + public static Dictionary> GetShellGeomPts(XmlNode closedShell) + { + Dictionary> PtsDict = new Dictionary>(); + + string spaceId = "none"; + + int cartPtCount; + try + { + //get the name of the space for which this point is defined + XmlNode spaceNode = closedShell.ParentNode; + XmlAttributeCollection spaceAtts = spaceNode.Attributes; + foreach (XmlAttribute at in spaceAtts) + { + if (at.Name == "id") + { + spaceId = at.Value; + break; + } + + } + //keep track of the number of polyloops in the closed shell + int pLCount = 1; + //store the geometry points + foreach (XmlNode PolyLoops in closedShell) + { + List vCoords = new List(); + List PtsList = new List(); + cartPtCount = 0; + foreach (XmlNode cartesianPoints in PolyLoops) + { + //reset surface area and unitRHR (this is how I know that there may be a problem + //and these values are returned as points. It is not perfect + Vector.CartCoord Pts = new Vector.CartCoord(); + Pts.X = -999; + Pts.Y = -999; + Pts.Z = -999; + PtsList.Add(Pts); + int crdCount = 1; + //gets a set of XYZ coordinates, one at a time + foreach (XmlNode coordinate in cartesianPoints.ChildNodes) + { + double coord = Convert.ToDouble(coordinate.InnerText); + switch (crdCount) + { + case 1: + + PtsList[cartPtCount].X = coord; + break; + case 2: + + PtsList[cartPtCount].Y = coord; + break; + case 3: + + PtsList[cartPtCount].Z = coord; + break; + default: + break; + + + } + crdCount++; + } + cartPtCount++; + } + string spaceSurface = spaceId + "/" + pLCount.ToString(); + + PtsDict.Add(spaceSurface, PtsList); + pLCount++; + //PtsList.Clear(); + } + } + catch (Exception e) + { + + } + //I may want to test the number of coordinates to make sure it matches, or if it has a minimum number of coords + return PtsDict; + } + + // + //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation + //Designed to take a Dictionary + //Each set of points are then turned into vectors, which are then put through a cross product to determine the + //normal vector. we only arbitrarily take the first three points in the list, which potentially could cause some issue. + //This is planned to be fixed in a future release. + //The normal vector calculated is the value in the key value pair, the key being the spaceId+surfaceNumber, + //The Dictionary is returned with it includes a key value pair for each surface it has analyzed. + //Therefore, if the Dictionary sent to it has 12 key value pairs, then it will return 12 key value pairs as well. + //This is not checked for explicitly but mentioned for clarity. + public static Dictionary> GetShellGeomPolyRHR(Dictionary> PtsList) + { + //reg expressions + string iDPatt = "(.+)[^/][0-9]"; + string numPatt = "[0-9]+"; + + //initialize variables needed in this method + VectorMath.Vector.CartVect unitRHR = new VectorMath.Vector.CartVect(); + List vCoords = new List(); + List vVect = new List(); + string spaceId = "none"; + string spacenum = ""; + //dictionary that will be returned by this method + Dictionary> plRHRDict = new Dictionary>(); + + //begin iterating through the Cartesian Points passed into the method (PtsList) + for (int i = 0; i < PtsList.Count; i++) + { + //get the identification strings associated with each list of points in the dictionary passed to the method + string spaceSurf = PtsList.Keys.ElementAt(i); + foreach (Match match in Regex.Matches(spaceSurf, iDPatt)) + { + spaceId = match.ToString(); + } + string spaceSurf2 = PtsList.Keys.ElementAt(i); + foreach (Match match in Regex.Matches(spaceSurf2, numPatt)) + { + spacenum = match.ToString(); + } + + //take the list of coordinates and store them locally + //this step does not need to be taken, but it does simplify the coding a little bit. + foreach (Vector.CartCoord coord in PtsList.Values.ElementAt(i)) + { + vCoords.Add(coord); + } + //just arbitrarily take the first 3 coordinates + //this can lead to bad results, but is used until the next release of the software + VectorMath.Vector.CartVect v1 = VectorMath.Vector.CreateVector(vCoords[0], vCoords[1]); + VectorMath.Vector.CartVect v2 = VectorMath.Vector.CreateVector(vCoords[1], vCoords[2]); + unitRHR = VectorMath.Vector.CrossProduct(v1, v2); + unitRHR = Vector.UnitVector(unitRHR); + vVect.Add(unitRHR); + vCoords.Clear(); + + } + plRHRDict.Add(spaceId, vVect); + return plRHRDict; + } + + // + //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation + //A simple method that reports the number of all surface elements in a test file and standard file + //If the number of surface elements is not the same, the method returns false and displays the difference in the number of surfaces. + public static DOEgbXMLReportingObj GetSurfaceCount(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units) + { + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Mar 14 2013 + report.testSummary = "This test compares the total number of Surface elements in the test and standard files. It does this by"; + report.testSummary += " simply counting up the total number of times that a \"\" tag appears in both files. If the "; + report.testSummary += "quantities are the same, this test passes, if different, it will fail. "; + report.testSummary += "The tolerance is zero for this test. In other words, the surface counts are the same, or the test fails."; + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Feb 13 2013 + report.testSummary += " You may notice that this test has failed, but overall your file has passed. This is because the surface"; + report.testSummary += " count may not be a perfect indicator of accuracy. So overall, the test may pass even though this test failed."; + report.testSummary += " Refer to the pass/fail summary sheet for more information."; + + report.unit = Units; + //assuming that this will be plenty large for now + string[] resultsArray = new string[50]; + for (int i = 0; i < gbXMLDocs.Count; i++) + { + try + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + + XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface", gbXMLns); + int nodecount = nodes.Count; + //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result + resultsArray[i] = nodecount.ToString(); + if (i % 2 != 0) + { + //setup standard result and test result + report.standResult.Add(resultsArray[i]); + report.testResult.Add(resultsArray[i - 1]); + report.idList.Add(""); + + double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)])); + if (difference <= report.tolerance) + { + report.longMsg = "The " + report.testType + " matches standard file, the difference was within tolerance = " + report.tolerance.ToString() + " " + Units; + report.passOrFail = true; + return report; + } + else + { + report.longMsg = "The " + report.testType + " does not match standard file, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference; + report.passOrFail = false; + return report; + } + } + else { continue; } + } + catch (Exception e) + { + report.MessageList.Add(e.ToString()); + report.longMsg = " Failed to locate " + report.testType + " in the XML file."; + report.passOrFail = false; + return report; + } + } + report.longMsg = "Fatal " + report.testType + " Test Failure"; + report.passOrFail = false; + return report; + } + // + //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation + //A simple method that reports the number of surface elements whose surfaceType attribute = "ExteriorWall in a test file and standard file + //If the number of surface elements is not the same, the method returns false and displays the difference in the number of surfaces. + public static DOEgbXMLReportingObj GetEWSurfaceCount(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units) + { + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Mar 14 2013 + report.testSummary = "This test compares the total number of Surface elements with the SurfaceType=\"ExteriorWall\" in the test"; + report.testSummary += " and standard files. It does this by"; + report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this SurfaceType in both files."; + report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. "; + report.testSummary += "The tolerance is zero for this test. In other words, the surface counts are the same, or the test fails."; + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Feb 13 2013 + report.testSummary += " You may notice that this test has failed, but overall your file has passed. This is because the surface"; + report.testSummary += " count may not be a perfect indicator of accuracy. So overall, the test summary may show \"Pass\" even though this test failed."; + report.testSummary += " Refer to the pass/fail summary sheet for more information."; + + report.unit = Units; + //assuming that this will be plenty large for now + string[] resultsArray = new string[50]; + int nodecount = 0; + for (int i = 0; i < gbXMLDocs.Count; i++) + { + nodecount = 0; + try + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + + XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface", gbXMLns); + foreach (XmlNode surfaceNode in nodes) + { + XmlAttributeCollection spaceAtts = surfaceNode.Attributes; + foreach (XmlAttribute at in spaceAtts) + { + if (at.Name == "surfaceType") + { + string type = at.Value; + if (type == "ExteriorWall") + { + nodecount++; + } + break; + } + } + } + + //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result + resultsArray[i] = nodecount.ToString(); + if (i % 2 != 0) + { + //setup standard result and test result + report.standResult.Add(resultsArray[i]); + report.testResult.Add(resultsArray[i - 1]); + report.idList.Add(""); + + double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)])); + if (difference == 0) + { + report.longMsg = "The Test File's" + report.testType + " matches the Standard File exactly, the difference is zero."; + report.passOrFail = true; + return report; + } + else if (difference <= report.tolerance) + { + report.longMsg = "The Test File's " + report.testType + " matches Standard File within the allowable tolerance, the difference between the two files is " + report.tolerance.ToString() + " " + Units; + report.passOrFail = true; + return report; + } + else + { + report.longMsg = "The Test File's " + report.testType + " does not match Standard File, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference + + ". " + resultsArray[i] + " exterior wall surfaces in the Standard File and " + resultsArray[i - 1] + " exterior wall surfaces in the Test File."; + report.passOrFail = false; + return report; + } + } + else { continue; } + + } + catch (Exception e) + { + report.MessageList.Add(e.ToString()); + report.longMsg = " Failed to locate " + report.testType + " in the XML file."; + report.passOrFail = false; + return report; + } + } + report.longMsg = "Fatal " + report.testType + " Test Failure"; + report.passOrFail = false; + return report; + } + // + //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation + //A simple method that reports the number of surface elements whose surfaceType attribute = "InterirWall" in a test file and standard file + //If the number of surface elements is not the same, the method returns false and displays the difference in the number of surfaces. + public static DOEgbXMLReportingObj GetIWSurfaceCount(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units) + { + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Mar 14 2013 + report.testSummary = "This test compares the total number of Surface elements with the SurfaceType=\"InteriorWall\" in the test"; + report.testSummary += " and standard files. It does this by"; + report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this SurfaceType in both files."; + report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. "; + report.testSummary += "The tolerance is zero for this test. In other words, the surface counts are the same, or the test fails."; + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Feb 13 2013 + report.testSummary += " You may notice that this test has failed, but overall your file has passed. This is because the surface"; + report.testSummary += " count may not be a perfect indicator of accuracy. So overall, the test summary may show \"Pass\" even though this test failed."; + report.testSummary += " Refer to the pass/fail summary sheet for more information."; + + report.unit = Units; + + //assuming that this will be plenty large for now + string[] resultsArray = new string[50]; + int nodecount = 0; + for (int i = 0; i < gbXMLDocs.Count; i++) + { + nodecount = 0; + try + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + + XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface", gbXMLns); + foreach (XmlNode surfaceNode in nodes) + { + XmlAttributeCollection spaceAtts = surfaceNode.Attributes; + foreach (XmlAttribute at in spaceAtts) + { + if (at.Name == "surfaceType") + { + string type = at.Value; + if (type == "InteriorWall") + { + nodecount++; + } + break; + } + } + } + + //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result + resultsArray[i] = nodecount.ToString(); + if (i % 2 != 0) + { + + //setup standard result and test result + report.standResult.Add(resultsArray[i]); + report.testResult.Add(resultsArray[i - 1]); + report.idList.Add(""); + + double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)])); + if (difference == 0) + { + report.longMsg = "The Test File's" + report.testType + " matches the Standard File exactly, the difference is zero."; + report.passOrFail = true; + return report; + } + else if (difference <= report.tolerance) + { + report.longMsg = "The Test File's " + report.testType + " matches Standard File within the allowable tolerance, the difference between the two files is " + report.tolerance.ToString() + " " + Units; + report.passOrFail = true; + return report; + } + else + { + report.longMsg = "The Test File's" + report.testType + " does not match Standard File, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference + + ". " + resultsArray[i] + " interior wall surfaces in the standard file and " + resultsArray[i - 1] + " interior wall surfaces in the test file."; + report.passOrFail = false; + return report; + } + } + else { continue; } + + } + catch (Exception e) + { + report.MessageList.Add(e.ToString()); + report.longMsg = " Failed to locate " + report.testType + " in the XML file."; + report.passOrFail = false; + return report; + } + } + report.longMsg = "Fatal " + report.testType + " Test Failure"; + report.passOrFail = false; + return report; + } + // + //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation + //A simple method that reports the number of surface elements whose surfaceType attribute = "InteriorFloor" in a test file and standard file + //If the number of surface elements is not the same, the method returns false and displays the difference in the number of surfaces. + public static DOEgbXMLReportingObj GetIFSurfaceCount(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units) + { + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Mar 14 2013 + report.testSummary = "This test compares the total number of Surface elements with the SurfaceType=\"InteriorFloor\" in the test"; + report.testSummary += " and standard files. It does this by"; + report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files."; + report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. "; + report.testSummary += "The tolerance is zero for this test. In other words, the surface counts are the same, or the test fails."; + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Feb 13 2013 + report.testSummary += " You may notice that this test has failed, but overall your file has passed. This is because the surface"; + report.testSummary += " count may not be a perfect indicator of accuracy. So overall, the test summary may show \"Pass\" even though this test failed."; + report.testSummary += " Refer to the pass/fail summary sheet for more information."; + + report.unit = Units; + //assuming that this will be plenty large for now + string[] resultsArray = new string[50]; + int nodecount = 0; + for (int i = 0; i < gbXMLDocs.Count; i++) + { + nodecount = 0; + try + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + + XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface", gbXMLns); + foreach (XmlNode surfaceNode in nodes) + { + XmlAttributeCollection spaceAtts = surfaceNode.Attributes; + foreach (XmlAttribute at in spaceAtts) + { + if (at.Name == "surfaceType") + { + string type = at.Value; + if (type == "InteriorFloor") + { + nodecount++; + } + break; + } + } + } + + //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result + resultsArray[i] = nodecount.ToString(); + if (i % 2 != 0) + { + //setup standard result and test result + report.standResult.Add(resultsArray[i]); + report.testResult.Add(resultsArray[i - 1]); + report.idList.Add(""); + + double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)])); + if (difference == 0) + { + report.longMsg = "The Test File's" + report.testType + " matches the Standard File exactly, the difference is zero."; + report.passOrFail = true; + return report; + } + else if (difference <= report.tolerance) + { + report.longMsg = "The Test File's " + report.testType + " matches Standard File within the allowable tolerance, the difference between the two files is " + report.tolerance.ToString() + " " + Units; + report.passOrFail = true; + return report; + } + else + { + report.longMsg = "The Test File's" + report.testType + " does not match Standard File, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference + + ". " + resultsArray[i] + " interior floor surfaces in the standard file and " + resultsArray[i - 1] + " interior floor surfaces in the test file."; + report.passOrFail = false; + return report; + } + } + else { continue; } + + } + catch (Exception e) + { + report.MessageList.Add(e.ToString()); + report.longMsg = " Failed to locate " + report.testType + " in the XML file."; + report.passOrFail = false; + return report; + } + } + report.longMsg = "Fatal " + report.testType + " Test Failure"; + report.passOrFail = false; + return report; + } + + // + //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation + //A simple method that reports the number of surface elements whose surfaceType attribute = "Roof" in a test file and standard file + //If the number of roof surface elements is not the same, the method returns false and displays the difference in the number of surfaces. + public static DOEgbXMLReportingObj GetRoofSurfaceCount(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units) + { + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Mar 14 2013 + report.testSummary = "This test compares the total number of Surface elements with the SurfaceType=\"Roof\" in the test"; + report.testSummary += " and standard files. It does this by"; + report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files."; + report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. "; + report.testSummary += "The tolerance is zero for this test. In other words, the surface counts are the same, or the test fails."; + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Feb 13 2013 + report.testSummary += " You may notice that this test has failed, but overall your file has passed. This is because the surface"; + report.testSummary += " count may not be a perfect indicator of accuracy. So overall, the test summary may show \"Pass\" even though this test failed."; + report.testSummary += " Refer to the pass/fail summary sheet for more information."; + + report.unit = Units; + + //assuming that this will be plenty large for now + string[] resultsArray = new string[50]; + int nodecount = 0; + for (int i = 0; i < gbXMLDocs.Count; i++) + { + nodecount = 0; + try + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + + XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface", gbXMLns); + foreach (XmlNode surfaceNode in nodes) + { + XmlAttributeCollection spaceAtts = surfaceNode.Attributes; + foreach (XmlAttribute at in spaceAtts) + { + if (at.Name == "surfaceType") + { + string type = at.Value; + if (type == "Roof") + { + nodecount++; + } + break; + } + } + } + + //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result + resultsArray[i] = nodecount.ToString(); + if (i % 2 != 0) + { + //setup standard result and test result + report.standResult.Add(resultsArray[i]); + report.testResult.Add(resultsArray[i - 1]); + report.idList.Add(""); + + double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)])); + if (difference == 0) + { + report.longMsg = "The Test File's" + report.testType + " matches the Standard File exactly, the difference is zero."; + report.passOrFail = true; + return report; + } + else if (difference <= report.tolerance) + { + report.longMsg = "The Test File's " + report.testType + " matches Standard File within the allowable tolerance, the difference between the two files is " + report.tolerance.ToString() + " " + Units; + report.passOrFail = true; + return report; + } + else + { + report.longMsg = "The Test File's" + report.testType + " does not match Standard File, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference + + ". " + resultsArray[i] + " roof surfaces in the standard file and " + resultsArray[i - 1] + " roof surfaces in the test file."; + report.passOrFail = false; + return report; + } + } + else { continue; } + + } + catch (Exception e) + { + report.MessageList.Add(e.ToString()); + report.longMsg = " Failed to locate " + report.testType + " in the XML file."; + report.passOrFail = false; + return report; + } + } + report.longMsg = "Fatal " + report.testType + " Test Failure"; + report.passOrFail = false; + return report; + } + + // + //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation + //A simple method that reports the number of surface elements whose surfaceType attribute = "Shade" in a test file and standard file + //If the number of surface elements is not the same, the method returns false and displays the difference in the number of surfaces. + public static DOEgbXMLReportingObj GetShadeSurfaceCount(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units) + { + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Mar 14 2013 + report.testSummary = "This test compares the total number of Surface elements with the SurfaceType=\"Shade\" in the test"; + report.testSummary += " and standard files. It does this by"; + report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files."; + report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. "; + report.testSummary += "The tolerance is zero for this test. In other words, the surface counts are the same, or the test fails."; + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Feb 13 2013 + report.testSummary += " You may notice that this test has failed, but overall your file has passed. This is because the surface"; + report.testSummary += " count may not be a perfect indicator of accuracy. So overall, the test summary may show \"Pass\" even though this test failed."; + report.testSummary += " Refer to the pass/fail summary sheet for more information."; + + report.unit = Units; + + //assuming that this will be plenty large for now + string[] resultsArray = new string[50]; + int nodecount = 0; + for (int i = 0; i < gbXMLDocs.Count; i++) + { + nodecount = 0; + try + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + + XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface", gbXMLns); + foreach (XmlNode surfaceNode in nodes) + { + XmlAttributeCollection spaceAtts = surfaceNode.Attributes; + foreach (XmlAttribute at in spaceAtts) + { + if (at.Name == "surfaceType") + { + string type = at.Value; + if (type == "Shade") + { + nodecount++; + } + break; + } + } + } + + //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result + resultsArray[i] = nodecount.ToString(); + if (i % 2 != 0) + { + //setup standard result and test result + report.standResult.Add(resultsArray[i]); + report.testResult.Add(resultsArray[i - 1]); + report.idList.Add(""); + + double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)])); + if (difference <= report.tolerance) + if (difference == 0) + { + report.longMsg = "The Test File's" + report.testType + " matches the Standard File exactly, the difference is zero."; + report.passOrFail = true; + return report; + } + else if (difference <= report.tolerance) + { + report.longMsg = "The Test File's " + report.testType + " matches Standard File within the allowable tolerance, the difference between the two files is " + report.tolerance.ToString() + " " + Units; + report.passOrFail = true; + return report; + } + else + { + report.longMsg = "The Test File's " + report.testType + " does not match Standard File, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference + + ". " + resultsArray[i] + " shading surfaces in the standard file and " + resultsArray[i - 1] + " shading surfaces in the test file."; + report.passOrFail = false; + return report; + } + } + else { continue; } + + } + catch (Exception e) + { + report.MessageList.Add(e.ToString()); + report.longMsg = " Failed to locate " + report.testType + " in the XML file."; + report.passOrFail = false; + return report; + } + } + report.longMsg = "Fatal " + report.testType + " Test Failure"; + report.passOrFail = false; + return report; + } + + // + //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation + //A simple method that reports the number of surface elements whose surfaceType attribute = "Air" in a test file and standard file + //If the number of surface elements is not the same, the method returns false and displays the difference in the number of surfaces. + public static DOEgbXMLReportingObj GetAirSurfaceCount(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units) + { + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Mar 14 2013 + report.testSummary = "This test compares the total number of Surface elements with the SurfaceType=\"Air\" in the test"; + report.testSummary += " and standard files. It does this by"; + report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files."; + report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. "; + report.testSummary += "The tolerance is zero for this test. In other words, the surface counts are the same, or the test fails."; + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Feb 13 2013 + report.testSummary += " You may notice that this test has failed, but overall your file has passed. This is because the surface"; + report.testSummary += " count may not be a perfect indicator of accuracy. So overall, the test summary may show \"Pass\" even though this test failed."; + report.testSummary += " Refer to the pass/fail summary sheet for more information."; + + report.unit = Units; + + //assuming that this will be plenty large for now + string[] resultsArray = new string[50]; + int nodecount = 0; + for (int i = 0; i < gbXMLDocs.Count; i++) + { + nodecount = 0; + try + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + + XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface", gbXMLns); + foreach (XmlNode surfaceNode in nodes) + { + XmlAttributeCollection spaceAtts = surfaceNode.Attributes; + foreach (XmlAttribute at in spaceAtts) + { + if (at.Name == "surfaceType") + { + string type = at.Value; + if (type == "Air") + { + nodecount++; + } + break; + } + } + } + + //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result + resultsArray[i] = nodecount.ToString(); + if (i % 2 != 0) + { + //setup standard result and test result + report.standResult.Add(resultsArray[i]); + report.testResult.Add(resultsArray[i - 1]); + report.idList.Add(""); + + double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)])); + if (difference == 0) + { + report.longMsg = "The Test File's" + report.testType + " matches the Standard File exactly, the difference is zero."; + report.passOrFail = true; + return report; + } + else if (difference <= report.tolerance) + { + report.longMsg = "The Test File's " + report.testType + " matches Standard File within the allowable tolerance, the difference between the two files is " + report.tolerance.ToString() + " " + Units; + report.passOrFail = true; + return report; + } + else + { + report.longMsg = "The Test File's " + report.testType + " does not match Standard File, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference + + ". " + resultsArray[i] + " air surfaces in the standard file and " + resultsArray[i - 1] + " air surfaces in the test file."; + report.passOrFail = false; + return report; + } + } + else { continue; } + + } + catch (Exception e) + { + report.MessageList.Add(e.ToString()); + report.longMsg = " Failed to locate " + report.testType + " in the XML file."; + report.passOrFail = false; + return report; + } + } + report.longMsg = "Fatal " + report.testType + " Test Failure"; + report.passOrFail = false; + return report; + } + // + //Written Jan 31, 2013 by Chien Si Harriman, Senior Product Manager, Carmel Software Corporation + //This method will take each surface element and convert the xml language into an instance of a SurfaceDefinition + //Each surface is converted in this way, with the resulting instance being stored in a list that is returned for later use + //----------------------

+ //This is an important method because it stores all of the information about a surface in a gbXML file in a list + //This list can later be recalled to perform analytics on the surfaces and the data contained within + private static List GetFileSurfaceDefs(XmlDocument xmldoc, XmlNamespaceManager xmlns) + { + List surfaces = new List(); + try + { + + XmlNodeList nodes = xmldoc.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface", xmlns); + foreach (XmlNode surfaceNode in nodes) + { + //initialize a new instance of the class + SurfaceDefinitions surfDef = new SurfaceDefinitions(); + surfDef.AdjSpaceId = new List(); + surfDef.PlCoords = new List(); + surfDef.InsertionPoint = new Vector.CartCoord(); + surfDef.PlRHRVector = new Vector.CartVect(); + + //get id and surfaceType + XmlAttributeCollection spaceAtts = surfaceNode.Attributes; + foreach (XmlAttribute at in spaceAtts) + { + if (at.Name == "id") + { + surfDef.SurfaceId = at.Value; + } + else if (at.Name == "surfaceType") + { + surfDef.SurfaceType = at.Value; + } + } + if (surfaceNode.HasChildNodes) + { + XmlNodeList surfChildNodes = surfaceNode.ChildNodes; + foreach (XmlNode node in surfChildNodes) + { + if (node.Name == "AdjacentSpaceId") + { + XmlAttributeCollection adjSpaceIdAt = node.Attributes; + foreach (XmlAttribute at in adjSpaceIdAt) + { + if (at.Name == "spaceIdRef") + { + surfDef.AdjSpaceId.Add(at.Value); + } + } + } + else if (node.Name == "RectangularGeometry") + { + if (node.HasChildNodes) + { + XmlNodeList rectGeomChildren = node.ChildNodes; + foreach (XmlNode rgChildNode in rectGeomChildren) + { + if (rgChildNode.Name == "Azimuth") { surfDef.Azimuth = Convert.ToDouble(rgChildNode.InnerText); } + else if (rgChildNode.Name == "CartesianPoint") + { + if (rgChildNode.HasChildNodes) + { + XmlNodeList coordinates = rgChildNode.ChildNodes; + int pointCount = 1; + foreach (XmlNode coordinate in coordinates) + { + switch (pointCount) + { + case 1: + surfDef.InsertionPoint.X = Convert.ToDouble(coordinate.InnerText); + break; + case 2: + surfDef.InsertionPoint.Y = Convert.ToDouble(coordinate.InnerText); + break; + case 3: + surfDef.InsertionPoint.Z = Convert.ToDouble(coordinate.InnerText); + break; + } + pointCount++; + } + } + } + else if (rgChildNode.Name == "Tilt") { surfDef.Tilt = Convert.ToDouble(rgChildNode.InnerText); } + else if (rgChildNode.Name == "Height") { surfDef.Height = Convert.ToDouble(rgChildNode.InnerText); } + else if (rgChildNode.Name == "Width") { surfDef.Width = Convert.ToDouble(rgChildNode.InnerText); } + } + } + } + else if (node.Name == "PlanarGeometry") + { + XmlNode polyLoop = node.FirstChild; + if (polyLoop.HasChildNodes) + { + XmlNodeList cartesianPoints = polyLoop.ChildNodes; + foreach (XmlNode coordinatePt in cartesianPoints) + { + Vector.CartCoord coord = new Vector.CartCoord(); + if (coordinatePt.HasChildNodes) + { + XmlNodeList coordinates = coordinatePt.ChildNodes; + int pointCount = 1; + foreach (XmlNode coordinate in coordinatePt) + { + + switch (pointCount) + { + case 1: + coord.X = Convert.ToDouble(coordinate.InnerText); + break; + case 2: + coord.Y = Convert.ToDouble(coordinate.InnerText); + break; + case 3: + coord.Z = Convert.ToDouble(coordinate.InnerText); + break; + } + pointCount++; + } + surfDef.PlCoords.Add(coord); + } + } + } + } + } + } + Vector.CartVect plRHRVect = GetPLRHR(surfDef.PlCoords); + surfDef.PlRHRVector = plRHRVect; + surfaces.Add(surfDef); + } + return surfaces; + } + catch (Exception e) + { + return surfaces; + } + + } + + private static Vector.CartVect GetPLRHR(List plCoords) + { + Vector.CartVect plRHRVect = new Vector.CartVect(); + //this list will store all of the rhr values returned by any arbitrary polyloop + List RHRs = new List(); + + int coordCount = plCoords.Count; + for (int i = 0; i < coordCount - 2; i++) + { + Vector.CartVect v1 = Vector.CreateVector(plCoords[i], plCoords[i + 1]); + Vector.CartVect v2 = Vector.CreateVector(plCoords[i + 1], plCoords[i + 2]); + Vector.CartVect uv = Vector.UnitVector(Vector.CrossProduct(v1, v2)); + RHRs.Add(uv); + } + int RHRVectorCount = RHRs.Count; + List distinctRHRs = new List(); + //the Distinct().ToList() routine did not work because, we believe, the item in the list is not recognized by Distinct() + //distinctRHRs = RHRs.Distinct().ToList(); + //so we took the following approach to try and find unique vectors and store them + distinctRHRs.Add(RHRs[0]); + for (int j = 1; j < RHRVectorCount; j++) + { + foreach (Vector.CartVect distinctVector in distinctRHRs) + { + //this could contain wacky RHRs that are removed below + if (RHRs[j].X != distinctVector.X && RHRs[j].Y != distinctVector.Y && RHRs[j].Z != distinctVector.Z) + { + distinctRHRs.Add(RHRs[j]); + } + } + } + + int RHRDistinctVectCount = distinctRHRs.Count; + if (RHRDistinctVectCount == 1) + { + plRHRVect = distinctRHRs[0]; + return plRHRVect; + } + else + { + Dictionary uniqueVectorCount = new Dictionary(); + //determine which vector shows up the most often + foreach (Vector.CartVect distinctVector in distinctRHRs) + { + int count = 0; + foreach (Vector.CartVect vect in RHRs) + { + if (distinctVector.X == vect.X && distinctVector.Y == vect.Y && distinctVector.Z == vect.Z) + { + count++; + } + } + uniqueVectorCount.Add(count, distinctVector); + } + + //returns the vector that has the largest count + //get the largest integer in the list of + //may also be able to use + //uniqueVectorCount.Keys.Max(); + List keysList = uniqueVectorCount.Keys.ToList(); + keysList.Sort(); + int max = 0; + + foreach (int key in keysList) + { + if (key > max) { max = key; } + } + plRHRVect = uniqueVectorCount[max]; + return plRHRVect; + } + } + + private DOEgbXMLReportingObj GetPossibleSurfaceMatches(SurfaceDefinitions surface, List TestSurfaces, DOEgbXMLReportingObj report) + { + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Mar 14 2013 + report.testSummary = "This test tries to match each Surface element in the standard file with an equivalent in your test file"; + report.testSummary += " To be as flexible about what constitutes a \"Good Match\", this test finds a pool of possible candidate "; + report.testSummary += "surfaces in your test file and then begins to eliminate them as they fail different tests."; + report.testSummary += " At the end, there should be only one surface candidate remaining that constitutes a good match. "; + report.testSummary += "You can see the result of this filtering process by reviewing the mini-report that is provided for you below."; + report.testSummary += "
"; + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added March 14 2013 + report.testSummary += " The search routine first tries to find all surfaces that have the same SurfaceType and adjacentSpaceIds."; + report.testSummary += " Everytime there is a match found in the test file, meeting these criteria, a message will appear in the "; + report.testSummary += "mini-report, indicating that a match has been found."; + report.testSummary += " There may be more than one match in your test file."; + report.testSummary += " If there are no matches found for SurfaceType and AdjacencyId, this message will be printed (and the test will end as failed):"; + report.testSummary += " In the test file, no matches could be found in the standard file that have the same AdjacentSpaceId(s) and SurfaceType."; + report.testSummary += "
"; + report.testSummary += " If this set of tests is successful, the routine next tries to remove those surfaces that do not meet"; + report.testSummary += " the tilt and azimuth tolerances. Let's pretend for example that the tilt and azimuth for the standard surface"; + report.testSummary += " in question are both 90 degrees. If the tilt and azimuth test tolerance are 1 degree, then the search"; + report.testSummary += " routine will only keep those walls that have 89<=tilt<=91 && <=89azimuth<=91 && match the SurfaceType and"; + report.testSummary += " adjacency relationships."; + report.testSummary += " The mini-report will let you know which surfaces pass the tilt and azimuth test and which do not."; + report.testSummary += "
"; + report.testSummary += " Next the search routine takes any of the remaining surface candidates that have passed all the tests so far, "; + report.testSummary += "and tries to determine if the Surface Areas defined by the polyLoops match to within a pre-defined % tolerance."; + report.testSummary += "
"; + report.testSummary += " the final tests are to physically test the coordinates of the polyloop and insertion point to make sure"; + report.testSummary += " that a match for the standard surface can be found."; + report.testSummary += " You should see additional messages telling you which surface in your test file matches, or doesn't match"; + report.testSummary += " the standard surface being searched against. If there is no match, the mini-report tells you."; + report.testSummary += " By making the tests this way, it is hoped that you can see exactly why your test file is failing against"; + report.testSummary += " the standard file's surface definitions."; + + try + { + report.MessageList.Add("Standard Surface Id: " + surface.SurfaceId); + report.MessageList.Add("
"); + //initialize the return list + //alternate between these two to filter out bad matches + List possiblesList1 = new List(); + List possiblesList2 = new List(); + + bool adjSpaceIdMatch = false; + //try to find a surface in the test file that has the same: + //adjacent space Id signature + //surfaceType + //free list is 1 + //list 2 is not used + foreach (SurfaceDefinitions testSurface in TestSurfaces) + { + //has to have the same number of Adjacent Space Ids + if (testSurface.AdjSpaceId.Count == surface.AdjSpaceId.Count) + { + //an exception for a shading device + if (surface.AdjSpaceId.Count == 0) { adjSpaceIdMatch = true; } + + foreach (string testAdjSpaceId in testSurface.AdjSpaceId) + { + //loop only returns true if all AdjSpaceIds in both surfaces are identical + adjSpaceIdMatch = false; + foreach (string standardAdjSpaceId in surface.AdjSpaceId) + { + if (testAdjSpaceId == standardAdjSpaceId) { adjSpaceIdMatch = true; } + } + } + //if adjacent space Ids match and the surface types match, note this + if (adjSpaceIdMatch && testSurface.SurfaceType == surface.SurfaceType) + { + report.MessageList.Add("AdjancentSpaceId(s) and surfaceType Match."); + report.MessageList.Add("Surface id: " + testSurface.SurfaceId + " is a candidate."); + report.MessageList.Add("
"); + possiblesList1.Add(testSurface); + } + } + } + if (possiblesList1.Count == 1) + { + report.MessageList.Add("Based on a comparison of the surface Type and Adjacent SpaceIds, there is " + possiblesList1.Count.ToString() + " surface in the test file that is a possible match for " + surface.SurfaceId + " of the Standard File."); + report.MessageList.Add("
"); + } + else if (possiblesList1.Count > 1) + { + report.MessageList.Add("Based on a comparison of the surface Type and Adjacent SpaceIds, there are " + possiblesList1.Count.ToString() + " surface in the test file that are possible matches for " + surface.SurfaceId + " of the Standard File."); + report.MessageList.Add("
"); + } + else + { + report.longMsg = "In the test file, no matches could be found in the standard file that have the same AdjacentSpaceId(s) and SurfaceType."; + report.passOrFail = false; + return report; + } + //begin to filter back this list + //tilt + //azimuth + //list 1 is analyzed + //list 2 is free + + if (possiblesList1.Count > 0) + { + foreach (SurfaceDefinitions testSurface in possiblesList1) + { + double tiltDifference = Math.Abs(testSurface.Tilt - surface.Tilt); + double azimuthDifference = Math.Abs(testSurface.Azimuth - surface.Azimuth); + //if the tilt and azimuth is outside of tolerance + if (tiltDifference > DOEgbXMLBasics.Tolerances.SurfaceTiltTolerance || azimuthDifference > DOEgbXMLBasics.Tolerances.SurfaceAzimuthTolerance) + { + report.MessageList.Add("Test file's Surface id: " + testSurface.SurfaceId + " azimuth and tilt match FAILED: "); + report.MessageList.Add("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); + report.MessageList.Add("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString()); + report.MessageList.Add(testSurface.SurfaceId + " has been removed as a candidate for matching."); + report.MessageList.Add("
"); + continue; + } + //if the tilt and azimuth is within tolerance + else + { + //add to the free List + possiblesList2.Add(testSurface); + if (tiltDifference == 0 && azimuthDifference == 0) + { + report.MessageList.Add("Test surface with id: " + testSurface.SurfaceId + " matches the standard surface tilt and azimuth exactly."); + report.MessageList.Add("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); + report.MessageList.Add("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString()); + + report.MessageList.Add("
"); + } + else + { + report.MessageList.Add("Test surface with id: " + testSurface.SurfaceId + " is within the azimuth and tilt tolerances of " + DOEgbXMLBasics.Tolerances.SurfaceAzimuthTolerance + " and " + DOEgbXMLBasics.Tolerances.SurfaceTiltTolerance + ", respectively. It matches the standard file surface within the allowable tolerance."); + report.MessageList.Add("Test file surface (Azimuth, Tilt): (" + testSurface.Azimuth.ToString() + "," + testSurface.Tilt.ToString() + ")"); + report.MessageList.Add("Standard file surface (Azimuth, Tilt): (" + surface.Azimuth.ToString() + "," + surface.Tilt.ToString()); + + report.MessageList.Add("
"); + } + } + } + } + // report to the user that no matches could be found + else + { + report.longMsg = "In the test file, surfaces could be found that match the standard file's AdjacentSpaceId and SurfaceType, but of these matches, none could be identified that also have a tilt or azimuth that exactly matches the standard file's, or is within the allowable tolerance."; + report.passOrFail = false; + return report; + } + //clear the first list + possiblesList1.Clear(); + //start to loop through the new refined list + //generally want to look at the polyLoop coordinates + //list 2 is analyzed + //list 1 is free + report.MessageList.Add("Starting Surface Area Match tests......"); + report.MessageList.Add("
"); + if (possiblesList2.Count > 0) + { + //simple method from this point forward is just to simply start doing a polyloop check + //check the standard surface PolyLoop and the test Surface(s) polyloop(s) + //check the absolute coordinates of the testSurface(s) polyloop(s) + + if (possiblesList2.Count == 1) + { + report.MessageList.Add("Only one Surface Candidate remaining from the original test pool."); + report.MessageList.Add("
"); + //meaning there is only one candidate still available + //go on to test the polyLoop coordinates and the insertion point + possiblesList1.Add(possiblesList2[0]); + + + } + //more than one candidate still exists even after the adjacency test, surfaceType test, and tilt and azimuth tests, so filter through + else + { + //The user should be able to determine, based on output which surfaces are left for consideration + //Option 1: (easiest) find the one best candidate + //do so based on an area match, matching the area of the test surface with the area of the test surface + //(without regard for absolute polyloop coordinates) + + //We find the area using area formulas for both regular polygons and irregular polygons + //first we check for the type of surface that it is (regular polygon or not), and we then take it from there + //in the case of a rectangular polygon, we only count rectangles or squares as regular, everything else is + //assumed to be irregular, though this does not fit the classic definition of a classic polygon. + //The language is just semantics + + //first try to find if the standard file has a regular rectangular or square profile + report.MessageList.Add("Checking if the surface is a square or rectangle."); + bool isRegular = IsSurfaceRegular(surface); + foreach (SurfaceDefinitions regSurface in possiblesList2) + { + //ensures likewise that all the test surface candidates are regular, + //if they are not, then the entire set is assumed to be irregular + isRegular = IsSurfaceRegular(regSurface); + if (isRegular == false) break; + } + if (isRegular) + { + //we take a shortcut and use the width and height as a way to simplify the area checking scheme + //we assume that the width and height are properly entered in this simplified case + report.MessageList.Add("Rectangle or Square = TRUE"); + report.MessageList.Add("Comparisons of the Width and Height values will be used as a proxy for surface Area."); + foreach (SurfaceDefinitions testsurface in possiblesList2) + { + //it first analyzes the test file to see if slivers are present. If they are, it will fail the test + //if slivers are not allowed for the test. This is the first time we check for slivers + if (testsurface.Width <= DOEgbXMLBasics.Tolerances.SliverDimensionTolerance || testsurface.Height <= DOEgbXMLBasics.Tolerances.SliverDimensionTolerance) + { + if (!DOEgbXMLBasics.SliversAllowed) + { + report.MessageList.Add("This test does not allow slivers less than " + DOEgbXMLBasics.Tolerances.SliverDimensionTolerance + " ft. A sliver has been detected. Test surface id: " + testsurface.SurfaceId + " is a sliver."); + report.passOrFail = false; + return report; + } + } + //otherwise, if the sliver test passes + double widthDiff = Math.Abs(testsurface.Width - surface.Width); + double heightDiff = Math.Abs(testsurface.Height - surface.Height); + if (widthDiff > DOEgbXMLBasics.Tolerances.SurfaceWidthTolerance || + heightDiff > DOEgbXMLBasics.Tolerances.SurfaceHeightTolerance) + { + report.MessageList.Add("Test file's Surface id: " + testsurface.SurfaceId + " width and height do not both match the standard file surface id: " + surface.SurfaceId + ". This surface has been removed as a candidate."); + continue; + } + else + { + //this surface is a candidate + possiblesList1.Add(testsurface); + if (widthDiff == 0 && heightDiff == 0) + { + report.MessageList.Add("Test file surface with id: " + testsurface.SurfaceId + " matches the width and height exactly of the standard file."); + //go ahead and now check the polyLoop coordinates, and then the insertion point + } + else + { + report.MessageList.Add("Test file surface with id: " + testsurface.SurfaceId + " is within the width and height tolerances of " + DOEgbXMLBasics.Tolerances.SurfaceWidthTolerance + " ft and " + DOEgbXMLBasics.Tolerances.SurfaceHeightTolerance + "ft, respectively."); + //go ahead and now check the polyloop coordinates, and then the insertion point + } + } + } + } + //It is not "regular". Find the one surface with the area that most closely matches, and then check its polyloops + //1. get the polyloop area of the standard file's surface polyloops + //2. get the area of the test file surface candidates using the polyloop coordinates + else + { + report.MessageList.Add("The surface is not a square or rectangle."); + report.MessageList.Add("PolyLoop coordinates will be used to calculate the area."); + //there are two basic cases, one where we get the area using greens theorem when the surface is parallel + //to one of the axes of the project global reference frame + //and the second where the surface is not parallel to one of the axes of the global reference frame + //Surface normal Parallel to global reference frame X Axis + if (Math.Abs(surface.PlRHRVector.X) == 1 && surface.PlRHRVector.Y == 0 && surface.PlRHRVector.Z == 0) + { + List coordList = new List(); + foreach (Vector.CartCoord coord in surface.PlCoords) + { + //only take the Y and Z coordinates and throw out the X because we can assume that they are all the same + coord.X = 0; + coordList.Add(coord); + + } + double area = GetAreaFrom2DPolyLoop(coordList); + if (area == -999) + { + report.MessageList.Add("The coordinates of the standard file polyloop has been incorrectly defined."); + report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); + report.MessageList.Add("Test may be inaccurate and requires gbXML.org support"); + + } + double testSurfacesArea = 0; + + foreach (SurfaceDefinitions testSurface in possiblesList2) + { + if (Math.Abs(testSurface.PlRHRVector.X) == 1 && testSurface.PlRHRVector.Y == 0 && + testSurface.PlRHRVector.Z == 0) + { + List testCoordList = new List(); + foreach (Vector.CartCoord coord in testSurface.PlCoords) + { + coord.X = 0; + testCoordList.Add(coord); + } + testSurfacesArea = GetAreaFrom2DPolyLoop(testCoordList); + if (testSurfacesArea == -999) + { + report.MessageList.Add("The coordinates of the test file polyloop has been incorrectly defined."); + report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); + } + double difference = Math.Abs(area - testSurfacesArea); + if (difference < area * DOEgbXMLBasics.Tolerances.SurfaceAreaPercentageTolerance) + { + possiblesList1.Add(testSurface); + if (difference == 0) + { + //then it perfectly matches, go on to check the poly loop coordinates + //then check the insertion point + report.MessageList.Add("The test surface: " + testSurface.SurfaceId + " polyloop surface area matches the polyLoop surface area of the standard surface: " + surface.SurfaceId + " exactly."); + } + else + { + report.MessageList.Add("The test surface: " + testSurface.SurfaceId + " polyloop surface area matches the polyLoop surface area of the standard surface: " + surface.SurfaceId + " within the allowable area percentage tolerance."); + } + } + else + { + report.MessageList.Add("The test surface cannot find a match for its surface area as defined in the polyLoop coordinates"); + //don't return here, it will be returned below + } + } + else + { + //do nothing, it will be handled by the more general case and then translated to a 2-D surface + } + } + + + } + //Surface normal Parallel to global reference frame y Axis + else if (surface.PlRHRVector.X == 0 && Math.Abs(surface.PlRHRVector.Y) == 1 && surface.PlRHRVector.Z == 0) + { + List coordList = new List(); + foreach (Vector.CartCoord coord in surface.PlCoords) + { + //only take the X and Z coordinates and throw out the Y because we can assume that they are all the same + coord.Y = 0; + coordList.Add(coord); + + } + double area = GetAreaFrom2DPolyLoop(coordList); + if (area == -999) + { + report.MessageList.Add("The coordinates of the standard file polyloop has been incorrectly defined."); + report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); + report.MessageList.Add("Test may be inaccurate and requires gbXML.org support"); + + } + double testSurfacesArea = 0; + + foreach (SurfaceDefinitions testSurface in possiblesList2) + { + if (Math.Abs(testSurface.PlRHRVector.X) == 0 && Math.Abs(testSurface.PlRHRVector.Y) == 1 && testSurface.PlRHRVector.Z == 0) + { + List testCoordList = new List(); + foreach (Vector.CartCoord coord in testSurface.PlCoords) + { + coord.Y = 0; + testCoordList.Add(coord); + } + testSurfacesArea = GetAreaFrom2DPolyLoop(testCoordList); + if (testSurfacesArea == -999) + { + report.MessageList.Add("The coordinates of the test file polyloop has been incorrectly defined."); + report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); + } + double difference = Math.Abs(area - testSurfacesArea); + if (difference < area * DOEgbXMLBasics.Tolerances.SurfaceAreaPercentageTolerance) + { + possiblesList1.Add(testSurface); + if (difference == 0) + { + //then it perfectly matches, go on to check the poly loop coordinates + //then check the insertion point + report.MessageList.Add("The test surface: " + testSurface.SurfaceId + " polyloop surface area matches the polyLoop surface area of the standard surface: " + surface.SurfaceId + " exactly."); + } + else + { + report.MessageList.Add("The test surface: " + testSurface.SurfaceId + " polyloop surface area matches the polyLoop surface area of the standard surface: " + surface.SurfaceId + " within the allowable area percentage tolerance."); + } + } + else + { + report.MessageList.Add("The test surface cannot find a match for its surface area as defined in the polyLoop coordinates"); + //don't return here, it will be returned below + } + } + else + { + //do nothing, it will be handled by the more general code below and translated to 2D + } + } + } + else if (surface.PlRHRVector.X == 0 && surface.PlRHRVector.Y == 0 && Math.Abs(surface.PlRHRVector.Z) == 1) + { + List coordList = new List(); + foreach (Vector.CartCoord coord in surface.PlCoords) + { + //only take the X and Y coordinates and throw out the Z because we can assume that they are all the same + coord.Z = 0; + coordList.Add(coord); + + } + double area = GetAreaFrom2DPolyLoop(coordList); + if (area == -999) + { + report.MessageList.Add("The coordinates of the standard file polyloop has been incorrectly defined."); + report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); + report.MessageList.Add("Test may be inaccurate and requires gbXML.org support"); + + } + double testSurfacesArea = 0; + + foreach (SurfaceDefinitions testSurface in possiblesList2) + { + if (Math.Abs(testSurface.PlRHRVector.X) == 0 && testSurface.PlRHRVector.Y == 0 && Math.Abs(testSurface.PlRHRVector.Z) == 1) + { + List testCoordList = new List(); + foreach (Vector.CartCoord coord in testSurface.PlCoords) + { + coord.Z = 0; + testCoordList.Add(coord); + } + testSurfacesArea = GetAreaFrom2DPolyLoop(testCoordList); + if (testSurfacesArea == -999) + { + report.MessageList.Add("The coordinates of the test file polyloop has been incorrectly defined."); + report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); + } + double difference = Math.Abs(area - testSurfacesArea); + if (difference < area * DOEgbXMLBasics.Tolerances.SurfaceAreaPercentageTolerance) + { + possiblesList1.Add(testSurface); + if (difference == 0) + { + //then it perfectly matches, go on to check the poly loop coordinates + //then check the insertion point + report.MessageList.Add("The test surface: " + testSurface.SurfaceId + " polyloop surface area matches the polyLoop surface area of the standard surface: " + surface.SurfaceId + " exactly."); + } + else + { + report.MessageList.Add("The test surface: " + testSurface.SurfaceId + " polyloop surface area matches the polyLoop surface area of the standard surface: " + surface.SurfaceId + " within the allowable area percentage tolerance."); + } + } + else + { + report.MessageList.Add("The test surface cannot find a match for its surface area as defined in the polyLoop coordinates"); + //don't return here, it will be returned below + } + } + else + { + //do nothing. The code below will handle the more general case where it is not aligned with reference frame axes + } + } + } + //the surface is not aligned with one of the reference frame axes, which requires a bit more work to determine the right answer. + else + { + report.MessageList.Add("The standard surface is not aligned along an axis, and will be rotated into a new coordinate frame"); + //New Z Axis for this plane is the normal vector, does not need to be created + //Get New Y Axis which is the surface Normal Vector cross the original global reference X unit vector (all unit vectors please + Vector.CartVect localY = new Vector.CartVect(); + Vector.CartVect globalReferenceX = new Vector.CartVect(); + globalReferenceX.X = 1; + globalReferenceX.Y = 0; + globalReferenceX.Z = 0; + localY = Vector.CrossProduct(surface.PlRHRVector, globalReferenceX); + localY = Vector.UnitVector(localY); + + //new X axis is the localY cross the surface normal vector + Vector.CartVect localX = new Vector.CartVect(); + localX = Vector.CrossProduct(localY, surface.PlRHRVector); + localX = Vector.UnitVector(localX); + + //convert the polyloop coordinates to a local 2-D reference frame + //using a trick employed by video game programmers found here http://stackoverflow.com/questions/1023948/rotate-normal-vector-onto-axis-plane + List translatedCoordinates = new List(); + Vector.CartCoord newOrigin = new Vector.CartCoord(); + newOrigin.X = 0; + newOrigin.Y = 0; + newOrigin.Z = 0; + translatedCoordinates.Add(newOrigin); + for (int j = 1; j < surface.PlCoords.Count; j++) + { + //randomly assigns the first polyLoop coordinate as the origin + Vector.CartCoord origin = surface.PlCoords[0]; + //captures the components of a vector drawn from the new origin to the + Vector.CartVect distance = new Vector.CartVect(); + distance.X = surface.PlCoords[j].X - origin.X; + distance.Y = surface.PlCoords[j].Y - origin.Y; + distance.Z = surface.PlCoords[j].Z - origin.Z; + Vector.CartCoord translatedPt = new Vector.CartCoord(); + //x coordinate is distance vector dot the new local X axis + translatedPt.X = distance.X * localX.X + distance.Y * localX.Y + distance.Z * localX.Z; + //y coordinate is distance vector dot the new local Y axis + translatedPt.Y = distance.X * localY.X + distance.Y * localY.Y + distance.Z * localY.Z; + translatedPt.Z = 0; + translatedCoordinates.Add(translatedPt); + + } + double area = GetAreaFrom2DPolyLoop(translatedCoordinates); + if (area == -999) + { + report.MessageList.Add("The coordinates of the standard file polyloop has been incorrectly defined."); + report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); + report.MessageList.Add("Test may be inaccurate and requires gbXML.org support"); + + } + //get the area of the test candidates using the polyloop coordinates + foreach (SurfaceDefinitions testSurface in possiblesList2) + { + Vector.CartVect testlocalY = new Vector.CartVect(); + Vector.CartVect testglobalReferenceX = new Vector.CartVect(); + globalReferenceX.X = 1; + globalReferenceX.Y = 0; + globalReferenceX.Z = 0; + testlocalY = Vector.CrossProduct(surface.PlRHRVector, testglobalReferenceX); + testlocalY = Vector.UnitVector(testlocalY); + + //new X axis is the localY cross the surface normal vector + Vector.CartVect testlocalX = new Vector.CartVect(); + testlocalX = Vector.CrossProduct(testlocalY, surface.PlRHRVector); + testlocalX = Vector.UnitVector(testlocalX); + + //convert the polyloop coordinates to a local 2-D reference frame + //using a trick employed by video game programmers found here http://stackoverflow.com/questions/1023948/rotate-normal-vector-onto-axis-plane + List testtranslatedCoordinates = new List(); + Vector.CartCoord newOriginTest = new Vector.CartCoord(); + newOrigin.X = 0; + newOrigin.Y = 0; + newOrigin.Z = 0; + testtranslatedCoordinates.Add(newOriginTest); + for (int j = 1; j < surface.PlCoords.Count; j++) + { + //randomly assigns the first polyLoop coordinate as the origin + Vector.CartCoord origin = testSurface.PlCoords[0]; + //captures the components of a vector drawn from the new origin to the + Vector.CartVect distance = new Vector.CartVect(); + distance.X = testSurface.PlCoords[j].X - origin.X; + distance.Y = testSurface.PlCoords[j].Y - origin.Y; + distance.Z = testSurface.PlCoords[j].Z - origin.Z; + Vector.CartCoord translatedPt = new Vector.CartCoord(); + //x coordinate is distance vector dot the new local X axis + translatedPt.X = distance.X * localX.X + distance.Y * localX.Y + distance.Z * localX.Z; + //y coordinate is distance vector dot the new local Y axis + translatedPt.Y = distance.X * localY.X + distance.Y * localY.Y + distance.Z * localY.Z; + translatedPt.Z = 0; + testtranslatedCoordinates.Add(translatedPt); + + } + double testarea = GetAreaFrom2DPolyLoop(translatedCoordinates); + if (testarea == -999) + { + report.MessageList.Add("The coordinates of the test file polyloop has been incorrectly defined."); + report.MessageList.Add("The coordinates should be 2D and could not be translated to 2D"); + } + double difference = Math.Abs(area - testarea); + if (difference < area * DOEgbXMLBasics.Tolerances.SurfaceAreaPercentageTolerance) + { + possiblesList1.Add(testSurface); + //within reason + if (difference == 0) + { + report.MessageList.Add + ("The test surface: " + testSurface.SurfaceId + + " polyloop surface area matches the polyLoop surface area of the standard surface: " + + surface.SurfaceId + " exactly."); + } + else + { + report.MessageList.Add + ("The test surface: " + testSurface.SurfaceId + + " polyloop surface area matches the polyLoop surface area of the standard surface: " + + surface.SurfaceId + " within the allowable area percentage tolerance."); + } + } + else + { + //not within reason, so the test will fail + //don't return yet, it will be returned below when possiblesList1 is found empty + } + } + } + } + } + + possiblesList2.Clear(); + //polyLoop absolute coordinates + //list 1 is analyzed + //list 2 is free + report.MessageList.Add("
"); + report.MessageList.Add("Starting PolyLoop coordinate comparisons......."); + report.MessageList.Add("
"); + if (possiblesList1.Count > 0) + { + + foreach (SurfaceDefinitions testSurface in possiblesList1) + { + //check the polyLoop coordinates + foreach (Vector.CartCoord standardPolyLoopCoord in surface.PlCoords) + { + report = GetPolyLoopCoordMatch(standardPolyLoopCoord, testSurface, report, surface.SurfaceId); + if (report.passOrFail) + { + continue; + } + else + { + report.MessageList.Add("Could not find a coordinate match in the test surface polyloop."); + break; + } + } + if (report.passOrFail) + { + possiblesList2.Add(testSurface); + } + } + } + else + { + report.longMsg = "In the test file, no surfaces could be found that match standard file;s Surface Id: " + surface.SurfaceId + " AdjacentSpaceId(s), SurfaceType, Tilt, Azimuth, and Surface Area. Failed when attempting to match the surface area."; + report.passOrFail = false; + return report; + } + possiblesList1.Clear(); + report.MessageList.Add("
"); + report.MessageList.Add("Starting Insertion Point Coordinate comparisons......."); + report.MessageList.Add("
"); + if (possiblesList2.Count > 0) + { + //check the insertion point coordinate + foreach (SurfaceDefinitions testSurface in possiblesList2) + { + //now match the differences + double insPtXDiff = Math.Abs(testSurface.InsertionPoint.X - surface.InsertionPoint.X); + double insPtYDiff = Math.Abs(testSurface.InsertionPoint.Y - surface.InsertionPoint.Y); + double insPtZDiff = Math.Abs(testSurface.InsertionPoint.Z - surface.InsertionPoint.Z); + if (insPtXDiff > DOEgbXMLBasics.Tolerances.SurfaceInsPtXTolerance || insPtYDiff > DOEgbXMLBasics.Tolerances.SurfaceInsPtYTolerance || insPtZDiff > DOEgbXMLBasics.Tolerances.SurfaceInsPtZTolerance) + { + report.MessageList.Add("Test file's Surface id: " + testSurface.SurfaceId + " insertion point coordinates do not both match the standard file surface id: " + surface.SurfaceId + ". It has been removed as a candidate."); + continue; + } + else + { + //possible match + possiblesList1.Add(testSurface); + if (insPtXDiff == 0 && insPtYDiff == 0 && insPtZDiff == 0) + { + //perfect match + report.MessageList.Add("Test file's Surface with id: " + testSurface.SurfaceId + " matches the insertion point in the standard file exactly."); + } + else + { + //perfect match + report.MessageList.Add(" Test file's Surface with id: " + testSurface.SurfaceId + " has an insertion point that is within the allowable tolerances of X:" + DOEgbXMLBasics.Tolerances.SurfaceInsPtXTolerance + " ft, Y:" + DOEgbXMLBasics.Tolerances.SurfaceInsPtYTolerance + "ft, Z:" + DOEgbXMLBasics.Tolerances.SurfaceInsPtZTolerance + "ft."); + } + } + + } + } + else + { + report.longMsg = "In the test file, no surfaces could be found that match standard file;s Surface Id: " + surface.SurfaceId + " AdjacentSpaceId(s), SurfaceType, Tilt, Azimuth, Surface Area, and PolyLoop Coordinates. Failed when matching PolyLoop coordinates."; + report.passOrFail = false; + return report; + } + if (possiblesList1.Count == 1) + { + report.longMsg = "Advanced Surface Test found a match for Standard file surface id: " + surface.SurfaceId + " in the test file. Only one match was found to be within all the tolerances allowed. Surface id: " + possiblesList2[0].SurfaceId + "."; + report.passOrFail = true; + List testFileSurfIds = new List(); + foreach (SurfaceDefinitions surf in possiblesList1) { testFileSurfIds.Add(surf.SurfaceId); } + + globalMatchObject.MatchedSurfaceIds.Add(surface.SurfaceId, testFileSurfIds); + return report; + } + else if (possiblesList1.Count == 0) + { + report.longMsg = "In the test file, no surfaces could be found that match standard file;s Surface Id: " + surface.SurfaceId + " AdjacentSpaceId(s), SurfaceType, Tilt, Azimuth, Surface Area, PolyLoop Coordinates, and Insertion Point. Failed when attempting to match the insertion point coordinates."; + report.passOrFail = false; + return report; + } + else if (possiblesList1.Count > 1) + { + report.longMsg = "Advanced Surface Test found more than one match for Standard file surface id: " + surface.SurfaceId + " in the test file. It was not possible to determine only one unique surface."; + report.passOrFail = false; + //List testFileSurfIds = new List(); + //foreach (SurfaceDefinitions surf in possiblesList1) { testFileSurfIds.Add(surf.SurfaceId); } + //report.MatchedSurfaceIds.Add(surface.SurfaceId, testFileSurfIds); + return report; + } + return report; + } + return report; + + } + catch (Exception e) + { + report.longMsg = (e.ToString()); + return report; + } + } + + private static DOEgbXMLReportingObj GetPolyLoopCoordMatch(Vector.CartCoord standardPolyLoopCoord, SurfaceDefinitions testSurface, DOEgbXMLReportingObj report, string standardSurfaceId) + { + List possibleMatch = new List(); + List exactMatch = new List(); + report.MessageList.Add("Testing Polyloop coordinates for Standard surface " + standardSurfaceId); + report.MessageList.Add(" X: " + standardPolyLoopCoord.X.ToString() + ", Y: " + standardPolyLoopCoord.Y.ToString() + ", Z: " + standardPolyLoopCoord.Z.ToString()); + foreach (Vector.CartCoord testPolyLoopCoord in testSurface.PlCoords) + { + + //find an appropriate match + double diffX = Math.Abs(testPolyLoopCoord.X - standardPolyLoopCoord.X); + if (diffX < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance) + { + //found a perfect X Match + if (diffX == 0) + { + //test Y + double diffY = Math.Abs(testPolyLoopCoord.Y - standardPolyLoopCoord.Y); + if (diffY < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance) + { + //perfect Y Match + if (diffY == 0) + { + double diffZ = Math.Abs(testPolyLoopCoord.Z - standardPolyLoopCoord.Z); + if (diffZ < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance) + { + //perfect Z match + if (diffZ == 0) + { + report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + " exactly"); + report.MessageList.Add("Test Surface " + testSurface.SurfaceId); + report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); + exactMatch.Add(testPolyLoopCoord); + } + else + { + //not a perfect Z match but within bounds + report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + " X and Y coordinates exactly. Z coordinate within allowable tolerance."); + report.MessageList.Add("Test Surface " + testSurface.SurfaceId); + report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); + possibleMatch.Add(testPolyLoopCoord); + } + } + else + { + //z coordinate not within tolerance + continue; + } + } + //Y Match is within the allowable tolerance + else + { + double diffZ = Math.Abs(testPolyLoopCoord.Z - standardPolyLoopCoord.Z); + if (diffZ < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance) + { + //perfect Z match + if (diffZ == 0) + { + report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + " in the X and Z coordinates, exactly. Y coordinate is within tolerance."); + report.MessageList.Add("Test Surface " + testSurface.SurfaceId); + report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); + possibleMatch.Add(testPolyLoopCoord); + } + else + { + report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + " X exactly. Y and Z coordinates are within tolerance."); + report.MessageList.Add("Test Surface " + testSurface.SurfaceId); + report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); + possibleMatch.Add(testPolyLoopCoord); + } + } + else + { + //z coordinate is not within tolerance + continue; + } + } + } + else + { + //a y match could not be found within tolerance + continue; + } + + } + else + { + //not a perfect X match, but within tolerance + //test Y + double diffY = Math.Abs(testPolyLoopCoord.Y - standardPolyLoopCoord.Y); + if (diffY < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance) + { + //perfect Y Match + if (diffY == 0) + { + double diffZ = Math.Abs(testPolyLoopCoord.Z - standardPolyLoopCoord.Z); + if (diffZ < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance) + { + //perfect Z match + if (diffZ == 0) + { + report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + " Y and Z coordinate exactly. X is within tolerance."); + report.MessageList.Add("Test Surface " + testSurface.SurfaceId); + report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); + possibleMatch.Add(testPolyLoopCoord); + } + else + { + report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + " Y coordinate exactly. X and Z is within tolerance."); + report.MessageList.Add("Test Surface " + testSurface.SurfaceId); + report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); + possibleMatch.Add(testPolyLoopCoord); + } + } + else + { + //z is not matched so continue + continue; + } + } + // the Y match is not perfect but within tolerance + else + { + double diffZ = Math.Abs(testPolyLoopCoord.Z - standardPolyLoopCoord.Z); + if (diffZ < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance) + { + //perfect Z match + if (diffZ == 0) + { + report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + " Z coordinate exactly. The X and Y coordinates are within tolerance."); + report.MessageList.Add("Test Surface " + testSurface.SurfaceId); + report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); + possibleMatch.Add(testPolyLoopCoord); + } + else + { + report.MessageList.Add("Test Surface " + testSurface.SurfaceId + ": Found polyLoop coordinate that matches Standard Surface " + standardSurfaceId + ". The X, Y, and Z coordinates are within tolerance."); + report.MessageList.Add("Test Surface " + testSurface.SurfaceId); + report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); + possibleMatch.Add(testPolyLoopCoord); + } + } + // no match found for the Z + else + { + continue; + } + } + } + //no match could be found for the Y + else + { + continue; + } + } + } + else + { + //not a match found for the X and continue + continue; + } + } + if (exactMatch.Count > 1) + { + report.MessageList.Add("Error, overlapping polyLoop coordinates found in the Test Surface PolyLoop."); + report.passOrFail = false; + return report; + } + else if (exactMatch.Count == 1) + { + report.MessageList.Add("One coordinate candidate found. Exact match"); + report.passOrFail = true; + return report; + } + if (possibleMatch.Count > 1) + { + report.MessageList.Add("No exact solution for a match of the polyLoop coordinate. More than one coordinate candidate found."); + report.passOrFail = false; + return report; + } + else if (possibleMatch.Count == 1) + { + report.MessageList.Add("One coordinate candidate found."); + report.passOrFail = true; + return report; + } + else + { + report.MessageList.Add("No coordinate candidate found."); + report.passOrFail = false; + return report; + } + + } + + private static DOEgbXMLReportingObj GetOpeningPolyLoopCoordMatch(Vector.CartCoord standardPolyLoopCoord, OpeningDefinitions testOpening, DOEgbXMLReportingObj report, string standardOpeningId) + { + List possibleMatch = new List(); + List exactMatch = new List(); + report.MessageList.Add("Testing Polyloop coordinates for Standard opening " + standardOpeningId); + report.MessageList.Add(" X: " + standardPolyLoopCoord.X.ToString() + ", Y: " + standardPolyLoopCoord.Y.ToString() + ", Z: " + standardPolyLoopCoord.Z.ToString()); + foreach (Vector.CartCoord testPolyLoopCoord in testOpening.PlCoords) + { + + //find an appropriate match + double diffX = Math.Abs(testPolyLoopCoord.X - standardPolyLoopCoord.X); + if (diffX < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance) + { + //found a perfect X Match + if (diffX == 0) + { + //test Y + double diffY = Math.Abs(testPolyLoopCoord.Y - standardPolyLoopCoord.Y); + if (diffY < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance) + { + //perfect Y Match + if (diffY == 0) + { + double diffZ = Math.Abs(testPolyLoopCoord.Z - standardPolyLoopCoord.Z); + if (diffZ < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance) + { + //perfect Z match + if (diffZ == 0) + { + report.MessageList.Add("Test Opening " + testOpening.OpeningId + ": Found polyLoop coordinate that matches Standard Opening " + standardOpeningId + " exactly"); + report.MessageList.Add("Test Opening " + testOpening.OpeningId); + report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); + exactMatch.Add(testPolyLoopCoord); + } + else + { + //not a perfect Z match but within bounds + report.MessageList.Add("Test Opening " + testOpening.OpeningId + ": Found polyLoop coordinate that matches Standard Opening " + standardOpeningId + " X and Y coordinates exactly. Z coordinate within allowable tolerance."); + report.MessageList.Add("Test Opening " + testOpening.OpeningId); + report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); + possibleMatch.Add(testPolyLoopCoord); + } + } + else + { + //z coordinate not within tolerance + continue; + } + } + //Y Match is within the allowable tolerance + else + { + double diffZ = Math.Abs(testPolyLoopCoord.Z - standardPolyLoopCoord.Z); + if (diffZ < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance) + { + //perfect Z match + if (diffZ == 0) + { + report.MessageList.Add("Test Opening " + testOpening.OpeningId + ": Found polyLoop coordinate that matches Standard Opening " + standardOpeningId + " in the X and Z coordinates, exactly. Y coordinate is within tolerance."); + report.MessageList.Add("Test Opening " + testOpening.OpeningId); + report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); + possibleMatch.Add(testPolyLoopCoord); + } + else + { + report.MessageList.Add("Test Opening " + testOpening.OpeningId + ": Found polyLoop coordinate that matches Standard Opening " + standardOpeningId + " X exactly. Y and Z coordinates are within tolerance."); + report.MessageList.Add("Test Opening " + testOpening.OpeningId); + report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); + possibleMatch.Add(testPolyLoopCoord); + } + } + else + { + //z coordinate is not within tolerance + continue; + } + } + } + else + { + //a y match could not be found within tolerance + continue; + } + + } + else + { + //not a perfect X match, but within tolerance + //test Y + double diffY = Math.Abs(testPolyLoopCoord.Y - standardPolyLoopCoord.Y); + if (diffY < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance) + { + //perfect Y Match + if (diffY == 0) + { + double diffZ = Math.Abs(testPolyLoopCoord.Z - standardPolyLoopCoord.Z); + if (diffZ < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance) + { + //perfect Z match + if (diffZ == 0) + { + report.MessageList.Add("Test Opening " + testOpening.OpeningId + ": Found polyLoop coordinate that matches Standard Opening " + standardOpeningId + " Y and Z coordinate exactly. X is within tolerance."); + report.MessageList.Add("Test Opening " + testOpening.OpeningId); + report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); + possibleMatch.Add(testPolyLoopCoord); + } + else + { + report.MessageList.Add("Test Opening " + testOpening.OpeningId + ": Found polyLoop coordinate that matches Standard Opening " + standardOpeningId + " Y coordinate exactly. X and Z is within tolerance."); + report.MessageList.Add("Test Opening " + testOpening.OpeningId); + report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); + possibleMatch.Add(testPolyLoopCoord); + } + } + else + { + //z is not matched so continue + continue; + } + } + // the Y match is not perfect but within tolerance + else + { + double diffZ = Math.Abs(testPolyLoopCoord.Z - standardPolyLoopCoord.Z); + if (diffZ < DOEgbXMLBasics.Tolerances.SurfacePLCoordTolerance) + { + //perfect Z match + if (diffZ == 0) + { + report.MessageList.Add("Test opening " + testOpening.OpeningId + ": Found polyLoop coordinate that matches Standard Opening " + standardOpeningId + " Z coordinate exactly. The X and Y coordinates are within tolerance."); + report.MessageList.Add("Test Opening " + testOpening.OpeningId); + report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); + possibleMatch.Add(testPolyLoopCoord); + } + else + { + report.MessageList.Add("Test opening " + testOpening.OpeningId + ": Found polyLoop coordinate that matches Standard Opening " + standardOpeningId + ". The X, Y, and Z coordinates are within tolerance."); + report.MessageList.Add("Test Opening " + testOpening.OpeningId); + report.MessageList.Add(" X: " + testPolyLoopCoord.X.ToString() + ", Y: " + testPolyLoopCoord.Y.ToString() + ", Z: " + testPolyLoopCoord.Z.ToString()); + possibleMatch.Add(testPolyLoopCoord); + } + } + // no match found for the Z + else + { + continue; + } + } + } + //no match could be found for the Y + else + { + continue; + } + } + } + else + { + //not a match found for the X and continue + continue; + } + } + if (exactMatch.Count > 1) + { + report.MessageList.Add("Error, overlapping polyLoop coordinates found in the Test Opening PolyLoop."); + report.passOrFail = false; + return report; + } + else if (exactMatch.Count == 1) + { + report.MessageList.Add("One coordinate candidate found. Exact match"); + report.passOrFail = true; + return report; + } + if (possibleMatch.Count > 1) + { + report.MessageList.Add("No exact solution for a match of the polyLoop coordinate. More than one coordinate candidate found."); + report.passOrFail = false; + return report; + } + else if (possibleMatch.Count == 1) + { + report.MessageList.Add("One coordinate candidate found."); + report.passOrFail = true; + return report; + } + else + { + report.MessageList.Add("No coordinate candidate found."); + report.passOrFail = false; + return report; + } + + } + + + + //March15 2013 + //by CHarriman Senior Product Manager Carmel Software Corporation + //this is a function only used internally. It is used to verify if a surface object only has four coordinates, and if those coordinates form + //a square or rectangle. + private static bool IsSurfaceRegular(SurfaceDefinitions Surface) + { + //tests to see if all candidate surfaces and the standard surface are regular (rectangular polygons) + + bool isRegularPolygon = true; + //see if the standard surface has four coordinates defining its polyloop (one marker of a rectangle) + int standSurfaceCoordinateCount = Surface.PlCoords.Count; + if (standSurfaceCoordinateCount == 4) + { + //check the two potentially parallel sides, to ensure they are indeed parallel + Vector.CartVect v1 = Vector.CreateVector(Surface.PlCoords[0], Surface.PlCoords[1]); + Vector.CartVect v2 = Vector.CreateVector(Surface.PlCoords[2], Surface.PlCoords[3]); + Vector.CartVect v1xv2 = Vector.CrossProduct(v1, v2); + v1xv2 = Vector.UnitVector(v1xv2); + double magnitudev1xv2 = Vector.VectorMagnitude(v1xv2); + Vector.CartVect v3 = Vector.CreateVector(Surface.PlCoords[1], Surface.PlCoords[2]); + Vector.CartVect v4 = Vector.CreateVector(Surface.PlCoords[3], Surface.PlCoords[0]); + Vector.CartVect v3xv4 = Vector.CrossProduct(v3, v4); + v3xv4 = Vector.UnitVector(v3xv4); + double magnitudev3xv4 = Vector.VectorMagnitude(v3xv4); + //the unit vector will not be a number NaN if the Cross product detects a zero vector (indicating parallel vectors) + if (double.IsNaN(magnitudev1xv2) && double.IsNaN(magnitudev3xv4)) + { + isRegularPolygon = true; + } + else + { + isRegularPolygon = false; + } + } + else + { + //might as well stop here because + isRegularPolygon = false; + return isRegularPolygon; + } + return isRegularPolygon; + + } + + //March15 2013 + //by CHarriman Senior Product Manager Carmel Software Corporation + //this is a function only used internally. It is used to verify if an opening object only has four coordinates, and if those coordinates form + //a square or rectangle. + private static bool IsOpeningRegular(OpeningDefinitions Opening) + { + //tests to see if all candidate surfaces and the standard surface are regular (rectangular polygons) + + bool isRegularPolygon = true; + //see if the standard surface has four coordinates defining its polyloop (one marker of a rectangle) + int standSurfaceCoordinateCount = Opening.PlCoords.Count; + if (standSurfaceCoordinateCount == 4) + { + //check the two potentially parallel sides, to ensure they are indeed parallel + Vector.CartVect v1 = Vector.CreateVector(Opening.PlCoords[0], Opening.PlCoords[1]); + Vector.CartVect v2 = Vector.CreateVector(Opening.PlCoords[2], Opening.PlCoords[3]); + Vector.CartVect v1xv2 = Vector.CrossProduct(v1, v2); + v1xv2 = Vector.UnitVector(v1xv2); + double magnitudev1xv2 = Vector.VectorMagnitude(v1xv2); + Vector.CartVect v3 = Vector.CreateVector(Opening.PlCoords[1], Opening.PlCoords[2]); + Vector.CartVect v4 = Vector.CreateVector(Opening.PlCoords[3], Opening.PlCoords[0]); + Vector.CartVect v3xv4 = Vector.CrossProduct(v3, v4); + v3xv4 = Vector.UnitVector(v3xv4); + double magnitudev3xv4 = Vector.VectorMagnitude(v3xv4); + //the unit vector will not be a number NaN if the Cross product detects a zero vector (indicating parallel vectors) + if (double.IsNaN(magnitudev1xv2) && double.IsNaN(magnitudev3xv4)) + { + isRegularPolygon = true; + } + else + { + isRegularPolygon = false; + } + } + else + { + //might as well stop here because + isRegularPolygon = false; + return isRegularPolygon; + } + return isRegularPolygon; + + } + //February 20 2013 + //Created by Chien Si Harriman Senior Product Manager for the Carmel Software Corporation + //Currently the tool assumes that the polyloop is a valid one (counterclockwise coordinates) Previous checks ensure this is the case? + //and the segments of the polygon are not self-intersecting (there are no previous tests for this as of the date above) + private static double GetAreaFrom2DPolyLoop(List coordList) + { + int count = coordList.Count; + double areaprod = 0; + bool XisZero = true; + bool YisZero = true; + bool ZisZero = true; + //the following calculates the area of any irregular polygon + foreach (Vector.CartCoord coord in coordList) + { + if (coord.X != 0) XisZero = false; + if (coord.Y != 0) YisZero = false; + if (coord.Z != 0) ZisZero = false; + } + if (!XisZero && !YisZero && !ZisZero) return -999; + + if (XisZero) + { + for (int i = 0; i < count; i++) + { + if (i < count - 1) + { + areaprod += (coordList[i].Y * coordList[i + 1].Z - coordList[i].Z * coordList[i + 1].Y); + } + else if (i == count - 1) + { + areaprod += (coordList[i].Y * coordList[0].Z - coordList[i].Z * coordList[0].Y); + } + } + areaprod = areaprod / 2; + } + else if (YisZero) + { + for (int i = 0; i < count; i++) + { + if (i < count - 1) + { + areaprod += (coordList[i].X * coordList[i + 1].Z - coordList[i].Z * coordList[i + 1].X); + } + else if (i == count - 1) + { + areaprod += (coordList[i].X * coordList[0].Z - coordList[i].Z * coordList[0].X); + } + } + areaprod = areaprod / 2; + } + else if (ZisZero) + { + for (int i = 0; i < count; i++) + { + if (i < count - 1) + { + areaprod += (coordList[i].X * coordList[i + 1].Y - coordList[i].Y * coordList[i + 1].X); + } + else if (i == count - 1) + { + areaprod += (coordList[i].X * coordList[0].Y - coordList[i].Y * coordList[0].X); + } + } + areaprod = areaprod / 2; + } + return areaprod; + } + + private static DOEgbXMLReportingObj CountFixedWindows(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units) + { + report.testSummary = "This test compares the total number of Opening elements with the openingType=\"FixedWindow\" in the test"; + report.testSummary += " and standard files. It does this by"; + report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files."; + report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. "; + report.testSummary += "The tolerance is zero for this test. In other words, the Opening of type FixedWindow counts are the same, or the test fails."; + //this summary is text that describes to a lay user what this test does, and how it works functionally. The user should have some familiarity with the basic knowledge of gbXML + //added Feb 13 2013 + + report.unit = Units; + //assuming that this will be plenty large for now + string[] resultsArray = new string[50]; + int nodecount = 0; + for (int i = 0; i < gbXMLDocs.Count; i++) + { + nodecount = 0; + try + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + + XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface/gbXMLv5:Opening", gbXMLns); + foreach (XmlNode surfaceNode in nodes) + { + XmlAttributeCollection spaceAtts = surfaceNode.Attributes; + foreach (XmlAttribute at in spaceAtts) + { + if (at.Name == "openingType") + { + string type = at.Value; + if (type == "FixedWindow") + { + nodecount++; + } + break; + } + } + } + + //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result + resultsArray[i] = nodecount.ToString(); + if (i % 2 != 0) + { + //setup standard result and test result + report.standResult.Add(resultsArray[i]); + report.testResult.Add(resultsArray[i - 1]); + report.idList.Add(""); + + double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)])); + if (difference <= report.tolerance) + { + report.longMsg = "The " + report.testType + " matches standard file, the difference was within tolerance = " + report.tolerance.ToString() + " " + Units; + report.passOrFail = true; + return report; + } + else + { + report.longMsg = "The " + report.testType + " does not match standard file, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference + + ". " + resultsArray[i] + " fixed windows in the standard file and " + resultsArray[i - 1] + " fixed windows in the test file."; + report.passOrFail = false; + return report; + } + } + else { continue; } + + } + catch (Exception e) + { + report.MessageList.Add(e.ToString()); + report.longMsg = " Failed to locate " + report.testType + " in the XML file."; + report.passOrFail = false; + return report; + } + } + report.longMsg = "Fatal " + report.testType + " Test Failure"; + report.passOrFail = false; + return report; + } + + private static DOEgbXMLReportingObj CountOperableWindows(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units) + { + report.testSummary = "This test compares the total number of Opening elements with the openingType=\"OperableWindow\" in the test"; + report.testSummary += " and standard files. It does this by"; + report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files."; + report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. "; + report.testSummary += "The tolerance is zero for this test. In other words, the Opening of type FixedWindow counts are the same, or the test fails."; + report.unit = Units; + //assuming that this will be plenty large for now + string[] resultsArray = new string[50]; + int nodecount = 0; + for (int i = 0; i < gbXMLDocs.Count; i++) + { + nodecount = 0; + try + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + + XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface/gbXMLv5:Opening", gbXMLns); + foreach (XmlNode surfaceNode in nodes) + { + XmlAttributeCollection spaceAtts = surfaceNode.Attributes; + foreach (XmlAttribute at in spaceAtts) + { + if (at.Name == "openingType") + { + string type = at.Value; + if (type == "OperableWindow") + { + nodecount++; + } + break; + } + } + } + + //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result + resultsArray[i] = nodecount.ToString(); + if (i % 2 != 0) + { + //setup standard result and test result + report.standResult.Add(resultsArray[i]); + report.testResult.Add(resultsArray[i - 1]); + report.idList.Add(""); + + double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)])); + if (difference <= report.tolerance) + { + report.longMsg = "The " + report.testType + " matches standard file, the difference was within tolerance = " + report.tolerance.ToString() + " " + Units; + report.passOrFail = true; + return report; + } + else + { + report.longMsg = "The " + report.testType + " does not match standard file, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference + + ". " + resultsArray[i] + " operable windows in the standard file and " + resultsArray[i - 1] + " operable windows in the test file."; + report.passOrFail = false; + return report; + } + } + else { continue; } + + } + catch (Exception e) + { + report.MessageList.Add(e.ToString()); + report.longMsg = " Failed to locate " + report.testType + " in the XML file."; + report.passOrFail = false; + return report; + } + } + report.longMsg = "Fatal " + report.testType + " Test Failure"; + report.passOrFail = false; + return report; + } + + private static DOEgbXMLReportingObj CountFixedSkylights(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units) + { + report.testSummary = "This test compares the total number of Opening elements with the openingType=\"FixedSkylight\" in the test"; + report.testSummary += " and standard files. It does this by"; + report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files."; + report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. "; + report.testSummary += "The tolerance is zero for this test. In other words, the Opening of type FixedSkylight counts are the same, or the test fails."; + report.unit = Units; + //assuming that this will be plenty large for now + string[] resultsArray = new string[50]; + int nodecount = 0; + for (int i = 0; i < gbXMLDocs.Count; i++) + { + nodecount = 0; + try + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + + XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface/gbXMLv5:Opening", gbXMLns); + foreach (XmlNode surfaceNode in nodes) + { + XmlAttributeCollection spaceAtts = surfaceNode.Attributes; + foreach (XmlAttribute at in spaceAtts) + { + if (at.Name == "openingType") + { + string type = at.Value; + if (type == "FixedSkylight") + { + nodecount++; + } + break; + } + } + } + + //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result + resultsArray[i] = nodecount.ToString(); + if (i % 2 != 0) + { + //setup standard result and test result + report.standResult.Add(resultsArray[i]); + report.testResult.Add(resultsArray[i - 1]); + report.idList.Add(""); + + double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)])); + if (difference <= report.tolerance) + { + report.longMsg = "The " + report.testType + " matches standard file, the difference was within tolerance = " + report.tolerance.ToString() + " " + Units; + report.passOrFail = true; + return report; + } + else + { + report.longMsg = "The " + report.testType + " does not match standard file, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference + + ". " + resultsArray[i] + " fixed skylights in the standard file and " + resultsArray[i - 1] + " fixed skylights in the test file."; + report.passOrFail = false; + return report; + } + } + else { continue; } + + } + catch (Exception e) + { + report.MessageList.Add(e.ToString()); + report.longMsg = " Failed to locate " + report.testType + " in the XML file."; + report.passOrFail = false; + return report; + } + } + report.longMsg = "Fatal " + report.testType + " Test Failure"; + report.passOrFail = false; + return report; + } + + private static DOEgbXMLReportingObj CountOperableSkylights(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units) + { + report.testSummary = "This test compares the total number of Opening elements with the openingType=\"OperableSkylights\" in the test"; + report.testSummary += " and standard files. It does this by"; + report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files."; + report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. "; + report.testSummary += "The tolerance is zero for this test. In other words, the Opening of type OperableSkylights counts are the same, or the test fails."; + report.unit = Units; + //assuming that this will be plenty large for now + string[] resultsArray = new string[50]; + int nodecount = 0; + for (int i = 0; i < gbXMLDocs.Count; i++) + { + nodecount = 0; + try + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + + XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface/gbXMLv5:Opening", gbXMLns); + foreach (XmlNode surfaceNode in nodes) + { + XmlAttributeCollection spaceAtts = surfaceNode.Attributes; + foreach (XmlAttribute at in spaceAtts) + { + if (at.Name == "openingType") + { + string type = at.Value; + if (type == "OperableSkylight") + { + nodecount++; + } + break; + } + } + } + + //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result + resultsArray[i] = nodecount.ToString(); + if (i % 2 != 0) + { + //setup standard result and test result + report.standResult.Add(resultsArray[i]); + report.testResult.Add(resultsArray[i - 1]); + report.idList.Add(""); + + double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)])); + if (difference <= report.tolerance) + { + report.longMsg = "The " + report.testType + " matches standard file, the difference was within tolerance = " + report.tolerance.ToString() + " " + Units; + report.passOrFail = true; + return report; + } + else + { + report.longMsg = "The " + report.testType + " does not match standard file, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference + + ". " + resultsArray[i] + " operable skylights in the standard file and " + resultsArray[i - 1] + " operable skylights in the test file."; + report.passOrFail = false; + return report; + } + } + else { continue; } + + } + catch (Exception e) + { + report.MessageList.Add(e.ToString()); + report.longMsg = " Failed to locate " + report.testType + " in the XML file."; + report.passOrFail = false; + return report; + } + } + report.longMsg = "Fatal " + report.testType + " Test Failure"; + report.passOrFail = false; + return report; + } + + private static DOEgbXMLReportingObj CountSlidingDoors(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units) + { + report.testSummary = "This test compares the total number of Opening elements with the openingType=\"SlidingDoor\" in the test"; + report.testSummary += " and standard files. It does this by"; + report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files."; + report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. "; + report.testSummary += "The tolerance is zero for this test. In other words, the Opening of type SlidingDoor counts are the same, or the test fails."; + report.unit = Units; + //assuming that this will be plenty large for now + string[] resultsArray = new string[50]; + int nodecount = 0; + for (int i = 0; i < gbXMLDocs.Count; i++) + { + nodecount = 0; + try + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + + XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface/gbXMLv5:Opening", gbXMLns); + foreach (XmlNode surfaceNode in nodes) + { + XmlAttributeCollection spaceAtts = surfaceNode.Attributes; + foreach (XmlAttribute at in spaceAtts) + { + if (at.Name == "openingType") + { + string type = at.Value; + if (type == "SlidingDoor") + { + nodecount++; + } + break; + } + } + } + + //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result + resultsArray[i] = nodecount.ToString(); + if (i % 2 != 0) + { + //setup standard result and test result + report.standResult.Add(resultsArray[i]); + report.testResult.Add(resultsArray[i - 1]); + report.idList.Add(""); + + double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)])); + if (difference <= report.tolerance) + { + report.longMsg = "The " + report.testType + " matches standard file, the difference was within tolerance = " + report.tolerance.ToString() + " " + Units; + report.passOrFail = true; + return report; + } + else + { + report.longMsg = "The " + report.testType + " does not match standard file, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference + + ". " + resultsArray[i] + " sliding doors in the standard file and " + resultsArray[i - 1] + " sliding doors in the test file."; + report.passOrFail = false; + return report; + } + } + else { continue; } + + } + catch (Exception e) + { + report.MessageList.Add(e.ToString()); + report.longMsg = " Failed to locate " + report.testType + " in the XML file."; + report.passOrFail = false; + return report; + } + } + report.longMsg = "Fatal " + report.testType + " Test Failure"; + report.passOrFail = false; + return report; + } + + private static DOEgbXMLReportingObj CountNonSlidingDoors(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units) + { + report.testSummary = "This test compares the total number of Opening elements with the openingType=\"NonSlidingDoor\" in the test"; + report.testSummary += " and standard files. It does this by"; + report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files."; + report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. "; + report.testSummary += "The tolerance is zero for this test. In other words, the Opening of type NonSlidingDoor counts are the same, or the test fails."; + report.unit = Units; + //assuming that this will be plenty large for now + string[] resultsArray = new string[50]; + int nodecount = 0; + for (int i = 0; i < gbXMLDocs.Count; i++) + { + nodecount = 0; + try + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + + XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface/gbXMLv5:Opening", gbXMLns); + foreach (XmlNode surfaceNode in nodes) + { + XmlAttributeCollection spaceAtts = surfaceNode.Attributes; + foreach (XmlAttribute at in spaceAtts) + { + if (at.Name == "openingType") + { + string type = at.Value; + if (type == "NonSlidingDoor") + { + nodecount++; + } + break; + } + } + } + + //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result + resultsArray[i] = nodecount.ToString(); + if (i % 2 != 0) + { + //setup standard result and test result + report.standResult.Add(resultsArray[i]); + report.testResult.Add(resultsArray[i - 1]); + report.idList.Add(""); + + double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)])); + if (difference <= report.tolerance) + { + report.longMsg = "The " + report.testType + " matches standard file, the difference was within tolerance = " + report.tolerance.ToString() + " " + Units; + report.passOrFail = true; + return report; + } + else + { + report.longMsg = "The " + report.testType + " does not match standard file, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference + + ". " + resultsArray[i] + " non-sliding doors in the standard file and " + resultsArray[i - 1] + " non-sliding doors in the test file."; + report.passOrFail = false; + return report; + } + } + else { continue; } + + } + catch (Exception e) + { + report.MessageList.Add(e.ToString()); + report.longMsg = " Failed to locate " + report.testType + " in the XML file."; + report.passOrFail = false; + return report; + } + } + report.longMsg = "Fatal " + report.testType + " Test Failure"; + report.passOrFail = false; + return report; + } + + private static DOEgbXMLReportingObj CountAirOpenings(List gbXMLDocs, List gbXMLnsm, DOEgbXMLReportingObj report, string Units) + { + report.testSummary = "This test compares the total number of Opening elements with the openingType=\"Air\" in the test"; + report.testSummary += " and standard files. It does this by"; + report.testSummary += " simply counting up the total number of times that a \"\" tag appears with this Surface Type in both files."; + report.testSummary += " If the quantities are the same, this test passes, if different, it will fail. "; + report.testSummary += "The tolerance is zero for this test. In other words, the Opening of type Air counts are the same, or the test fails."; + report.unit = Units; + //assuming that this will be plenty large for now + string[] resultsArray = new string[50]; + int nodecount = 0; + for (int i = 0; i < gbXMLDocs.Count; i++) + { + nodecount = 0; + try + { + XmlDocument gbXMLTestFile = gbXMLDocs[i]; + XmlNamespaceManager gbXMLns = gbXMLnsm[i]; + + XmlNodeList nodes = gbXMLTestFile.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Surface/gbXMLv5:Opening", gbXMLns); + foreach (XmlNode surfaceNode in nodes) + { + XmlAttributeCollection spaceAtts = surfaceNode.Attributes; + foreach (XmlAttribute at in spaceAtts) + { + if (at.Name == "openingType") + { + string type = at.Value; + if (type == "Air") + { + nodecount++; + } + break; + } + } + } + + //need to test for accuracy of result if accurate then pass, if not, how much inaccuracy and return this result + resultsArray[i] = nodecount.ToString(); + if (i % 2 != 0) + { + //setup standard result and test result + report.standResult.Add(resultsArray[i]); + report.testResult.Add(resultsArray[i - 1]); + report.idList.Add(""); + + double difference = Math.Abs(Convert.ToInt32(resultsArray[i]) - Convert.ToInt32(resultsArray[(i - 1)])); + if (difference <= report.tolerance) + { + report.longMsg = "The " + report.testType + " matches standard file, the difference was within tolerance = " + report.tolerance.ToString() + " " + Units; + report.passOrFail = true; + return report; + } + else + { + report.longMsg = "The " + report.testType + " does not match standard file, the difference was not within tolerance = " + report.tolerance.ToString() + " " + Units + ". Difference of: " + difference + + ". " + resultsArray[i] + " air openings in the standard file and " + resultsArray[i - 1] + " air openings in the test file."; + report.passOrFail = false; + return report; + } + } + else { continue; } + + } + catch (Exception e) + { + report.MessageList.Add(e.ToString()); + report.longMsg = " Failed to locate " + report.testType + " in the XML file."; + report.passOrFail = false; + return report; + } + } + report.longMsg = "Fatal " + report.testType + " Test Failure"; + report.passOrFail = false; + return report; + } + #endregion + } +} diff --git a/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLReportingObj.cs b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLReportingObj.cs new file mode 100644 index 0000000..e95125b --- /dev/null +++ b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLReportingObj.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace DOEgbXML +{ + public class DOEgbXMLReportingObj + { + //new ReportingObj strings created Feb 13 2013 + public string testSummary; + public string testReasoning; + // public Dictionary globalTestCriteria; + //original ReportingObj created Jan 1 2013 + public List standResult; + public List testResult; + public List idList; + public double tolerance; + public TestType testType; + public int subTestIndex = -1; + public string unit; + public Dictionary TestPassedDict; + public bool passOrFail; + public List MessageList; + public string longMsg; + // public Dictionary> MatchedSurfaceIds; + // public Dictionary> MatchedOpening; + + public void Clear() + { + + if (standResult != null) + standResult.Clear(); + + if (testResult != null) + testResult.Clear(); + + if (idList != null) + idList.Clear(); + tolerance = DOEgbXMLBasics.Tolerances.ToleranceDefault; + testType = TestType.None; + subTestIndex = -1; + passOrFail = false; + if (MessageList != null) { MessageList.Clear(); } + if (TestPassedDict != null) { TestPassedDict.Clear(); } + longMsg = ""; + } + + public DOEgbXMLReportingObj Copy() + { + DOEgbXMLReportingObj report = new DOEgbXMLReportingObj(); + + report.standResult = new List(this.standResult); + report.testResult = new List(this.testResult); + report.idList = new List(this.idList); + report.TestPassedDict = new Dictionary(this.TestPassedDict); + report.MessageList = new List(this.MessageList); + // if (this.MatchedSurfaceIds != null) + // report.MatchedSurfaceIds = new Dictionary>(this.MatchedSurfaceIds); + + + report.tolerance = this.tolerance; + report.testType = this.testType; + report.subTestIndex = this.subTestIndex; + report.unit = this.unit; + report.passOrFail = this.passOrFail; + report.longMsg = this.longMsg; + + report.testSummary = this.testSummary; + + return report; + } + + } +} \ No newline at end of file diff --git a/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLSurface.cs b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLSurface.cs new file mode 100644 index 0000000..f5c6862 --- /dev/null +++ b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLSurface.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using VectorMath; + +namespace DOEgbXML +{ + class SurfaceDefinitions + { + //creates instances of an object that store information about surfaces in a gbXML file + public string SurfaceType; + public string SurfaceId; + public List AdjSpaceId; + public double Azimuth; + public double Tilt; + public double Height; + public double Width; + public Vector.CartCoord InsertionPoint; + public List PlCoords; + public Vector.CartVect PlRHRVector; + } + class SurfaceResults + { + public int matchCount; + public Dictionary> SurfaceIdMatch; + } +} \ No newline at end of file diff --git a/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLTestCriteriaObject.cs b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLTestCriteriaObject.cs new file mode 100644 index 0000000..476c31b --- /dev/null +++ b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLTestCriteriaObject.cs @@ -0,0 +1,318 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace DOEgbXML +{ + public class DOEgbXMLTestCriteriaObject + { + public Dictionary TestCriteriaDictionary; + + + public void InitializeTestCriteriaWithTestName(string testname) + { + TestCriteriaDictionary = new Dictionary(); + + + if (testname == "Test1") + { + DOEgbXMLBasics.SliversAllowed = true; + TestCriteriaDictionary.Add(TestType.Building_Area, true); + TestCriteriaDictionary.Add(TestType.Space_Count, true); + TestCriteriaDictionary.Add( TestType.Building_Story_Count, true); + TestCriteriaDictionary.Add( TestType.Building_Story_Z_Height, true); + TestCriteriaDictionary.Add( TestType.Building_Story_PolyLoop_RHR, true); + TestCriteriaDictionary.Add(TestType.SpaceId_Match_Test , true); + TestCriteriaDictionary.Add(TestType.Space_Area, true); + TestCriteriaDictionary.Add(TestType.Space_Volume , true); + TestCriteriaDictionary.Add(TestType.Total_Surface_Count , false); + TestCriteriaDictionary.Add(TestType.Exterior_Wall_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Underground_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Interior_Wall_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Interior_Floor_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Roof_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Shading_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Air_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Surface_Planar_Test, true); + TestCriteriaDictionary.Add(TestType.Detailed_Surface_Checks, true); + TestCriteriaDictionary.Add(TestType.Fixed_Windows_Count, false); + TestCriteriaDictionary.Add(TestType.Operable_Windows_Count, false); + TestCriteriaDictionary.Add(TestType.Fixed_Skylight_Count, false); + TestCriteriaDictionary.Add(TestType.Operable_Skylight_Count,false); + TestCriteriaDictionary.Add(TestType.Sliding_Doors_Count,false); + TestCriteriaDictionary.Add(TestType.Non_Sliding_Doors_Count, false); + TestCriteriaDictionary.Add(TestType.Air_Openings_Count, false); + TestCriteriaDictionary.Add(TestType.Opening_Planar_Test, true); + TestCriteriaDictionary.Add(TestType.Detailed_Opening_Checks, true); + //As of Feb 13 2013, this test is for a future release. Placeholder only + TestCriteriaDictionary.Add(TestType.Shell_Geom_RHR, false); + } + else if (testname == "Test2") + { + DOEgbXMLBasics.SliversAllowed = true; + TestCriteriaDictionary.Add(TestType.Building_Area, true); + TestCriteriaDictionary.Add(TestType.Space_Count, true); + TestCriteriaDictionary.Add(TestType.Building_Story_Count, true); + TestCriteriaDictionary.Add(TestType.Building_Story_Z_Height, true); + TestCriteriaDictionary.Add(TestType.Building_Story_PolyLoop_RHR, true); + TestCriteriaDictionary.Add(TestType.SpaceId_Match_Test, true); + TestCriteriaDictionary.Add(TestType.Space_Area, true); + TestCriteriaDictionary.Add(TestType.Space_Volume, true); + TestCriteriaDictionary.Add(TestType.Total_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Exterior_Wall_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Underground_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Interior_Wall_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Interior_Floor_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Roof_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Shading_Surface_Count, true); //shades must match + TestCriteriaDictionary.Add(TestType.Air_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Surface_Planar_Test, true); + TestCriteriaDictionary.Add(TestType.Detailed_Surface_Checks, true); + TestCriteriaDictionary.Add(TestType.Fixed_Windows_Count, false); + TestCriteriaDictionary.Add(TestType.Operable_Windows_Count, false); + TestCriteriaDictionary.Add(TestType.Fixed_Skylight_Count, false); + TestCriteriaDictionary.Add(TestType.Operable_Skylight_Count, false); + TestCriteriaDictionary.Add(TestType.Sliding_Doors_Count, false); + TestCriteriaDictionary.Add(TestType.Non_Sliding_Doors_Count, false); + TestCriteriaDictionary.Add(TestType.Air_Openings_Count, false); + TestCriteriaDictionary.Add(TestType.Opening_Planar_Test, true); + TestCriteriaDictionary.Add(TestType.Detailed_Opening_Checks, true); + //As of Feb 13 2013, this test is for a future release. Placeholder only + TestCriteriaDictionary.Add(TestType.Shell_Geom_RHR, false); + } + else if (testname == "Test3") + { + DOEgbXMLBasics.SliversAllowed = true; + TestCriteriaDictionary.Add(TestType.Building_Area, true); + TestCriteriaDictionary.Add(TestType.Space_Count, true); + TestCriteriaDictionary.Add(TestType.Building_Story_Count, true); + TestCriteriaDictionary.Add(TestType.Building_Story_Z_Height, true); + TestCriteriaDictionary.Add(TestType.Building_Story_PolyLoop_RHR, true); + TestCriteriaDictionary.Add(TestType.SpaceId_Match_Test, true); + TestCriteriaDictionary.Add(TestType.Space_Area, true); + TestCriteriaDictionary.Add(TestType.Space_Volume, true); + TestCriteriaDictionary.Add(TestType.Total_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Exterior_Wall_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Underground_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Interior_Wall_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Interior_Floor_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Roof_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Shading_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Air_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Surface_Planar_Test, true); + TestCriteriaDictionary.Add(TestType.Detailed_Surface_Checks, true); + TestCriteriaDictionary.Add(TestType.Fixed_Windows_Count, false); + TestCriteriaDictionary.Add(TestType.Operable_Windows_Count, false); + TestCriteriaDictionary.Add(TestType.Fixed_Skylight_Count, false); + TestCriteriaDictionary.Add(TestType.Operable_Skylight_Count, false); + TestCriteriaDictionary.Add(TestType.Sliding_Doors_Count, false); + TestCriteriaDictionary.Add(TestType.Non_Sliding_Doors_Count, false); + TestCriteriaDictionary.Add(TestType.Air_Openings_Count, false); + TestCriteriaDictionary.Add(TestType.Opening_Planar_Test, true); + TestCriteriaDictionary.Add(TestType.Detailed_Opening_Checks, true); + //As of Feb 13 2013, this test is for a future release. Placeholder only + TestCriteriaDictionary.Add(TestType.Shell_Geom_RHR, false); + } + else if (testname == "Test4") + { + DOEgbXMLBasics.SliversAllowed = true; + TestCriteriaDictionary.Add(TestType.Building_Area, true); + TestCriteriaDictionary.Add(TestType.Space_Count, true); + TestCriteriaDictionary.Add(TestType.Building_Story_Count, true); + TestCriteriaDictionary.Add(TestType.Building_Story_Z_Height, true); + TestCriteriaDictionary.Add(TestType.Building_Story_PolyLoop_RHR, true); + TestCriteriaDictionary.Add(TestType.SpaceId_Match_Test, true); + TestCriteriaDictionary.Add(TestType.Space_Area, true); + TestCriteriaDictionary.Add(TestType.Space_Volume, true); + TestCriteriaDictionary.Add(TestType.Total_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Exterior_Wall_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Underground_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Interior_Wall_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Interior_Floor_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Roof_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Shading_Surface_Count, true); //shades must match + TestCriteriaDictionary.Add(TestType.Air_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Surface_Planar_Test, true); + TestCriteriaDictionary.Add(TestType.Detailed_Surface_Checks, true); + TestCriteriaDictionary.Add(TestType.Fixed_Windows_Count, false); + TestCriteriaDictionary.Add(TestType.Operable_Windows_Count, false); + TestCriteriaDictionary.Add(TestType.Fixed_Skylight_Count, false); + TestCriteriaDictionary.Add(TestType.Operable_Skylight_Count, false); + TestCriteriaDictionary.Add(TestType.Sliding_Doors_Count, false); + TestCriteriaDictionary.Add(TestType.Non_Sliding_Doors_Count, false); + TestCriteriaDictionary.Add(TestType.Air_Openings_Count, false); + TestCriteriaDictionary.Add(TestType.Opening_Planar_Test, true); + TestCriteriaDictionary.Add(TestType.Detailed_Opening_Checks, true); + //As of Feb 13 2013, this test is for a future release. Placeholder only + TestCriteriaDictionary.Add(TestType.Shell_Geom_RHR, false); + } + else if (testname == "Test5") + { + DOEgbXMLBasics.SliversAllowed = true; + TestCriteriaDictionary.Add(TestType.Building_Area, true); + TestCriteriaDictionary.Add(TestType.Space_Count, true); + TestCriteriaDictionary.Add(TestType.Building_Story_Count, true); + TestCriteriaDictionary.Add(TestType.Building_Story_Z_Height, true); + TestCriteriaDictionary.Add(TestType.Building_Story_PolyLoop_RHR, true); + TestCriteriaDictionary.Add(TestType.SpaceId_Match_Test, true); + TestCriteriaDictionary.Add(TestType.Space_Area, true); + TestCriteriaDictionary.Add(TestType.Space_Volume, true); + TestCriteriaDictionary.Add(TestType.Total_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Exterior_Wall_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Underground_Surface_Count, true); + TestCriteriaDictionary.Add(TestType.Interior_Wall_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Interior_Floor_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Roof_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Shading_Surface_Count, true); //shading surface must match + TestCriteriaDictionary.Add(TestType.Air_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Surface_Planar_Test, true); + TestCriteriaDictionary.Add(TestType.Detailed_Surface_Checks, true); + TestCriteriaDictionary.Add(TestType.Fixed_Windows_Count, false); + TestCriteriaDictionary.Add(TestType.Operable_Windows_Count, false); + TestCriteriaDictionary.Add(TestType.Fixed_Skylight_Count, false); + TestCriteriaDictionary.Add(TestType.Operable_Skylight_Count, false); + TestCriteriaDictionary.Add(TestType.Sliding_Doors_Count, false); + TestCriteriaDictionary.Add(TestType.Non_Sliding_Doors_Count, false); + TestCriteriaDictionary.Add(TestType.Air_Openings_Count, false); + TestCriteriaDictionary.Add(TestType.Opening_Planar_Test, true); + TestCriteriaDictionary.Add(TestType.Detailed_Opening_Checks, true); + //As of Feb 13 2013, this test is for a future release. Placeholder only + TestCriteriaDictionary.Add(TestType.Shell_Geom_RHR, false); + } + else if (testname == "Test7") + { + DOEgbXMLBasics.SliversAllowed = true; + TestCriteriaDictionary.Add(TestType.Building_Area, true); + TestCriteriaDictionary.Add(TestType.Space_Count, true); + TestCriteriaDictionary.Add(TestType.Building_Story_Count, true); + TestCriteriaDictionary.Add(TestType.Building_Story_Z_Height, true); + TestCriteriaDictionary.Add(TestType.Building_Story_PolyLoop_RHR, true); + TestCriteriaDictionary.Add(TestType.SpaceId_Match_Test, true); + TestCriteriaDictionary.Add(TestType.Space_Area, true); + TestCriteriaDictionary.Add(TestType.Space_Volume, true); + TestCriteriaDictionary.Add(TestType.Total_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Exterior_Wall_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Underground_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Interior_Wall_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Interior_Floor_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Roof_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Shading_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Air_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Surface_Planar_Test, true); + TestCriteriaDictionary.Add(TestType.Detailed_Surface_Checks, true); + TestCriteriaDictionary.Add(TestType.Fixed_Windows_Count, false); + TestCriteriaDictionary.Add(TestType.Operable_Windows_Count, false); + TestCriteriaDictionary.Add(TestType.Fixed_Skylight_Count, false); + TestCriteriaDictionary.Add(TestType.Operable_Skylight_Count, false); + TestCriteriaDictionary.Add(TestType.Sliding_Doors_Count, false); + TestCriteriaDictionary.Add(TestType.Non_Sliding_Doors_Count, false); + TestCriteriaDictionary.Add(TestType.Air_Openings_Count, false); + TestCriteriaDictionary.Add(TestType.Opening_Planar_Test, true); + TestCriteriaDictionary.Add(TestType.Detailed_Opening_Checks, true); + //As of Feb 13 2013, this test is for a future release. Placeholder only + TestCriteriaDictionary.Add(TestType.Shell_Geom_RHR, false); + } + else if (testname == "Test8") + { + DOEgbXMLBasics.SliversAllowed = true; + TestCriteriaDictionary.Add(TestType.Building_Area, true); + TestCriteriaDictionary.Add(TestType.Space_Count, true); + TestCriteriaDictionary.Add(TestType.Building_Story_Count, true); + TestCriteriaDictionary.Add(TestType.Building_Story_Z_Height, true); + TestCriteriaDictionary.Add(TestType.Building_Story_PolyLoop_RHR, true); + TestCriteriaDictionary.Add(TestType.SpaceId_Match_Test, true); + TestCriteriaDictionary.Add(TestType.Space_Area, true); + TestCriteriaDictionary.Add(TestType.Space_Volume, true); + TestCriteriaDictionary.Add(TestType.Total_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Exterior_Wall_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Underground_Surface_Count, true); + TestCriteriaDictionary.Add(TestType.Interior_Wall_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Interior_Floor_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Roof_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Shading_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Air_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Surface_Planar_Test, true); + TestCriteriaDictionary.Add(TestType.Detailed_Surface_Checks, true); + TestCriteriaDictionary.Add(TestType.Fixed_Windows_Count, false); + TestCriteriaDictionary.Add(TestType.Operable_Windows_Count, false); + TestCriteriaDictionary.Add(TestType.Fixed_Skylight_Count, false); + TestCriteriaDictionary.Add(TestType.Operable_Skylight_Count, false); + TestCriteriaDictionary.Add(TestType.Sliding_Doors_Count, false); + TestCriteriaDictionary.Add(TestType.Non_Sliding_Doors_Count, false); + TestCriteriaDictionary.Add(TestType.Air_Openings_Count, false); + TestCriteriaDictionary.Add(TestType.Opening_Planar_Test, true); + TestCriteriaDictionary.Add(TestType.Detailed_Opening_Checks, true); + //As of Feb 13 2013, this test is for a future release. Placeholder only + TestCriteriaDictionary.Add(TestType.Shell_Geom_RHR, false); + } + else if (testname == "Test25") + { + DOEgbXMLBasics.SliversAllowed = true; + TestCriteriaDictionary.Add(TestType.Building_Area, true); + TestCriteriaDictionary.Add(TestType.Space_Count, true); + TestCriteriaDictionary.Add(TestType.Building_Story_Count, true); + TestCriteriaDictionary.Add(TestType.Building_Story_Z_Height, true); + TestCriteriaDictionary.Add(TestType.Building_Story_PolyLoop_RHR, true); + TestCriteriaDictionary.Add(TestType.SpaceId_Match_Test, true); + TestCriteriaDictionary.Add(TestType.Space_Area, true); + TestCriteriaDictionary.Add(TestType.Space_Volume, true); + TestCriteriaDictionary.Add(TestType.Total_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Exterior_Wall_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Underground_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Interior_Wall_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Interior_Floor_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Roof_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Shading_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Air_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Surface_Planar_Test, true); + TestCriteriaDictionary.Add(TestType.Detailed_Surface_Checks, true); + TestCriteriaDictionary.Add(TestType.Fixed_Windows_Count, false); + TestCriteriaDictionary.Add(TestType.Operable_Windows_Count, false); + TestCriteriaDictionary.Add(TestType.Fixed_Skylight_Count, false); + TestCriteriaDictionary.Add(TestType.Operable_Skylight_Count,false); + TestCriteriaDictionary.Add(TestType.Sliding_Doors_Count,false); + TestCriteriaDictionary.Add(TestType.Non_Sliding_Doors_Count, false); + TestCriteriaDictionary.Add(TestType.Air_Openings_Count, false); + TestCriteriaDictionary.Add(TestType.Opening_Planar_Test, true); + TestCriteriaDictionary.Add(TestType.Detailed_Opening_Checks, true); + //As of Feb 13 2013, this test is for a future release. Placeholder only + TestCriteriaDictionary.Add(TestType.Shell_Geom_RHR, false); + } + else if (testname == "Test28") + { + DOEgbXMLBasics.SliversAllowed = true; + TestCriteriaDictionary.Add(TestType.Building_Area, true); + TestCriteriaDictionary.Add(TestType.Space_Count, true); + TestCriteriaDictionary.Add(TestType.Building_Story_Count, true); + TestCriteriaDictionary.Add(TestType.Building_Story_Z_Height, true); + TestCriteriaDictionary.Add(TestType.Building_Story_PolyLoop_RHR, true); + TestCriteriaDictionary.Add(TestType.SpaceId_Match_Test, true); + TestCriteriaDictionary.Add(TestType.Space_Area, true); + TestCriteriaDictionary.Add(TestType.Space_Volume, true); + TestCriteriaDictionary.Add(TestType.Total_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Exterior_Wall_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Underground_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Interior_Wall_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Interior_Floor_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Roof_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Shading_Surface_Count, true); //shading count must match + TestCriteriaDictionary.Add(TestType.Air_Surface_Count, false); + TestCriteriaDictionary.Add(TestType.Surface_Planar_Test, true); + TestCriteriaDictionary.Add(TestType.Detailed_Surface_Checks, true); + TestCriteriaDictionary.Add(TestType.Fixed_Windows_Count, false); + TestCriteriaDictionary.Add(TestType.Operable_Windows_Count, false); + TestCriteriaDictionary.Add(TestType.Fixed_Skylight_Count, false); + TestCriteriaDictionary.Add(TestType.Operable_Skylight_Count, false); + TestCriteriaDictionary.Add(TestType.Sliding_Doors_Count, false); + TestCriteriaDictionary.Add(TestType.Non_Sliding_Doors_Count, false); + TestCriteriaDictionary.Add(TestType.Air_Openings_Count, false); + TestCriteriaDictionary.Add(TestType.Opening_Planar_Test, true); + TestCriteriaDictionary.Add(TestType.Detailed_Opening_Checks, true); + //As of Feb 13 2013, this test is for a future release. Placeholder only + TestCriteriaDictionary.Add(TestType.Shell_Geom_RHR, false); + } + + } + } +} \ No newline at end of file diff --git a/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLTestDetail.cs b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLTestDetail.cs new file mode 100644 index 0000000..923c51c --- /dev/null +++ b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLTestDetail.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace DOEgbXML +{ + public class DOEgbXMLTestDetail + { + public string testName; + public string testSummary; + public string passString; + public string failString; + public string shortTitle; + //holds a bunch of strings for a given test + //this list will have this format: TestShortTitle, Pass String, Fail String, Summary String + // public List testString = new List(); + + //this List will store all the test Detail + public List TestDetailList; + + public void InitializeTestResultStrings() + { + //holds the Detail object for all the tests + TestDetailList = new List(); + + //get the strings for the summary page table + //initialize the testdetails for all the tests + DOEgbXMLTestDetail test1detail = new DOEgbXMLTestDetail(); + DOEgbXMLTestDetail test2detail = new DOEgbXMLTestDetail(); + DOEgbXMLTestDetail test3detail = new DOEgbXMLTestDetail(); + DOEgbXMLTestDetail test4detail = new DOEgbXMLTestDetail(); + DOEgbXMLTestDetail test5detail = new DOEgbXMLTestDetail(); + DOEgbXMLTestDetail test7detail = new DOEgbXMLTestDetail(); + DOEgbXMLTestDetail test8detail = new DOEgbXMLTestDetail(); + DOEgbXMLTestDetail test25detail = new DOEgbXMLTestDetail(); + DOEgbXMLTestDetail test28detail = new DOEgbXMLTestDetail(); + //create the strings + //Test1 + test1detail.testName = "Test1"; + test1detail.shortTitle = "2 Walls of Different Thicknesses with Parallel Aligned Faces"; + test1detail.testSummary = "This test is designed to make sure that when walls of different thicknesses are joined with their faces aligned, that the centerline offset does not create extra walls during the gbXML creation process. If these extra sliver walls are found in the gbXML file, this test will fail."; + test1detail.passString = "This test has passed."; + test1detail.failString = "This test has failed."; + //ADD list to local testStrings List of Lists + TestDetailList.Add(test1detail); + + //test 2 + test2detail.testName = "Test2"; + test2detail.shortTitle = "Single window with overhang that bisects the window's height."; + test2detail.testSummary = "A 1-zone, one story, simple model with exterior shading devices that act as overhangs and exterior light shelves for windows on the south façade. Light shelves are 1” thick and split a single window instance in the BIM along its centerline. This test is designed to ensure that this window should be represented as two windows in gbXML, the one window that is above the overhang, and the other that is below."; + test2detail.passString = "This test has passed."; + test2detail.failString = "This test has failed."; + //ADD list to local testStrings List of Lists + TestDetailList.Add(test2detail); + + //test 3 + test3detail.testName = "Test3"; + test3detail.shortTitle = "Interior walls and Floor Second Level Space Boundary Test "; + test3detail.testSummary = "A 5-zone model with overlapping zones and a double-height zone. This test is designed to ensure that the tool used to create the zones can properly follow the basic conventions for second level space boundaries."; + test3detail.passString = "This test has passed."; + test3detail.failString = "This test has failed."; + //ADD list to local testStrings List of Lists + TestDetailList.Add(test3detail); + + //test 4 + test4detail.testName = "Test4"; + test4detail.shortTitle = "Double height space with hole cut in floor and a skylight"; + test4detail.testSummary = "This test is a large open atrium with a hole cut in the floor to allow light to penetrate through to the floor below."; + test4detail.passString = "This test has passed."; + test4detail.failString = "This test has failed."; + //ADD list to local testStrings List of Lists + TestDetailList.Add(test4detail); + + //test 5 + test5detail.testName = "Test5"; + test5detail.shortTitle = "Basement walls that extend above grade and bound two different spaces"; + test5detail.testSummary = "A two zone model that ensures exterior walls can properly be defined as underground and above grade. A single wall has been drawn by the user that begins below grade, and terminates above grade. Above grade, the walls bound a space that is above grade. Below grade, the walls bound a space that is entirely below grade."; + test5detail.passString = "This test has passed."; + test5detail.failString = "This test has failed."; + //ADD list to local testStrings List of Lists + TestDetailList.Add(test5detail); + + //test 7 + test7detail.testName = "Test7"; + test7detail.shortTitle = "Folded roof element."; + test7detail.testSummary = "This is the first in a proposed series of tests that focus on roof elements that grow in geometric complexity."; + test7detail.passString = "This test has passed."; + test7detail.failString = "This test has failed."; + //ADD list to local testStrings List of Lists + TestDetailList.Add(test7detail); + + //test 8 + test8detail.testName = "Test8"; + test8detail.shortTitle = "Sloping slab on grade"; + test8detail.testSummary = "Ensures that sloping slab on grade comes through properly in gbXML, and that walls, which terminate at grade, are turned into the appropriate surfaceType (\"UndergroundWall\")"; + test8detail.passString = "This test has passed."; + test8detail.failString = "This test has failed."; + //ADD list to local testStrings List of Lists + TestDetailList.Add(test8detail); + + //test 25 + test25detail.testName = "Test25"; + test25detail.shortTitle = "Stacked interior walls with openings"; + test25detail.testSummary = "A simplified 4-zone model of a building that has interior walls stacked on top of one another. The interior walls each have openings cut into them, to simulate something that may be drawn as a hallway by a designer."; + test25detail.passString = "This test has passed."; + test25detail.failString = "This test has failed."; + //ADD list to local testStrings List of Lists + TestDetailList.Add(test25detail); + + //test 28 + test28detail.testName = "Test28"; + test28detail.shortTitle = "Roof eaves are turned into shading devices automatically"; + test28detail.testSummary = "A simplified 3-zone model of a building shaped like a residential home has been created. The home is a simple two story example that has a small attic formed by a roof with a 30 degree pitch which slopes along one of the site’s Cartesian axes. This test is a simple test that ensures the authoring tool is able to automatically break the roof into a space bounding object and shade object appropriately without any user intervention."; + test28detail.passString = "This test has passed."; + test28detail.failString = "This test has failed."; + //ADD list to local testStrings List of Lists + TestDetailList.Add(test28detail); + + + } + } + +} \ No newline at end of file diff --git a/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLValidator.cs b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLValidator.cs new file mode 100644 index 0000000..9dbce76 --- /dev/null +++ b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLValidator.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Xml; +using System.IO; +using System.Xml.Schema; + +namespace DOEgbXML +{ + public class DOEgbXMLValidator + { + + public int nErrors = 0; + public int nWarnings = 0; + private string strErrorMsg = string.Empty; + public string Errors { get { return strErrorMsg; } } + public string BigError; + + public bool IsValidXmlEx(XmlReader xmlStream) + { + bool bStatus = false; + try + { + // Declare local objects + string xsdSchemaLocalLocation = Path.Combine(HttpRuntime.AppDomainAppPath, "SupportFiles/XSD/GreenBuildingXML_Ver5.10.xsd"); + XmlReaderSettings rs = new XmlReaderSettings(); + rs.ValidationType = ValidationType.Schema; + rs.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation | XmlSchemaValidationFlags.ReportValidationWarnings; + rs.ValidationEventHandler += new ValidationEventHandler(rs_ValidationEventHandler); + + //add schema + rs.Schemas.Add(null, xsdSchemaLocalLocation); + + + using (XmlReader xmlValidatingReader = XmlReader.Create(xmlStream, rs)) + { + while (xmlValidatingReader.Read()) + { + } + } + + ////Exception if error.s + if (nErrors > 0) + { + throw new Exception(strErrorMsg); + } + else { bStatus = true; }//Success + } + catch (Exception error) + { + BigError = "BIG ERROR: " + error + "
"; + bStatus = false; + } + + return bStatus; + } + + void rs_ValidationEventHandler(object sender, ValidationEventArgs e) + { + + if (e.Severity == XmlSeverityType.Warning) + { + strErrorMsg += "

" + "WARNING: " + e.Exception.Message + " Line Position " + e.Exception.LinePosition + " Line Number: " + e.Exception.LineNumber + "

"; + nWarnings++; + } + else if(!e.Exception.Message.Contains("The element cannot contain white space. Content model is empty.")) + { + + strErrorMsg += "

" + "ERROR: " + e.Exception.Message + " Line Position " + e.Exception.LinePosition + " Line Number: " + e.Exception.LineNumber + "

"; + nErrors++; + } + } + + } +} \ No newline at end of file diff --git a/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLenum.cs b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLenum.cs new file mode 100644 index 0000000..a790f92 --- /dev/null +++ b/XMLValidatorWeb/DOEgbXMLClass/DOEgbXMLenum.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace DOEgbXML +{ + public enum TestType + { + None, + Building_Area, + Space_Count, + Building_Story_Count, + Building_Story_Z_Height, + Building_Story_PolyLoop_RHR, + SpaceId_Match_Test, + Space_Area, + Space_Volume, + Total_Surface_Count, + Exterior_Wall_Surface_Count, + Underground_Surface_Count, + Interior_Wall_Surface_Count, + Interior_Floor_Surface_Count, + Roof_Surface_Count, + Shading_Surface_Count, + Air_Surface_Count, + Surface_Planar_Test, + Detailed_Surface_Checks, + Fixed_Windows_Count, + Operable_Windows_Count, + Fixed_Skylight_Count, + Operable_Skylight_Count, + Sliding_Doors_Count, + Non_Sliding_Doors_Count, + Air_Openings_Count, + Opening_Planar_Test, + Detailed_Opening_Checks, + Shell_Geom_RHR + } + public class DOEgbXMLenum + { + } +} \ No newline at end of file diff --git a/XMLValidatorWeb/DOEgbXMLClass/Vector.cs b/XMLValidatorWeb/DOEgbXMLClass/Vector.cs new file mode 100644 index 0000000..4392ab3 --- /dev/null +++ b/XMLValidatorWeb/DOEgbXMLClass/Vector.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace VectorMath +{ + public class Vector + { + public class CartCoord + { + public double X { get; set; } + public double Y { get; set; } + public double Z { get; set; } + } + + public class CartVect + { + public double X { get; set; } + public double Y { get; set; } + public double Z { get; set; } + } + + public static CartVect CreateVector(CartCoord cd1, CartCoord cd2) + { + CartVect vector = new CartVect(); + vector.X = cd2.X - cd1.X; + vector.Y = cd2.Y - cd1.Y; + vector.Z = cd2.Z - cd1.Z; + return vector; + } + + public static Double VectorMagnitude(CartVect vector) + { + double magnitude= 0.0; + + magnitude = Math.Sqrt(Math.Pow((vector.X),2) + Math.Pow((vector.Y),2) + Math.Pow((vector.Z),2)); + return magnitude; + } + + public static CartVect UnitVector(CartVect vector) + { + CartVect UV = new CartVect(); + double magnitude = VectorMagnitude(vector); + + UV.X = vector.X / magnitude; + UV.Y = vector.Y / magnitude; + UV.Z = vector.Z / magnitude; + return UV; + } + + public static CartVect CrossProduct(CartVect vector1, CartVect vector2) + { + CartVect xProd = new CartVect(); + + xProd.X = vector2.Z * vector1.Y - vector1.Z * vector2.Y; + xProd.Y = vector2.Z * vector1.X - vector1.Z * vector2.X; + xProd.Z = vector2.Y * vector1.X - vector1.Y * vector2.X; + return xProd; + } + + public double getPlanarSA(List polygonVect) + { + List normalizedPlane = new List(); + //the new plane's first coordinate is arbitrarily set to zero + normalizedPlane[0].X = 0; + normalizedPlane[0].Y = 0; + normalizedPlane[0].Z = 0; + double diffX = 0; + double diffY = 0; + double diffZ = 0; + + double surfaceArea = -1; + int numPoints = polygonVect.Count; + for(int i=0; i 0) + { + + } + } + return surfaceArea; + } + } +} diff --git a/XMLValidatorWeb/DOEgbXMLClass/gbXML2IDF.cs b/XMLValidatorWeb/DOEgbXMLClass/gbXML2IDF.cs new file mode 100644 index 0000000..958b9b5 --- /dev/null +++ b/XMLValidatorWeb/DOEgbXMLClass/gbXML2IDF.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Xml; +using System.IO; + +namespace XMLValidatorWeb.DOEgbXMLClass +{ + public class gbXML2IDF + { + public void gbXMLToIDF(string filelocation) + { + XmlDocument gbxf = new XmlDocument(); + + //getXMLFile + gbxf.Load(filelocation); + XmlNamespaceManager gbxmlns = new XmlNamespaceManager(gbxf.NameTable); + gbxmlns.AddNamespace("gbXMLv5", "http://www.gbxml.org/schema"); + + //make zone file + string zonestring = makeZones(gbxf, gbxmlns); + + } + + public string makeZones(XmlDocument gbxf,XmlNamespaceManager gbxmlns) + { + string zones = ""; + XmlNodeList nodes = gbxf.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Space", gbxmlns); + int nodecount = nodes.Count; + foreach (XmlNode node in nodes) + { + + } + + return zones; + } + } +} \ No newline at end of file diff --git a/XMLValidatorWeb/DOEgbXMLClass/gbXMLMatches.cs b/XMLValidatorWeb/DOEgbXMLClass/gbXMLMatches.cs new file mode 100644 index 0000000..93f4da8 --- /dev/null +++ b/XMLValidatorWeb/DOEgbXMLClass/gbXMLMatches.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace DOEgbXML +{ + public class gbXMLMatches + { + public Dictionary> MatchedSurfaceIds; + public Dictionary> MatchedOpeningIds; + + public void Init() + { + MatchedSurfaceIds = new Dictionary>(); + MatchedOpeningIds = new Dictionary>(); + } + } +} \ No newline at end of file diff --git a/XMLValidatorWeb/Default.aspx b/XMLValidatorWeb/Default.aspx new file mode 100644 index 0000000..4d0cf43 --- /dev/null +++ b/XMLValidatorWeb/Default.aspx @@ -0,0 +1,10 @@ +<%@ Page Language="C#" MasterPageFile="~/MasterPage.Master" AutoEventWireup="true" + CodeBehind="Default.aspx.cs" Inherits="XMLXSDValidator._Default" %> + + +
+

+ Test Page +

+
+
diff --git a/XMLValidatorWeb/Default.aspx.cs b/XMLValidatorWeb/Default.aspx.cs new file mode 100644 index 0000000..10b620f --- /dev/null +++ b/XMLValidatorWeb/Default.aspx.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; +using System.Xml; +using System.Xml.Schema; +using System.IO; + +namespace XMLXSDValidator +{ + public partial class _Default : System.Web.UI.Page + { + + + + protected void LoginView1_ViewChanged1(object sender, EventArgs e) + { + + } + } +} \ No newline at end of file diff --git a/XMLValidatorWeb/Default.aspx.designer.cs b/XMLValidatorWeb/Default.aspx.designer.cs new file mode 100644 index 0000000..ac28f88 --- /dev/null +++ b/XMLValidatorWeb/Default.aspx.designer.cs @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace XMLXSDValidator { + + + public partial class _Default { + + /// + /// HyperLink1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.HyperLink HyperLink1; + } +} diff --git a/XMLValidatorWeb/GreenBuildingXML_Ver5.10.xsd b/XMLValidatorWeb/GreenBuildingXML_Ver5.10.xsd new file mode 100644 index 0000000..737de2c --- /dev/null +++ b/XMLValidatorWeb/GreenBuildingXML_Ver5.10.xsd @@ -0,0 +1,6478 @@ + + + + + gbXML version 5.10 - maintained by gbXML.org. + + + Change Log: + +5.10 + 10/2012 + +1. Added new element: ProjectEntity under ProgramInfo and it contains three new elements Filename, URI, and GUID. +2. Added new element: Filename for storing filenames of project files that created or modified the gbXML file. +3. Added new element: URI for storing location of filename or project that created or modified the gbXML file. +4. Added new element: GUID for storing unique ids for models, projects, simulations, and files that created or modified the gbXML file. GUID also has entity attribute that uses entityType enumeration. +5. Added new enumeration: entityType which has four values, Model, File, Project, Run. +6. Added programId attribute to the following elements; LightPowerPerArea, EquipPowerPerArea, InfiltrationFlow, PeopleNumber, PeopleHeatGain, Temperature, PeakDomesticHotWaterFlow, Weather, Schedule, IntEquip, ExtEquip, OAFlowPerPerson, OAFlowPerArea, DesignHeatT, DesignCoolT, Construction, HydronicLoop, HydronicLoopEquipment, AirLoop, AirLoopEquipment, LightingSystem, LightingControl, Lighting, WindowType, Vegetation, Weather, Meter, Transportation, Zone, ShadeControl, AltEnergySource, FlowPerArea, FlowPerPerson, and Flow. +7. Added Lux and Phot to illuminanceUnitEnum. +8. Added Damper, Boiler, Chiller to controlTypeEnum. +9. Added unit attribute using temperatureUnitEnum to DesignTemp, MinTemp, and MaxTemp. +10. Added unit attribute using flowUnitEnum to DesignFlow, MaximumFlow, and MinimumFlow. +11. Added LPM to flowUnitEnum. +12. Added primaryLoopId attribute to HydronicLoop. +13. Added Location element to Weather element. +14. Remove City, Country, StateorProvince elements from Weather element as Location element superceeds it. +15. Added Modeled to stationTypeEnumeration. +16. Added DataCenter to buildingTypeEnum. +17. Added ServerRoom to spaceTypeEnum. +18. Remove CADModelId from CreatedBy element as ProgramInfo and ProjectEntites superceeds it. +19. Changed minOccurs value to 4 for Surface sub-element of Campus main element +20. Changed minOccurs value to 0 for Surface main element + +5.01 + 4/2012 + +1. Deleted "surfaceNormalConvention" element. No longer used. +2. Deleted "surfaceNormalEnum" enumeration. No longer used. + +5.00 + 10/2011 + +1. Added new element: YearModeled. It consists of BeginDate, EndDate, and HolidaysModeled child elements. +2. Added new element: HolidaysModeled. It consists of Name, Description, and HolidayDate child elements. +3. Added new element: HolidayDate (type: date) +4. Added YearModeled child element to Campus element +5. Added 5 new enumeration items to the extEquipTypeEnum enumeration (Types of exterior equipment): +a. WindTurbine +b. Photovoltaic +c. CogenDiesel +d. CogenFuelCell +e. CogenGasTurbine +6. Added new element: HeatRejectedtoSpace with unitlessUnitEnum attribute +7. Added new element: Weight with attribute weightUnitEnum +8. Added Weight, HeatRejectedtoSpace child elements to IntEquip element +9. Added Weight child element to ExtEquip, airLoopEquip, HydronicEquip elements +10 Added new element: HeatRejectedtoSpace (type: decimal). Also added annotation explaining this element +11. Added HeatRejectedtoSpace child element to intEquip +12. Added Exhaust item to enumeration systemTypeEnum +13. Added new enumeration: resetTemperatureTypeEnum with 3 items: None, Automatic, OutdoorAirBased +14. Added new element: ResetTemperature with attributes: temperatureUnitEnum, resetTemperatureTypeEnum +15. Added ResetTemperature child element to AirLoopEquipment element +16. Updated the annotation of the AirLoopEquipment element to explain how they should be ordered in an AirLoop +17. Added new element: MotorInAirstream (type: boolean) +18. Added MotorInAirstream child element to AirLoopEquipment element +19. Added new element: Enthalpy with attribute enthalpyUnitEnum +20. Added new enumeration: enthalpyUnitEnum with 2 items: BTUPerLb and KJPerKg +21. Added Enthalpy child element to AirLoopEquipment element +22. Added 2 enumeration items to equipmentTypeEnum: EvaporativePreCooler, PreHeatCoil +23. Added 2 enumeration items to efficiencyTypeEnum: BTUPerHourPerF, kWPerC. Also, added annotation saying that this applies to StandByLoss for water heaters +24. Updated SolarHeatGainCoeff child element of Opening element so that it is unbounded (i.e. - many SHGC values for an Opening) +25. Updated AdjacentSpaceId annotation to better explain its use +26. Updated PolyLoop annotation to better explain its use +27. Added ProductName, Version, Platform elements (All of type: string) +28. Added AirChangesPerHour child element to Space element +29. Updated ShellGeometry annotation with clarification +30. Updated SpaceBoundary annotation with clarification +31. Added oppositeIdRef attribute (type: IDREF) to SpaceBoundary +32. Added SpaceBoundary child element to Building element along with annotation +33. Added new element: FamilyName (type: string) +34. Added FamilyName child element to Surface +35. Added new elements: Address1, Address2, City, State, ZipCode, Country, PhoneNumber (all of type: string) +36. Added Address1, Address2, City, State, ZipCode, Country, PhoneNumber child elements to PersonInfo element +37. Added ExtEquipId child element to both Construction and WindowType elements for purposes of modeling BIPV. +38. Added 2 enumeration items to powerTypeEnum: Diesel, Biogas +39. Added 1 enumeration item to powerUseTypeEnum: ElectricityGeneration +40. Added 2 enumeration items to tempTypeEnum: HighTempLockout, LowTempLockout +41. Added new enumeration: windSpeedEnum with 3 items: RatedWindSpeed, CutInWindSpeed, CutOutWindSpeed +42. Added new element: WindSpeed with attributes velocityUnitEnum, windSpeedEnum +43. Added WindSpeed child element to ExtEquip element +44. Added ResetTemperature child element to HydronicLoopEquipment element +45. Updated Equation element documentation to clarify dependent vs. independent variables +45. Updated IndependentVariable child element of Equation element to allow for infinite number of independent variables +46. Updated all instances of text "Dependent" and "Independent". It was misspelled. +47. Updated Performance element documentation to clarify that it can represent all types of performance metrics + +0.37 + 12/08 + Added version attribute to gbXML element. + Added the ability to have additional SolarHeatGainCoeff values for Openings and WindowTypes for different angles of incidence defined by a new attribute in the SolarHeatGainCoeff element. + Added the Photometry element to the LightingSystem element. + Added the CADModelID to the CreatedBy element to track the CAD/BIM model the gbXML was created from. + Added CoefficientOfUtilization element to Lighting element. + Added PhotometryOrientation element to Lighting element. + Added Radiator to hydronicEquipTypeEnum. + Added 25 additional systemTypeEnums. +0.36 + 02/08 + Corrected buildingStoreyIdRef attribute in Space element. + Added HydronicLoopEquipmentId element to Space element. + Added airChangesSchedIdRef attribute to Zone element. + Add constraint to Surface element to have a minimum of four defined. + Corrected spelling error in PercentAreaDaylitControlled element in LightingControl element. + Added the following elements to allow USDA-FS to conduct urban/wildland interface fire modeling: BiomassDensity element to Vegetation element, WFTDTemp, WFTDRelHumidity, WFTDWindSpeed, WFTDWindDir, and WFTDPressure to Weather element, Fire to Material element and FireFace to Construction element. + Changed DocumentHistory/CreatedBy and DocumentHistory/ProgramInfo elements to be required. +0.35 + 8/06 + Corrected spelling error in capacityTypeEnum. + Added SingleFamily to buildingTypeEnum. + Replaced sequence requirement with unbound choice. +0.34 + 8/19/03 + Convert spaceTypeEnum facets to Pascal case and added DiningCafeteriaFastFood to buildingTypeEnum. Ensured all enumeration facets are in Pascal case. + 6/25/03 + Added CartesianPoint element to Results element. + Set minNumber for ZipcodeOrPostalCode element under the Location element to 1. + Set Campus element id attribute use to required. + Set Building element id attribute use to required. + Corrected Surface element id attribute use to required. +0.33 + 1/15/02 + Added PolyLoop element to RectangularGeometry for describing polygons + Changed CartesianPoint element to allow only two Coordinate elements for describing flat geometry + Added PeakDomesticHotWaterFlow element to Building + Created PeakDomesticHotWaterFlow element + Moved simple type elements into complex type elements - easier to find correct element + Added enumeration to conditionTypeEnum + 1/14/02 + Made HydronicLoopId repeatable in AirLoopEquipment and HydronicLoopEquipment + Added Name and Description as optional elements to the Results element + 1/10/02 + Created heatGainTypeEnum enumeration and assigned it to the PeopleHeatGain element + Created PeopleHeatGain element and added it to the Space element + Removed TotalPeopleHeatGain and PeopleLatentHeatGain elements + Added systemType attribute to the AirLoop element, and added systemTypeEnum enumeration + Removed Lighting element from gbXML root element + Replaced LightId in Campus and Building elements with Lighting elements that refrence LightingSystem elements directly + Changed InfiltrationFlow/@type to optional + Added an optional HydronicLoop/@primaryLoopId attribute +0.32 + 12/12/01 + Changed xsd:any namespace="##any" to ##other for GeneralGeometry and Meter elements + 12/10/01 + Removed gbXML/CreatorPersonInfo and gbXML/CreatorCadInfo + Created Surface/RectangularGeometry and Opening/RectangularGeometry and their children + Created gbXML/DocumentHistory and its children + Updated schema to version http://www.w3.org/2001/XMLSchema + Changed enumerations for spaceTypeEnum to remove spaces and slashes + Changed Results/@timeIncrement to type xsd:duration as required for the 2001 schema specification +0.31 + 8/1/01 + Added HydronicLoopId to AirLoopEquipment element + 7/26/01 + Added Control element to equipment elements + Added FlowControl element to HydronicLoop element + Added PressureControl element to AirLoop element + Added TemperatureControl element to both loop elements + Added enumerations to tempTypeEnum + 7/25/01 + Added xmlns to schema element + Added conditioningTypeEnum + Changed enumerations for efficiencyTypeEnum + Changed enumerations for resourceTypeEnum + Added stadardsTypeEnum + Added DependentValue element + Added IndependentValue element + Removed XValue element + Removed YValue element + Added RefrigerantType to AirLoopEquipment element + Changed structure of Data element + Added attributes to DeltaP element + Added conditionType attribute to DeltaT element + Made Name and Description elements optional in the DependentVariable element + Added minValue and maxValue attributes to the DependentVariable element + Changed structure of the Efficiency element + Allowed up to 2 IndependentVariable elements in the Equation element + Added fluidType attribute to the HydronicLoop element + Changed structure of HydronicLoopEquipment element + Made Name in IndependentVariable element optional + Changed structure of MinFlow element + Added id attribute to the Performance element + Changed structure of PointData element + 7/9/01 + Added hydronicLoopType to HydronicLoopId + Added HydronicLoopId to HydronicLoopEquipment + 7/3/01 + Added ShadeControl to Opening + Added ShadeSchedule, SolarOnOpening, HorizontalSolar, AirTempature, ZoneCoolingLoad, and Glare to ShadeControl + Added attributes, enumerations, and documentation for these new elements + Removed frameIdRef, blindIdRef, GlazeId, GapId from Opening - they are redundant and already contained in WindowType +0.30 + 6/28/01 + Changed Results element + Removed MaterialType - it did not add information +0.29 + 4/30/01 + Added StreetAddress element to Building - removed Location. + Changed SIResults element to useSIUnitsForResults. + Made several attributes at the gbXML level required instead of defaulting to SI. + Campus/@buildingType removed - Building/@buildingType required. + Changed SpaceId element to AdjacentSpaceId. + Moved CADObjectId after PlanarGeometry in the Opening element. + Made PlanarGeometry/@id optional. + Removed shadeTypeEnum (no longer used). + 4/27/01 + Added annotation to several elements and attributes. + Added Enum to the end of enumerations to clarify distinction between 'type', meaning simple type (used for enumerations) and 'type', used in classifying an object (example: buildingType, surfaceType). +0.28 + 4/12/01 + Added uValueUnit. + Made exposedToSun default = true. + 4/10/01 + Changed sequence of gbXML, Campus, Building, Surface, and Location children. + Added more of a description for Location. + Made Building/@id, Surface/@id optional. + Moved Surface to be child of Campus. + Added enumerations to conditionType. + Changed ShadingSurface element to ExposedToSun boolean attribute. + Renamed SpaceRef to SpaceId, @spaceRef to @spaceIdRef + Removed Name and Description from PlanarGeometry. + Added explicit right-hand-rule documentation to the PolyLoop element. + Constrained PolyLoop to at least 3 CartesianPoints. + Constrained CartesianPoint to exactly 3 Coordinates. + Added @lengthUnit, @areaUnit, @volumeUnit, and @temperatureUnit to the gbXML element. + Changed documentation for Latitude and Longitude. + 4/6/01 + Added targetNamespace. + Removed gbXML/@version. + Made gbXML/@id optional. + Removed GeoPraxisEAM from gbXML/@engine. + Renamed gbXML/SI to gbXML/SIResults and added documentation. + Removed @unit from Latitude and Longitude and made simple type - must be in decimal degrees. + Added global enumerations to be called out elsewhere. +0.27 + 2/13/01 + Removed buildingType attribute from Space. + Added spaceType attribute to Space. + Changed FloorArea to Area. + Changed CADObjectIdRef attribute to CADObjectId element to allow for multiples. + Changed to surface-centric model. + Changed Geometry to PlanarGeometry, ShellGeometry, and GeneralGeometry + 2/12/01 + Changing from X3D elements to ifcXML elements. + Removed X3D element. + Placed in alphabetical order. + Seperated complex types from simple type elements. + Changed back to sequence type - all had unusable restrictions. +0.26 + 2/7/01 + Replaced sequence types with type all. + Removed empty sequence elements. + + + + ACCA has given permission to gbxml authors to use this trademark ACCA and Manual J in the gbXML schema. Users of the gbXML schema are restricted from using the ACCA trademarks for any other purposes without express permission from ACCA. + + + "ASHRAE" is a registered service mark of the American Society of Heating, Refrigerating and Air-Conditioning Engineers, Inc. All rights reserved. + + + Enumerations + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Use to specify the most predominant building use type. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Enumeration value to be used when there is no building type information available. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Coefficient of Performance + + + + + Energy Efficiency Ratio + + + + + Seasonal Energy Efficiency Ratio + + + + + Annual Fuel Utilization Efficiency + + + + + Heating Seasonal Performance Factor + + + + + + + Thermal Efficiency + + + + + Motor Efficiency + + + + + Fan Efficiency + + + + + Mechanical Efficiency + + + + + Boiler Efficiency + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Used with the floorCategory attribute. + + + + + + + + + + + + + + + + + + + + + + + + + + + Used with the floorSlabPerimeterHeatLossCoefficientUnitType attribute. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Used with the hOutsideUnitType attribute. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Opening in a surface with a tilt between 45° and 149.99° with a non-operable glazed opening in it. + + + + + Opening in a surface with a tilt between 45° and 149.99° with a operable glazed opening in it. + + + + + Opening in a surface with a tilt between 0° and 44.99° with a non-operable glazed opening in it. + + + + + Opening in a surface with a tilt between 0° and 44.99° with a operable glazed opening in it. + + + + + Opening in a surface with a tilt between 45° and 149.99° with a sliding door in it. + + + + + Opening in a surface with a tilt between 45° and 149.99° with a non-sliding door in it. + + + + + Opening in a surface with a tilt between 0° and 180° with nothing in it. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Used with the roofASHRAENumber attribute. Each annotation for the values is only one example of many possible constructions for that ASHRAE roof number. The user should select the one that best matches the thermal characteristics of the roof, not necessarily the one closest to the example description. + + + + + Undefined + + + + + Steel sheet with 1 or 2 inches insulation + + + + + One inch wood with 1 inch insulation + + + + + Four inch light weight concrete + + + + + Two inch heavy weight concrete + + + + + One inch wood with 2 inch insulation + + + + + Six inch light weight concrete + + + + + 2.5 inch wood with 1 inch insulation + + + + + Eight inch light weight concrete + + + + + 4 inch hvy wt concrete with 1-2 inch insulation + + + + + 2.5 inch wood with 2 inches of insulation + + + + + Roof Terrace System + + + + + 6 inch hvy wt concrete with 1-2 inch insulation + + + + + 4 inch wood with 1-2 inches of insulation + + + + + + + Used with the roofCLTDIndex attribute. + + + + + Under attic or knee wall, U-value = 0.408 - 0.018, Unvented Attic, No Radiant Barrier, Any Roofing Material, Any Roof Color + + + + + Under attic or knee wall, U-value = 0.408 - 0.018, Vented Attic, No Radiant Barrier, Dark Asphalt Shingles or Dark Metal, Tar and Gravel or Membrane + + + + + Under attic or knee wall, U-value = 0.408 - 0.018, Vented Attic, No Radiant Barrier, White or Light Color Shingles, Any Wood Shake Light Metal, Tar and Gravel or Membrane + + + + + Under attic or knee wall, U-value = 0.408 - 0.02, Vented Attic, No Radiant Barrier, Dark Tile, Slate or Concrete + + + + + Under attic or knee wall, U-value = 0.408 - 0.02, Vented Attic, No Radiant Barrier, Light Tile, Slate or Concrete + + + + + Under attic or knee wall, U-value = 0.408 - 0.02, Vented Attic, No Radiant Barrier, White Tile, Slate or Concrete, White Metal or White Membrane + + + + + On exposed beams, U-value = 0.287 - 0.134, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel + + + + + On exposed beams, U-value = 0.118 - 0.091, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel + + + + + On exposed beams, U-value = 0.074 - 0.063, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel + + + + + On exposed beams, U-value = 0.054, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel + + + + + On exposed beams, U-value = 0.048, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel + + + + + On exposed beams, U-value = 0.043 - 0.039, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel + + + + + On exposed beams, U-value = 0.035, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel + + + + + On exposed beams, U-value = 0.032 - 0.027, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel + + + + + On exposed beams, U-value = 0.287 - 0.134, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel + + + + + On exposed beams, U-value = 0.118 - 0.091, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel + + + + + On exposed beams, U-value = 0.074 - 0.063, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel + + + + + On exposed beams, U-value = 0.054, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel + + + + + On exposed beams, U-value = 0.048, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel + + + + + On exposed beams, U-value = 0.043 - 0.039, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel + + + + + On exposed beams, U-value = 0.035, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel + + + + + On exposed beams, U-value = 0.032 - 0.027, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel + + + + + On exposed beams, U-value = 0.287 - 0.134, White or Light Color Tile, Slate or Concrete, White Metal, White Membrane + + + + + On exposed beams, U-value = 0.118 - 0.091, White or Light Color Tile, Slate or Concrete, White Metal, White Membrane + + + + + On exposed beams, U-value = 0.074 - 0.063, White or Light Color Tile, Slate or Concrete, White Metal, White Membrane + + + + + On exposed beams, U-value = 0.054, White or Light Color Tile Slate or Concrete, White Metal, White Membrane + + + + + On exposed beams, U-value = 0.048, White or Light Color Tile Slate or Concrete, White Metal, White Membrane + + + + + On exposed beams, U-value = 0.043 - 0.039, White or Light Color Tile, Slate or Concrete, White Metal, White Membrane + + + + + On exposed beams, U-value = 0.035, White or Light Color Tile Slate or Concrete, White Metal, White Membrane + + + + + On exposed beams, U-value = 0.032 - 0.027, White or Light Color Tile, Slate or Concrete, White Metal, White Membrane + + + + + Below roof joists, U-value = 0.241 - 0.109, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel + + + + + Below roof joists, U-value = 0.09 - 0.076, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel + + + + + Below roof joists, U-value = 0.069, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel + + + + + Below roof joists, U-value = 0.051 - 0.047, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel + + + + + Below roof joists, U-value = 0.034, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel + + + + + Below roof joists, U-value = 0.029, Dark or Bold-Color Asphalt Shingle, Dark Metal, Dark Membrane, Dark Tar and Gravel + + + + + Below roof joists, U-value = 0.241 - 0.109, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel + + + + + Below roof joists, U-value = 0.09 - 0.076, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel + + + + + Below roof joists, U-value = 0.069, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel + + + + + Below roof joists, U-value = 0.051 - 0.047, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel + + + + + Below roof joists, U-value = 0.034, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel + + + + + Below roof joists, U-value = 0.029, White or Light Color Asphalt Shingle, Any Wood Shake, Dark or Medium Color Tile, Slate or Concrete, Light or Unpainted Metal, Light or Silver Membrane, Light Tar and Gravel + + + + + Below roof joists, U-value = 0.241 - 0.109, White or Light Color Tile, Slate or Concrete, White Metal, White Membrane + + + + + Below roof joists, U-value = 0.09 - 0.076, White or Light Color Tile, Slate or Concrete, White Metal, White Membrane + + + + + Below roof joists, U-value = 0.069, White or Light Color Tile, Slate or Concrete, White Metal, White Membrane + + + + + Below roof joists, U-value = 0.051 - 0.034, White or Light Color Tile, Slate or Concrete, White Metal, White Membrane + + + + + Below roof joists, U-value = 0.029, White or Light Color Tile, Slate or Concrete, White Metal, White Membrane + + + + + + + Used with the roofColor attribute. Only enter Light if the construction is a roof and if it's in a rural location. + + + + + Dark colored or light colored in an industrial area + + + + + Permanently light colored and in a rural area + + + + + + + Used with the roofCTSType attribute. Each annotation for the values is only one example of many possible constructions for that CTS type. The user should select the one that best matches the thermal characteristics of the roof, not necessarily the one closest to the example description. + + + + + Metal Roof, R-19 Batt Insulation, Gyp Board + + + + + Metal Roof, R-19 Batt Insulation, Suspended Acoustical Ceiling + + + + + Metal Roof, R-19 Batt Insulation + + + + + Asphalt Shingles, Wood Sheathing, R-19 Batt Insulation, Gyp Board + + + + + Slate or Tile, Wood Sheathing, R-19 Batt Insulation, Gyp Board + + + + + Wood Shingles, Wood Sheathing, R-19 Batt Insulation, Gyp Board + + + + + Membrane, Sheathing, R-10 Insulation Board, Wood Deck + + + + + Membrane, Sheathing, R-10 Insulation Board, Wood Deck Suspended Acoustical Ceiling + + + + + Membrane, Sheathing, R-10 Insulation Board, Metal Deck + + + + + Membrane, Sheathing, R-10 Insulation Board, Metal Deck Suspended Acoustical Ceiling + + + + + Membrane, Sheathing, R-15 Insulation Board, Metal Deck + + + + + Membrane, Sheathing, R-10 plus R-15 Insulation Boards, Metal Deck + + + + + 2" Concrete Roof Ballast, Membrane, Sheathing, R-15 Insulation Board, Metal Deck + + + + + Membrane, Sheathing, R-15 Insulation Board, 4" LW Concrete + + + + + Membrane, Sheathing, R-15 Insulation Board, 6" LW Concrete + + + + + Membrane, Sheathing, R-15 Insulation Board, 8" LW Concrete + + + + + Membrane, Sheathing, R-15 Insulation Board, 6" HW Concrete + + + + + Membrane, Sheathing, R-15 Insulation Board, 8" HW Concrete + + + + + Membrane, 6" HW Concrete, R-19 Batt Insulation, Suspended Acoustical Ceiling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Department of Energy + + + + + Air-Conditioning and Refrigeration Institute + + + + + American National Standards Institute + + + + + National Electrical Manufacturers Association + + + + + + + + + A five-digit station identifier assigned by the World Meteorological Organization (WMO), used for international weather data exchange and station documentation. + + + + + Weather-Bureau-Army-Navy station id. A five-digit station identifier used at National Climatic Data Center (NCDC) for digital data storage and general station identification purposes. + + + + + A 4-letter indicator for geographical locations throughout the world, managed by the International Civil Aviation Organization (ICAO). + + + + + A 3- to 5-character alpha-numeric identifier assigned by the US National Weather Service (NWS), used for site identification in the NWS communications systems (e.g. AFOS, ROSA, SHEF, etc.). + + + + + An alpha-numeric identifier of up to 4-characters managed by the USDT Federal Aviation Administration (FAA), used for site identification of airports, weather stations and other sites vital to navigation. + + + + + A 6-digit number identifying a station in the NWS Cooperative Network. + + + + + A custom code identifying a virtual station for a particular grid location on the planet that was modeled by a simulation program such as MM5, WRF, or other weather simulation programs. + + + + + + + + + Surface adjacent to two conditioned or unconditioned spaces with a tilt between 45° and 149.99°. + + + + + Surface adjacent to one conditioned or unconditioned space and the outside with a tilt between 45° and 149.99°. + + + + + Surface adjacent to one conditioned or unconditioned space and the outside with a tilt between 0° and 44.99°. + + + + + Surface adjacent to two conditioned or unconditioned spaces with a tilt between 150° and 180°. + + + + + Surface not adjacent to any spaces with tilt between 0° and 180°. + + + + + Surface adjacent to one conditioned or unconditioned space and earth (soil) with a tilt between 45° and 149.99°. + + + + + Surface adjacent to one conditioned or unconditioned space and earth (soil) below grade with a tilt between 150° and 180°. + + + + + Surface adjacent to two conditioned or unconditioned spaces with a tilt between 0° and 44.99°. + + + + + Air membrane between two conditioned or unconditioned spaces with a tilt between 0° and 180°. + + + + + Surface adjacent to one conditioned or unconditioned space and earth (soil) with a tilt between 0° and 44.99°. + + + + + Surface adjacent to one conditioned or unconditioned space and the outside with a tilt between 150° and 180°. + + + + + Surface adjacent to one conditioned or unconditioned space and earth (soil) at grade with a tilt between 150° and 180°. + + + + + Freestanding column in space specified by its top surface having the same ifcGUID. + + + + + Embedded column in wall specified by a surface which is coplanar with (one of) the embedding wall(s). + + + + + + + + + Variable Temperature + + + + + Packaged Single-zone + + + + + Ceiling Induction + + + + + Constant-volume Reheat Fan + + + + + Variable-volume Fan + + + + + Powered Induction Unit + + + + + Packaged Variable Air Volume + + + + + Packaged Variable-Volume Variable-Temperature + + + + + Ceiling Bypass + + + + + Evaporative Cooling + + + + + Multizone Fan + + + + + Packaged Multizone + + + + + Dual-duct Fan + + + + + Fan Coil + + + + + Induction Unit + + + + + Packaged Terminal Air Conditioner + + + + + Water Loop Heat Pump + + + + + Residential with cycling furnace and cycling air-conditioner + + + + + Residential Variable-Volume Variable-Temperature + + + + + Floor Panel Heating + + + + + Heating and Ventilating + + + + + Unit Heater + + + + + Unit Ventilator + + + + + Central Heating Radiators + + + + + Central Heating Convectors + + + + + Central Heating Radiant Floor + + + + + Central Heating Hot Air + + + + + Other Room Heater + + + + + Radiant Heater No Flue + + + + + Radiant Heater Flue + + + + + Radiant Heater Multiburner + + + + + Forced Convection Heater Flue + + + + + Forced Convection Heater No Flue + + + + + VAV Single Duct + + + + + VAV Dual Duct + + + + + VAV Reheat Fan + + + + + VAV Indoor Packaged Cabinet + + + + + Constant Volume Fixed OA + + + + + Constant Volume Variable OA + + + + + Constant Volume Terminal Reheat + + + + + Multizone Hot Deck Cold Deck + + + + + Constant Volume Dual Duct + + + + + Radiant Cooled Ceilings + + + + + Active Chilled Beams + + + + + Variable Refrigerant Flow + + + + + Split Systems With Natural Ventilation + + + + + Split Systems With Mechanical Ventilation + + + + + Split Systems With Mechanical Ventilation With Cooling + + + + + Exhaust Air Systems + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Used with the wallASHRAEGroup attribute. Each annotation for the values is only one example of many possible constructions for that ASHRAE wall group. The user should select the one that best matches the thermal characteristics of the wall, not necessarily the one closest to the example description. + + + + + 4-in. face brick, insulation + 8-in. com. brick + + + + + 4-in. face brick, 2-in. insul., 4-in. com. brick + + + + + 4-in. face brick, air space + 4-in. face brick + + + + + 4-in. face brick + 4-in. common brick + + + + + 4-in. face brick + 4-in. block + + + + + 4-in. block + air space or insulation + + + + + Metal curtain wall + 1 to 3-in. insulation + + + + + + + Used with the wallColor attribute. Only enter Light or Medium if the construction is a wall and if it's in a rural location. + + + + + Dark colored or light colored in an industrial area + + + + + Permanently medium colored and in a rural area + + + + + Permanently light colored and in a rural area + + + + + + + Used with the wallCTSType attribute. Each annotation for the values is only one example of many possible constructions for that CTS type. The user should select the one that best matches the thermal characteristics of the wall, not necessarily the one closest to the example description. + + + + + Spandrel Glass, R-10 Insulation Board, Gyp Board + + + + + Metal Wall Panel, R-10 Insulation Board, Gyp Board + + + + + 1" Stone, R-10 Insulation Board, Gyp Board + + + + + Metal Wall Panel, Sheathing, R-11 Batt Insulation, Gyp Board + + + + + 1" Stone, Sheathing, R-11 Batt Insulation, Gyp Board + + + + + Wood Siding, Sheathing, R-11 Batt Insulation, 1/2" + Wood + + + + + 1" Stucco, Sheathing, R-11 Batt Insulation, Gyp Board + + + + + EIFS Finish, R-5 Insulation Board, Sheathing, Gyp Board + + + + + EIFS Finish, R-5 Insulation Board, Sheathing, R-11 Batt Insulation, Gyp Board + + + + + EIFS Finish, R-5 Insulation Board, Sheathing, 8" LW CMU, Gyp Board + + + + + Brick, R-5 Insulation Board, Sheathing, Gyp Board + + + + + Brick, Sheathing, R-11 Batt Insulation, Gyp Board + + + + + Brick, R-5 Insulation Board, Sheathing, R-11 Batt Insulation Gyp Board + + + + + Brick, R-5 Insulation Board, 8" LW CMU + + + + + Brick, 8" LW CMU, R-11 Batt Insulation, Gyp Board + + + + + Brick, R-5 Insulation Board, 8" HW CMU, Gyp Board + + + + + Brick, R-5 Insulation Board, Brick + + + + + Brick, R-5 Insulation Board, 8" LW Concrete, Gyp Board + + + + + Brick, R-5 Insulation Board, 12" HW Concrete, Gyp Board + + + + + Brick, 8" HW Concrete, R-11 Batt Insulation, Gyp Board + + + + + 8" LW CMU, R-11 Batt Insulation, Gyp Board + + + + + 8" LW CMU w Fill Insulation, R-11 Batt Insulation, Gyp Board + + + + + 1" Stucco, 8" HW CMU, R-11 Batt Insulation, Gyp Board + + + + + 8" LW CMU w Fill Insulation + + + + + 8" LW CMU w Fill Insulation, Gyp Board + + + + + 12" LW CMU w Fill Insulation, Gyp Board + + + + + 4" LW Concrete. R-5 Board Insulation, Gyp Board + + + + + 4" LW Concrete. R-11 Batt Insulation, Gyp Board + + + + + 4" LW Concrete. R-10 Board Insulation, 4" LW Concrete + + + + + EIFS Finish, R-5 Insulation Board, 8" LW Concrete, Gyp Board + + + + + 8" LW Concrete. R-11 Batt Insulation, Gyp Board + + + + + EIFS Finish, R-10 Insulation Board, 8" HW Concrete, Gyp Board + + + + + 8" HW Concrete. R-11 Batt Insulation, Gyp Board + + + + + 12" HW Concrete. R-19 Batt Insulation, Gyp Board + + + + + 12" HW Concrete + + + + + + + Used with the wallGroupManualJ attribute. + + + + + Fastest heat transfer + + + + + + + + + + + + + + + + + + + + + + + + + Medium heat transfer + + + + + + + + + + + + + + + + + + + + + + + + + Slowest heat transfer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Analysis engine used + + + + + + + + + + + + This attribute specifies the default temperature unit for the entire gbXML document, wherever the temperatureUnit simple type is used. + + + + + This attribute specifies the default length unit for the entire gbXML document, wherever the lengthUnit simple type is used. + + + + + This attribute specifies the default area unit for the entire gbXML document, wherever the areaUnit simple type is used. + + + + + This attribute specifies the default volume unit for the entire gbXML document, wherever the volumeUnit simple type is used. + + + + + Results will be given in SI or IP units. True = SI units which is the implied default. If False, results will be in english units. + + + + + + + + + Absorptance of the outside surface + + + + + + + + + + + + + + + ID for a space that is bounded by this surface. First AdjacentSpaceId entered will determine how the referenced construction layers are ordered with the first construction layer being in contact with the outside or 2nd space listed and the last layer in contact with the first space listed. The outward normal of the surface, as defined by the right hand rule of the coordinates in the planar geometry element, is always pointing away from the first AdjacentSpaceID listed. + + + + + With interior horizontal surfaces, this attribute can distinguish between ceiling and floor surfaces to avoid double-counting of floor areas, etc. May be required in future schema versions. + + + + + + + + + + + + + + + + + + + + + + + The AirLoop element represents the equipment serving one path of air + + + + + + + + + + + + + + + + Please specify the program that added this element. + + + + + + + A piece of equipment serving an air-loop. This is generalized to be able to contain any type of air loop equipment. The air loop equipment are ordered as they exist on the airloop. A blow-through system should have fan listed before the coils. A draw-through system should have the fan listed after the coils. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Please specify the program that added this element. + + + + + + + + + ID pointing at an air loop equipment object + + + + + + + + + ID pointing to an air loop + + + + + + + Minimum air temperature before shades are closed. + + + + + + + + + + + + + Cooling and Heating Reset Temperature Type + + + + + + + + + + + + + Reflectance of solar radiation + + + + + + + + + + + + Alternative energy source + + + + + + + + + + + + + + + + + + + + + + Please specify the program that added this element. + + + + + + + Specifies the area of the space or building. This value should be equal to the area enclosed by the physical boundaries of the space, as defined by the intersection of the horizontal plane at the highest floor height and the volumetric model's vertical interior surface planes. Building area should be the sum of space areas whose PeopleNumber element values are greater than zero. + + + + + + + + + + + + + Polygon azimuth. The direction of the outward normal for the polygon (surface or opening) defined in RectangularGeometry element. Azimuth is measured in degrees clockwise from North, where North = 0 degrees. Examples: East = 90 deg, South = 180 deg, West = 270 deg. If CADModelAzimuth is defined, the Azimuth value is relative to the CADModelAzimuth value rather then North. + + + + + + + + + + + Type of ballast used + + + + + Month and day year schedule begins + + + + + Date of holiday modeled + + + + + Biomass of vegetation + + + + + + + + + + + + + + + + + + + + + + + + + + Leakage value obtained from blower door test. + + + + + + + + + + + + + + + + + + + + + + Use this element to define the shell of the building. + + + + + This element establishes the logical relation of a given part of the building envelope such that its PlanarGeometry is part of an exterior surface of the building. + + + + + + + + + + + + + Global Unique ID from Industry Foundation Class (IFC) file. + + + + + + + Captures Building Storey Structure + + + + + + + + + + + Global Unique ID from Industry Foundation Class (IFC) file. + + + + + + + + + ID used by a CAD/BIM program to reference its internal materials library + + + + + + + The number of degrees (0 to 360) of the angle of positive Y axis from north. (Value of the of Azimuth of Model's North relative to Cardinal North) + + + + + The CADModelId Element is used to map a CAD model or BIM to its corresponding gbXML file. Allows the CAD/BIM tool referenced by the programIdRef to correlate the gbXML file to its CAD/BIM model. + + + + + + + ID reference to unique CAD/BIM program defined in DocumentHistory/ProgramInfo element. + + + + + + + + + The CADObjectId Element is used to map unique CAD object identifiers to gbXML elements. Allows CAD/BIM tools to read results from a gbXML file and map them to their CAD objects. + + + + + + + ID reference to unique CAD/BIM program defined in DocumentHistory/ProgramInfo element. + + + + + + + + + The Campus element should be used as the base for all physical objects. On a campus, place one or more buildings. + + + + + + + + + + + + + + + + + + + + + + + + ID for the weather data used for a heating design day + + + + + ID for the weather data used for a cooling design day + + + + + Global Unique ID from Industry Foundation Class (IFC) file. + + + + + + + + + + + + + + + + + This is the x, y, and z distances from the origin. This element must have three Coordinate elements when representing 3-d space, which represent x, y and z in order. This element must have two Coordinate elements when representing 2-d space. + + IfcCartesianPoint + + + + + + + + + + + Cooling degree days. CDD is calculated as the number of degrees a mean daily temperature is above a value (specified as the Temperature element), for each day. For example, if the mean temperature in a region rises to 77 degrees for three days during a year, the rest of the time staying below 75, and the Temperature element is set at 75, then CDD = 6. + + + + + + + + + + + Cooling degree day value + + + + + + This is an element from ifcXML that describes a collection of faces that make up a closed shell. + + IfcClosedShell + + + + + + + + + + + Parameters required by CLTD load calculation method, as described in the 1989 ASHRAE Handbook, Fundamentals volume, pages 26.32 and following. Ignore this element and all elements under it if you are not planning to use that method. + + + + + Specifies the number 1 to 13 to use for a roof. See Table 29 page 26.34, 1989 ASHRAE Handbook, Fundamentals volume. + + + + + Specifies the wall group code A to G to use for a wall. See Table 31, page 26.36, 1989 ASHRAE Handbook, Fundamentals volume. + + + + + Specifies the effective roof color, which depends on the actual color and whether the location is industrial or rural. See page 26.34, 1989 ASHRAE Handbook, Fundamentals volume. + + + + + Specifies whether or not a roof has a suspended ceiling under it. See table 29, page 26.34, 1989 ASHRAE Handbook, Fundamentals volume. + + + + + Specifies the effective wall color, which depends on the actual color and whether the location is industrial or rural. See page 26.36, 1989 ASHRAE Handbook, Fundamentals volume. + + + + + + + The coefficient of utilization is the ratio of luminous flux on a work plane to the luminous flux emitted by the lamps alone. + + + + + + + + + + Room cavity ratio is a measure of the room cavity proportions. + + + + + + + + + + + + + + + + + + + Conductivity as a function of temperature + + + + + + + + + + + + A Construction is a combination of layers, such as a wall or a roof + + + + + + + + + + + + + + + + + + Reference to layers that comprise this construction. Multiple LayerId's order is important and specifies the layering of the layer's referenced materials. The first Surface/AdjacentSpaceId entered will determine how the referenced construction layers are ordered with the first construction layer being in contact with the outside or 2nd Surface/AdjacentSpaceId listed and the last layer in contact with the first Surface/AdjacentSpaceId listed. + + + + + This element is for purposes of modeling BIPV (building integrated photovoltaics). + + + + + + + + Use this attribute to reference objects in the DOE2 library + + + + + Please specify the program that added this element. + + + + + + + The Control element should be used for describing how this equipment is controlled. + + + + + + + + + + + + This is the an x, y, or z length measurement from the origin. + + IfcLengthMeasure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Denotes the time this file has been created, as well as the person and program used to create this file. + + + + + + + + + + + + + + Number of operation cycles per week. + + + + + + + + + + + + + + + + + ID for operation schedules + + + + + + + + + + Allows for including daylight savings time + + + + + Set of values that define the profile of one 24 hour period divided equally to the number of values entered. + + + + + + + + + + + + + + Day of the month that the cooling design day occurs on + + + + + Day of the month that the heating design day occurs on + + + + + Flag for daylight savings on the cooling design day + + + + + Flag for daylight savings for the heating design day + + + + + Cooling design day dry bulb temperature + + + + + + + + + + + + Heating design day dry bulb temperature + + + + + + + + + + + + Cooling design day dry bulb temperature range + + + + + + + + + + + + Heating design day dry bulb temperature range + + + + + + + + + + + + Ground temperature on the cooling design day + + + + + + + + + + + + Ground temperature for the heating design day + + + + + + + + + + + + Cooling design day hour of high temperature + + + + + Heating design day hour of high temperature + + + + + Cooling design day hour of low temperature + + + + + Heating design day hour of low temperature + + + + + Month the cooling design day lands on. 1=Jan 12=Dec + + + + + Month that the heating design day occurs on. 1=Jan 12=Dec + + + + + Cooling design day atmospheric pressure + + + + + + + + + + + + Heating design day atmospheric pressure + + + + + + + + + + + + Flag for rain on the cooling design day. 0=no rain 1=rain + + + + + Heating design day rain flag. 0=no rain, 1=rain + + + + + Cooling design day sky clearness + + + + + + + + + + + + Heating design day sky clearness + + + + + + + + + + + + Flag for snow on the cooling design day. 0=not snowing 1=snowing + + + + + Heating design day snow flag. 0=not snowing 1=snowing + + + + + Cooling design day wet bulb temperature + + + + + + + + + + + + Heating design day wet bulb temperature + + + + + + + + + + + + Cooing design day wind direction + + + + + + + + + + + + Heating design day wind direction + + + + + + + + + + + + Cooling design day wind speed + + + + + + + + + + + + Heating design day wind speed + + + + + + + + + + + + Difference in pressure + + + + + + + + + + Use this attribute for conditioning units with both heating and cooling. + + + + + Use this attribute to point to a performance curve if one is provided + + + + + + + + + Difference in temperature + + + + + + + + Use this attribute for conditioning units with both heating and cooling. + + + + + + + + + + + + + + + + + + Density as a function of temperature + + + + + + + + + + + + Value of a dependent variable for this data point + + + + + + + + + + + + + Use minValue and maxValue to define constraints on the curve. + + + + + + + + + Design temperature for cooling + + + + + + + + Please specify the program that added this element. + + + + + + + + + + + + + + + + + + Design temperature for heating + + + + + + + + Please specify the program that added this element. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Contains details about people and programs that created and modified this file + + + + + + + + + + + + + + + + + Use the standardsType attribute when the efficiency is measured at standard conditions. + + + + + + Use this attribute for conditioning units with both heating and cooling. + + + + + Use this attribute to point to a performance curve if one is provided + + + + + + + + + Electric load + + + + + + + + + + + + Height above sea level + + + + + + + + + + + + + + + + + + + + + + Infra-red emissivity + + + + + + + + + + + + + Month and day year schedule ends + + + + + + + + + + + + + ID for a resource meter + + + + + + + + + Minimum enthalpy setpoint for air-side economizer. + + + + + + + + + + + + The Equation element allows data for n-dimensional algebraic data to be entered. The Expression element should contain an dependent variable followed by an = sign and an equation containing independent variables. The independent and dependent variables are then defined by their respective tags. The only mathematical operations allowed are ^ (power), + (addition), - (subtraction), / (division), and * (multiplication). Example: z=x+2*y^2 would have an DependentVariable with a name = z, and two IndependentVariable(s) with names of x and y. Descriptions would be included for each variable, along with unit and dataType information identifying the variable and its role. + + + + + + + + + + + + Amount of power used by equipment in a given area + + + + + + + + Please specify the program that added this element. + + + + + + + + + + External equipment. This is generalized to be able to contain any type of external equipment. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ID for the schedule of transmittance of a shading surface + + + + + + ID pointing to a hydronic loop + + + + + + + + ID pointing to an air loop + + + + + Please specify the program that added this element. + + + + + + + + + + + + + + + + + + Properties of a material under fire conditions. + + + + + + + + + + + + + Properties of a construction under fire conditions. + + + + + + + + + + + + + + + + + + Specifies the heat loss from a floor in terms of the amount of heat lost per length of exposed perimeter. Used with both commercial and residential load calculation methods. + + + + + + + + + + + + + + + + + Please specify the program that added this element. + + + + + + + + + Use this element to describe how the fluid flow is controlled. The temperatures specified in this element should be measured just upstream of the chiller. + + + + + + + + + + + + + + + + + + Please specify the program that added this element. + + + + + + + + + + + + + + Please specify the program that added this element. + + + + + + + + + + + + + + + + + + Use this attribute to reference objects in the DOE2 library + + + + + + + + + + + + + + + + Space between window panes + + + + + + + + + + + + + + + + + + + + Use this attribute to reference objects in the DOE2 library + + + + + + + + + ID for a gap between window panes + + + + + + + This element has been left open for use with other geometry definitions, such as X3D or BLISXML. + + + + + + + + + + Minimum amount of glare to trigger the shades to close + + + + + + + + + + + + Properties of one layer of a window + + + + + + + + + + + + + + + + Use this attribute to reference objects in the DOE2 library + + + + + + + + + + + + + + + + + + ID indicating the type of glaze used + + + + + + + Monthly ground temperatures, 12 values + + + + + + + + + + + + + + + + + + + + + + Heating degree days. HDD is calculated as the number of degrees a mean daily temperature is below a value (specified as the Temperature element), for each day. For example, if the mean temperature in a region drops to 64 degrees for four days during a year, the rest of the time staying above 65, and the Temperature element is set at 65, then HDD = 4. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Amount of horizontal solar radiation striking the opening before a shade is closed. + + + + + + + + + + + + h (Outside) is the combined coefficient of heat transfer by long-wave radiation and convection at outer surface, Btu/h-sf-F. See 2001 HoF Chapter 25 Table 1. + + + + + + + Used by the hOutsideUnitType attribute. + + + + + + + + + The HydronicLoop element represents the equipment serving one path of water, or other liquid + + + + + + + + + + + + + + + + + + Only use this attribute for secondary loops to reference the primary loop. + + + + + Please specify the program that added this element. + + + + + + + A piece of equipment serving a hydronic loop (most commonly a water loop). This is generalized to be able to contain any type of hydronic loop equipment. + + + + + + + + + + + + + Use this element to point to another loop. For instance if this is a chiller and is a child of a chilled water loop, use this element to point at a cooling water loop. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Please specify the program that added this element. + + + + + + + + + ID pointing at a hydronic loop equipment object + + + + + + + + + ID pointing to a hydronic loop + + + + + Type of hydronic loop + + + + + + + + + + + + + + + + This is an X3D element to map a texture to this material. From X3D specification: The ImageTexture node defines a texture map by specifying an image file and general parameters for mapping to geometry. Texture maps are defined in a 2D coordinate system (s, t) that ranges from [0.0, 1.0] in both directions. The bottom edge of the image corresponds to the S-axis of the texture map, and left edge of the image corresponds to the T-axis of the texture map. The lower-left pixel of the image corresponds to s=0, t=0, and the top-right pixel of the image corresponds to s=1, t=1. + + + + + + Specifies location of the image. From X3D specification: The texture is read from the URL specified by the url field. When the url field contains no values, texturing is disabled. Browsers shall support the JPEG and PNG image file formats. In addition, browsers may support other image formats (e.g. CGM) which can be rendered into a 2D image. Support for the GIF format is also recommended (including transparency). + + + + + From X3D specification: If repeatS is TRUE, the texture map is repeated outside the [0.0, 1.0] texture coordinate range in the S direction so that it fills the shape. If repeatS is FALSE, the texture coordinates are clamped in the S direction to lie within the [0.0, 1.0] range. + + + + + From X3D specification: If repeatT is TRUE, the texture map is repeated outside the [0.0, 1.0] texture coordinate range in the T direction so that it fills the shape. If repeatT is FALSE, the texture coordinates are clamped in the T direction to lie within the [0.0, 1.0] range. + + + + + + + Value of the independent variable for this data point + + + + + + + + + + + + + + + + + + + + + + + ID for the schedule of transmittance of a shading surface + + + + + + + Flow of air through building envelope + + + + + + + + + + Please specify the program that added this element. + + + + + + + + + + + + + + + + Thermal resistance of the internal air film in a layer + + + + + + + + + + + + Interior equipment. This is generalized to be able to contain any type of internal equipment. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ID for the schedule of transmittance of a shading surface + + + + + + ID pointing to a hydronic loop + + + + + + + + ID pointing to an air loop + + + + + Please specify the program that added this element. + + + + + + + + + ID pointing at an interior equipment object + + + + + + + Type of lamp used + + + + + + + + + + + + + + + Degrees north of the equator, in decimal degrees. Locations south of the equator are negative. + + + + + A Layer is a combination of one of more materials + + + + + + + + + + + + + Use this attribute to reference objects in the DOE2 library + + + + + + + + + ID identifying a layer in this construction. Multiple layers in Constructions are in order from outside to inside. + + + + + + + + + + + + + + + + Building storey Local Placement Z coordinate. + + + + + + + + + + + + + + + + + + + + + + + + + ID for the schedule of transmittance of a shading surface + + + + + + + + + + + Identifier pointing at a light object + + + + + + + + + + + + + + + + + + ID for a resource meter + + + + + Please specify the program that added this element. + + + + + + + + + + + + Illuminance level that the lights are maintained if daylighting controls present (lightControlTypeEnum not equal to on off). + + + + + Location where Illuminance value is specified. + + + + + + + + + + + + Please specify the program that added this element. + + + + + + + + + + + + + + + + + + + + + + + + + + Please specify the program that added this element. + + + + + + + Amount of power used by lighting in a given area + + + + + + + + Please specify the program that added this element. + + + + + + + + + + + + + + + + + + + The Location element describes the location of the global origin for this campus. This element can be used in a general sense by using the Name and Description elements for a physical address or landmark, or Location can be made precise by specifying the Elevation, Longitude, and Latitude of the origin. + + + + + + + + + + + + + + + + + Degrees east of Greenwich, in decimal degrees. Locations west of Greenwich are negative. + + + + + + + + + + + + + + + Type of luminaire used + + + + + Parameters required by the ACCA Manual J Eighth Edition load calculation method. Ignore this element and all elements under it if you are not planning to use that method. + + + + + Specifies the group code for the wall, which determines how quickly the wall delivers heat into the space. See Table 4C, page T4C-1 ACCA Manual J Eighth Edition. + + + + + Specifies the array of CLTD values to use for the roof, which determines how quickly the roof delivers heat into the space. See Table 4A page T4A-18 and following, ACCA Manual J Eighth Edition. + + + + + Specifies whether or not to use a higher heating temperature difference value in calculating the heating loss for a floor (25 degrees F higher value is used in formula if floor is radiant). See Figure A5-5, page A5-8, ACCA Manual J Eighth Edition. + + + + + Specifies the u-value of the crawl space wall that is associated with the floor, which affects both the heating and cooling load. See Figure A5-5, page A5-8, and Figure A5-17, page A5-16, ACCA Manual J Eighth Edition. + + + + + Specifies whether or not the crawl space wall associated with this floor is well sealed from the outdoor air, which affects both the heating and cooling loads. See Figure A5-5, page A5-8, and Figure A5-17 page A5-16, ACCA Manual J Eighth Edition. + + + + + Specifies the type of floor being considered, which affects both the heating and the cooling loads. See Table 4A, pages T4A-27 and following, ACCA Manual J Eighth Edition. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Use this attribute to reference objects in the DOE2 library + + + + + + + + + ID identifying a material in this layer. Multiple materials in layers are in order from outside to inside. + + + + + Percentage (1-100%) of this layer that this material is made from. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Description of a resource measurement + + + + + + + + + + + + + Please specify the program that added this element. + + + + + + + + + ID for a resource meter + + + + + + + + Minimum flow + + + + + + + + + + + + + + + + + + + + + + + + + + + Fraction of light illuminance used at minimum setting. + + + + + + + + + + + + + + Fraction of power used at minimum setting. + + + + + + + + + + + + + + + + + + + + Denotes the time this file has been modified, as well as the person and program used to modify this file. + + + + + + + + + + Indicates if the motor is located in the path of the air stream. + + + + + + Natural ventilation does not occur above this temperature. + + + + + + + + + + + + Natural ventilation does not occur below this temperature. + + + + + + + + + + + + Occupancy dependence of natural ventilation. If true, then natural ventilation only occurs when people are present. + + + + + + Outside air flow per area + + + + + + + + Please specify the program that added this element. + + + + + + + + + Outside air flow per person + + + + + + + + Please specify the program that added this element. + + + + + + + + + Indicates which object or objects the results apply to, if any + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Identifier pointing to a construction + + + + + + Global Unique ID from Industry Foundation Class (IFC) file. + + + + + + + + + + + + + + + + + + + + Schedule of operation for a piece of equipment. For heating and cooling equipment (such as a boiler or chiller) this is the availability schedule, the schedule of temperatures that, when reached, the piece of equipment will be available. + + + + + + + Use this element to report overall domestic hot water use for the domestic hot water loop referenced with the hydronicLoopIdRef attribute. The schedule referenced by waterUseScheduleIdRef defines a hot water use fraction schedule, which when combined with the value of PeakDomesticHotWaterFlow fully describe the hot water use of this building. + + + + + + + + + + Please specify the program that added this element. + + + + + + + + + Occupancy of the space + + + + + + + + Please specify the program that added this element. + + + + + + + + + Amount of heat added to the space by people + + + + + + + + + Please specify the program that added this element. + + + + + + + + + Percent of space area whose lights are controlled by a daylight sensor. Only applicable when LightPowerPerArea is used at the space level and not Lighting Systems. + + + + + + + + + + + + Percent of original building shell used in renovation + + + + + + + + + + + + Used to represent part-load performance and other performance metrics + + + + + + + + + + + + + The rate water vapor is allowed through a surface + + + + + + + + + + + + Contains information about people that created and modified this file + + + + + + + + + + + + + + + + + + + + + + + This element has been left open for use with other photometry definitions. Photometric data is required for various forms of lighting analysis. This tag provides a way for the photometric data to be passed. Since this can be done in a variety of ways (iesna LM-63, cibse TM14, ELUMDAT, etc.) a specific format is not being specified. + + + + + This element specifies the position and the x, y and z axis of the light source. This element must have four Coordinate elements which represent the position and the x, y and z axis in order. The first CartesianPoint element specifies the position of the light source. The second, third and fourth CartesianPoint elements specifies the displacement points for the positive x, positive y and positive z axis. + + + + + + + + + + List of points defining a loop. There are no repeated points in the list. All data are global, with the assumption that positive Z is up, and if CADModelAzimuth is undefined or zero, positive X is East and positive Y is North. If CADModelAzimuth is defined it is the angle of positive Y to North, positive X is the vectorial product of Y and Z. If geometry is to be precise, use Longitude, Latitude and Elevation in the Location element to define the origin. Otherwise the origin is an arbitrary point. Use PlanarGeometry to define a three dimensional polygon that lies on a plane, and has no self-intersection. + + + + + + + + + + + + + The PointData element allows for graph or tabular information to be entered. The data type and units of the independent and dependent variables are defined in their respective elements. Each Data element represent a data point, with each Value element representing the value of a variable - starting with the independent variable, then each dependent variable listed in the order defined. + + + + + + + + + + + + This is a list of coordinates that make up a polygon in three-dimensional space. All coordinates must lie on the same plane. The right-hand rule applies for defining the outward normal of a surface: For every surface, points must be defined in order, such that the direction of (the average cross-product between (any point, the centroid of the surface, and the next point)) points in the direction of the outward normal, which is a vector pointing away from the first AdjacentSpaceID listed. + + IfcPolyLoop + + + + + + + + + + + the ratio of the total amount of void space in a material (due to poses, small channels, and so on) to the bulk volume occupied by the material. + + + + + + + + + + + + Maximum consumption of energy (power input) + + + + + + + + + + ID for a resource meter + + + + + + + + + + Prandtl number as a function of temperature + + + + + + + + + + + + Use this element to describe how the air pressure is controlled. The temperatures specified in this element should be measured just upstream of the air handlers. + + + + + + + + + + + + + + + + + + + Contains information about the originating or modifying file or service that created or modified this file + + + + + + + + + + + + Contains information about programs that created and modified this file + + + + + + + + + + + + + + + + + + + + + + + + + + Geometry data in a form typically used in simulation engines. For surfaces, specify the location of the bottom-left corner with the CartesianPoint element when facing it from the outside. Also for surfaces, Tilt and Azimuth must be specified. If CADModelAzimuth is defined, the Azimuth value is relative to the CADModelAzimuth value rather then North. For openings, the third Coordinate should be zero or left missing. For openings, these Coordinates represent the distance of the bottom-left of the opening to the bottom-left corner of the parent surface. Azimuth and Tilt should not be specified for opening. There is an optional PolyLoop element, which may be used for describing the polygon shape of the surface. + + + + + + + + + + + This is a two-dimensional polygon, with the origin at the point specified with RectangularGeometry/CartesianPoint. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Please specify the program that generated the results using the id of the ProgramInfo element. + + + + + Please specify how the values were obtained. + + + + + Use the startTime attribute to define the start of the first Value element. + + + + + This specifies the duration of time between each Value element. This is required if more than one Value element exists in a this Results element. + + + + + + + Roughness of the outside surface + + + + + + + + Parameters required by RTS load calculation method, as described in pages 29.25 and following of the 2001 ASHRAE Handbook, Fundamentals volume. Ignore this element and all elements under it if you are not planning to use that method. + + + + + + + + Specifies which Conduction Time Series to use for the roof. See Table 21, page 29.30, 2001 ASHRAE Handbook, Fundamentals volume. Only used if the construction is a roof and you are using the RTS calculation method. + + + + + Specifies which Conduction Time Series to use for the wall. See Table 20, page 29.28, 2001 ASHRAE Handbook, Fundamentals volume. Only used if the construction is a wall and you are using the RTS calculation method. + + + + + + + Resistance of material + + + + + + + + + + + + + The ShadeControl element is a bit complex, as shading control is handled differently in different simulation engines. Each child of ShadeControl represents a criteria to help determine if the shades will be open or closed. The resulting shade action should be a union of these. Example: You have included a ShadeSchedule, which is a 1 on weekdays and a 0 on weekends, and a SolarOnOpening. The shade will be drawn when the solar radiation on this opening is greater than SolarOnOpening and it is a weekday. + + + + + + + + + + + + + Please specify the program that added this element. + + + + + + + Use this element to define schedules for a shade. + + + + + + + + List of year schedules that make up an entire calendar year. + + + + + + + + + + + + Please specify the program that added this element. + + + + + + + Value for one block of time. Divides a day evenly into number of ScheduleValue elements defined in DaySchedule. Example: If 12 ScheduleValue elements are defined, each will represent two hours + + + + + Distance from outside surface of window to outside surface of wall + + + + + + + + + + + + Shading Coefficient: The ratio of total solar transmittance for the specified glazing system to the total solar transmittance for the standard reference glazing (1/8" clear). + + + + + + + + + + + + All data are global, with the assumption that positive Z is up, and if CADModelAzimuth is undefined or zero, positive X is East and positive Y is North. If CADModelAzimuth is defined it is the angle of positive Y to North, positive X is the vectorial product of Y and Z. If geometry is to be precise, use Longitude Latitude, and Elevation in the Location element to define the origin. Otherwise the origin is an arbitrary point. ShellGeometry is used to define a union of closed shells, where there is no intersection of any two of the given shells. + + + + + + + + + + + + + + + + + + + + + + + When element is a child of WindowType: The center of glass solar heat gain coefficient. When element is a child of Opening: The overall solar heat gain coefficient for the window assembly. + + + + + + + + + + + + + Amount of solar radiation striking the opening before a shade is closed. + + + + + + + + + + + + A space represents a volume enclosed by surfaces. + + + + + + + + + + + + + + + + + + + Planar polygon that represents the perimeter of space and whose area is equal to the floor area of the space. + + + + + Planar polygons that represent the interior surfaces bounding the space and whose volume is equal to the volume of the space. + + + + + + + + + + + + + + + + spaceType represents how a space is used. + + IfcPolyLoop, an IESNA and ASHRAE project for determining lighting power density for individual spaces. + + + + + + ID for the schedule of transmittance of a shading surface + + + + + ID of the schedule for lights contained in this space + + + + + ID for schedule of equipment use + + + + + ID for schedule of people in this space + + + + + + ID for BuildingStorey this space is on. + + + + + Global Unique ID from Industry Foundation Class (IFC) file. + + + + + + + This element establishes the logical relation of a given part of the space ShellGeometry such that its PlanarGeometry is part of an interior surface bounding the space. + + + + + + + + Global Unique ID from Industry Foundation Class (IFC) + file. + + + + + If this attribute is set to true, the boundary is important in heat flow calculation. + + + + + Connects the space boundary to a surface representing a building element (or representing the open air). + + + + + If surface referenced by SpaceBoundary is adjacent to two spaces, then this references the corresponding SpaceBoundary of the opposite space. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + First AdjacentSpaceId entered will determine how the referenced construction layers are ordered with the first construction layer being in contact with the outside or 2nd space listed and the last layer in contact with the first space listed. + + + + + + + + + + + + Identifier pointing to a construction + + + + + ID for the schedule of transmittance of a shading surface + + + + + This attribute specifies whether or not direct beam radiation from the sun will ever hit this surface. Only relevant to exterior surface types. + + + + + Global Unique ID from Industry Foundation Class (IFC) file. + + + + + + + Temperature + + + + + + + + + + + + + + + + + + Please specify the program that added this element. + + + + + + + + + Use this element to describe how the temperature is controlled. The temperatures specified in this element should be measured just upstream of the most critical piece of equipment (air handlers for a chilled water and hot water loops the chiller for the cooling water loop). + + + + + + + + + + + + + + + + + + + + + The number of degrees from up that the outside of the surface is tilted in relation to the bottom-left corner. + + + + + + + + + + + Time or period that results represent. Example: if timeType = Month and TimeIncrement = 1 the Value would be for the month of January or if timeType = Hour and TimeIncrement = 4 the 81st the Value would be for January 14 at noon. + + + + + + + + + + + + Transmittance of shading surface + + + + + + + + + + + + + Public transportation + + + + + + + + + + + + ID for the schedule of transmittance of a shading surface + + + + + Please specify the program that added this element. + + + + + + + User/project defined Code for Space or Zone. + + + + + + We have left the UtilityRate element open to allow for use with billing schemas. + + + + + + Overall conductance + + + + + + + + + + + + Contains the actual numerical result value. If series result type each Value element contains the one value and is in sequential order for the series. + + + + + Plants, trees, etc. on a campus + + + + + + + + + + + + + + + + Refers to a building-level surface. + + + + + Please specify the program that added this element. + + + + + + + + + + + + + + + + + Viscosity as a function of temperature + + + + + + + + + + + + Specifies the volume of the space. This value should be equal to the volume enclosed by the actual physical boundaries of the space, as defined by the volumetric model's interior surfaces bounding that space. + + + + + + + + + + + + Waste water heat recovery efficiency + + + + + + + + ID pointing to an air loop + + + + + ID pointing to a hydronic loop + + + + + + + + + This includes blowdown (draining a cooling tower to clean), drift (water loss from water sprayed), and evaporation in cooling towers. + + + + + + + + + + + + + + + + + + + + + Amount of water used for water using equipment per cycle of operation. + + + + + + + + + + + + The amount of heat from this equipment rejected to this space. For condensors exterior to building, this value will be 0. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Please specify the program that added this element. + + + + + + + + Set of day schedules all assigned to a unique particular period of the week using the day type attribute. Do not schedule conflicting day types to the same week schedule. + + + + + + + + + + + + + + + + + + + + + + + + + + + + Wildfire threat design atomospheric pressure. + + + + + + + + + + + + Wildfire threat design relative humidity. + + + + + + + + + + + + Wildfire threat design dry bulb temperature. + + + + + + + + + + + + Wildfire threat design wind direction + + + + + + + + + + + + Wildfire threat design wind speed. + + + + + + + + + + + + Wind speed for wind turbine. + + + + + + + + + + + + + + + + + + + + + + One WindowType should be created for each type of window. Create a Blind, Frame, and Cost for each OpeningType, and then add as many Glaze and Gaps as exist in the window. Place these Glaze and Gap elements in order from outside to inside. For instance, a two pane window will have Glaze Gap Glaze, where the first Glaze represents the outside surface. + + + + + + + + + + + + + + + + + + + This element is for purposes of modeling BIPV (building integrated photovoltaics). + + + + + + + Use this attribute to reference objects in the DOE2 library + + + + + Please specify the program that added this element. + + + + + + + + + + + + + + + + + + + + + + + + + + + Year of simulation to use + + + + + + + + + + + + Set of week schedules all assigned for a particular time period during the year defined by the begin and end date elements. These must not span more than one calendar year. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ID of heating schedule + + + + + Design temperature for cooling + + + + + Outside air schedule ID + + + + + Air changes schedule ID + + + + + ID of the fan schedule for this zone + + + + + Global Unique ID from Industry Foundation Class (IFC) file. + + + + + Please specify the program that added this element. + + + + + + + Minimum cooling load that triggers the shades to close + + + + + + + + + + diff --git a/XMLValidatorWeb/Images/TmpImage.gif b/XMLValidatorWeb/Images/TmpImage.gif new file mode 100644 index 0000000000000000000000000000000000000000..0ca7ada960568fff04400cda966fbdcb106abfa2 GIT binary patch literal 6820 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 literal 0 HcmV?d00001 diff --git a/XMLValidatorWeb/Images/header01.jpg b/XMLValidatorWeb/Images/header01.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2e379caf0a4ff0c98afa9f3d347c2d08d68c4dd1 GIT binary patch literal 51337 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�ABC3aAhq5Cn@U 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 + + + + + + + + + + + + + +
+ +
+ + +
+ + + + + + + + + diff --git a/XMLValidatorWeb/MasterPage.Master.cs b/XMLValidatorWeb/MasterPage.Master.cs new file mode 100644 index 0000000..795a292 --- /dev/null +++ b/XMLValidatorWeb/MasterPage.Master.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; + +namespace XMLValidatorWeb +{ + public partial class MasterPage : System.Web.UI.MasterPage + { + protected void Page_Load(object sender, EventArgs e) + { + + } + } +} \ No newline at end of file diff --git a/XMLValidatorWeb/MasterPage.Master.designer.cs b/XMLValidatorWeb/MasterPage.Master.designer.cs new file mode 100644 index 0000000..2dc02df --- /dev/null +++ b/XMLValidatorWeb/MasterPage.Master.designer.cs @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace XMLValidatorWeb { + + + public partial class MasterPage { + + /// + /// head control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.ContentPlaceHolder head; + + /// + /// form1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.HtmlControls.HtmlForm form1; + + /// + /// Img1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.HtmlControls.HtmlImage Img1; + + /// + /// Img2 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.HtmlControls.HtmlImage Img2; + + /// + /// ContentPlaceHolder1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.ContentPlaceHolder ContentPlaceHolder1; + } +} diff --git a/XMLValidatorWeb/Pages/PrintFriendlyTablePage.aspx b/XMLValidatorWeb/Pages/PrintFriendlyTablePage.aspx new file mode 100644 index 0000000..5575291 --- /dev/null +++ b/XMLValidatorWeb/Pages/PrintFriendlyTablePage.aspx @@ -0,0 +1,18 @@ +<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="PrintFriendlyTablePage.aspx.cs" Inherits="XMLValidatorWeb.PrintFriendlyTablePage" %> + + + + + + + + +
+
+ + + +
+
+ + diff --git a/XMLValidatorWeb/Pages/PrintFriendlyTablePage.aspx.cs b/XMLValidatorWeb/Pages/PrintFriendlyTablePage.aspx.cs new file mode 100644 index 0000000..8b4c5ea --- /dev/null +++ b/XMLValidatorWeb/Pages/PrintFriendlyTablePage.aspx.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; + + + +namespace XMLValidatorWeb +{ + public partial class PrintFriendlyTablePage : System.Web.UI.Page + { + protected void Page_Load(object sender, EventArgs e) + { + if (PrintFriendlyTablePageLabel != null) + { + if (Session["table"] == null) + Response.Redirect(@"~/"); + + PrintFriendlyTablePageLabel.Text = Session["table"].ToString(); + } + + } + } +} \ No newline at end of file diff --git a/XMLValidatorWeb/Pages/PrintFriendlyTablePage.aspx.designer.cs b/XMLValidatorWeb/Pages/PrintFriendlyTablePage.aspx.designer.cs new file mode 100644 index 0000000..38c2c7e --- /dev/null +++ b/XMLValidatorWeb/Pages/PrintFriendlyTablePage.aspx.designer.cs @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace XMLValidatorWeb { + + + public partial class PrintFriendlyTablePage { + + /// + /// form1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.HtmlControls.HtmlForm form1; + + /// + /// PrintFriendlyTablePageLabel control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label PrintFriendlyTablePageLabel; + } +} diff --git a/XMLValidatorWeb/Pages/TestDetailPage.aspx b/XMLValidatorWeb/Pages/TestDetailPage.aspx new file mode 100644 index 0000000..9b138fa --- /dev/null +++ b/XMLValidatorWeb/Pages/TestDetailPage.aspx @@ -0,0 +1,18 @@ +<%@ Page Language="C#" MasterPageFile="~/MasterPage.Master" AutoEventWireup="true" CodeBehind="TestDetailPage.aspx.cs" Inherits="XMLValidatorWeb.TestDetail" %> + + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
diff --git a/XMLValidatorWeb/Pages/TestDetailPage.aspx.cs b/XMLValidatorWeb/Pages/TestDetailPage.aspx.cs new file mode 100644 index 0000000..1deddbc --- /dev/null +++ b/XMLValidatorWeb/Pages/TestDetailPage.aspx.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.UI; +using System.Web.UI.WebControls; +using DOEgbXML; + +namespace XMLValidatorWeb +{ + public partial class TestDetail : System.Web.UI.Page + { + protected void Page_Load(object sender, EventArgs e) + { + if (TestDetailLabelOverView != null) + { + if (Request.QueryString["type"] != "Error") + { + List reportlist = new List(); + if (Session["reportList"] == null || Request.QueryString["type"] == null) + Response.Redirect(@"~/"); + + reportlist = (List)Session["reportList"]; + + //looking for the right report from the list + int testType = 0; + int subType = -1; + + if (Request.QueryString["type"] != null) + { + try + { + testType = (int)Convert.ToInt32(Request.QueryString["type"]); + } + catch + { + return; + } + } + + if (Request.QueryString["subtype"] != null) + { + try + { + subType = (int)Convert.ToInt32(Request.QueryString["subtype"]); + } + catch + { + return; + } + } + + DOEgbXMLReportingObj rightReport = new DOEgbXMLReportingObj(); + foreach (DOEgbXMLReportingObj report in reportlist) + if (report.testType == (TestType)testType) + if (report.subTestIndex == -1 || report.subTestIndex == subType) + rightReport = report; + + + //title + string title = rightReport.testType.ToString(); + title = title.Replace("_", " "); + if (subType != -1) + title += " " + subType; + TestDetailLabelName.Text += "

" + title + "

"; + + //description + // TestDetailLabelOverView.Text += "

" + "Description.................................................................." + "

"; + TestDetailLabelOverView.Text += "

" + "Test Summary:" + "

" + + "

" + rightReport.testSummary + "

"; + var passTest = rightReport.TestPassedDict.Values; + bool individualTestBool = true; + foreach (bool testResult in passTest) + { + if (testResult == false) + { + individualTestBool = false; + break; + } + } + + string output = "

" + "Test Result:" + "

"; + if (rightReport.passOrFail && individualTestBool) + output += "
" + rightReport.longMsg + "
"; + else + output += "
" + rightReport.longMsg + "
"; + if (rightReport.MessageList.Count > 0) + for (int i = 0; i < rightReport.MessageList.Count; i++) + { + output += "
" + rightReport.MessageList[i] + "
"; + } + + TestDetailLabelResults.Text = output; + } + else + { + TestDetailImage.Visible = false; + TestDetailLabelResults.Text = Session["table"].ToString(); + } + } + } + } +} \ No newline at end of file diff --git a/XMLValidatorWeb/Pages/TestDetailPage.aspx.designer.cs b/XMLValidatorWeb/Pages/TestDetailPage.aspx.designer.cs new file mode 100644 index 0000000..9a86ba2 --- /dev/null +++ b/XMLValidatorWeb/Pages/TestDetailPage.aspx.designer.cs @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace XMLValidatorWeb { + + + public partial class TestDetail { + + /// + /// TestDetailLabelName control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label TestDetailLabelName; + + /// + /// TestDetailLabelOverView control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label TestDetailLabelOverView; + + /// + /// TestDetailImage control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Image TestDetailImage; + + /// + /// TestDetailLabelResults control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label TestDetailLabelResults; + } +} diff --git a/XMLValidatorWeb/Pages/TestPage.aspx b/XMLValidatorWeb/Pages/TestPage.aspx new file mode 100644 index 0000000..fbd353f --- /dev/null +++ b/XMLValidatorWeb/Pages/TestPage.aspx @@ -0,0 +1,52 @@ +<%@ Page Title="" Language="C#" MasterPageFile="~/MasterPage.Master" AutoEventWireup="true" + CodeBehind="TestPage.aspx.cs" Inherits="XMLValidatorWeb.Pages.TestPage" %> + + + + + + + +
+

+ gbXML Validator +

+
+
+ Select Which Test You Want To Run: + + +
+
+ +
+
+
+ Select Your XML File Here: + + + +
+
+
+ +
+
+ + + +
+ +
+ + + +
diff --git a/XMLValidatorWeb/Pages/TestPage.aspx.cs b/XMLValidatorWeb/Pages/TestPage.aspx.cs new file mode 100644 index 0000000..93baa69 --- /dev/null +++ b/XMLValidatorWeb/Pages/TestPage.aspx.cs @@ -0,0 +1,234 @@ +using System; +using System.Collections.Generic; +using System.Web.UI; +using System.Web.UI.WebControls; +using DOEgbXML; +using System.Xml; +using System.IO; + +namespace XMLValidatorWeb.Pages +{ + public partial class TestPage : System.Web.UI.Page + { + protected void Page_Load(object sender, EventArgs e) + { + //create testlist for creating dropdown list iteams dynamically + DOEgbXMLTestDetail testList = new DOEgbXMLTestDetail(); + testList.InitializeTestResultStrings(); + + //create dropdownlist items base on the tests + if (DropDownList1 != null) + { + string selectedValue = DropDownList1.SelectedValue; + + //clear all iteam + DropDownList1.Items.Clear(); + + foreach (DOEgbXMLTestDetail detail in testList.TestDetailList) + //if test is the one selected before select it + if (detail.testName == selectedValue) + { + DropDownList1.Items.Add(new ListItem(detail.testName, detail.testName, true)); + DropDownList1.SelectedValue = selectedValue; + } + else + DropDownList1.Items.Add(new ListItem(detail.testName, detail.testName)); + } + + if (TestSummuryLabel != null) + { + //show the test summary of the selected test + foreach (DOEgbXMLTestDetail detail in testList.TestDetailList) + if (detail.testName == DropDownList1.SelectedValue) + { + TestSummuryLabel.Text = detail.testSummary; + break; + } + } + } + + protected void upLoadButton_Click1(object sender, EventArgs e) + { + if (FileUpload1.HasFile) + { + if (FileUpload1.PostedFile.ContentType == "text/xml") + { + //if there is a file + //valadate it by pass in input stream as xmlreader + Stream responseStream = FileUpload1.PostedFile.InputStream; + XmlReader xmlreader = XmlReader.Create(responseStream); + + + //validating xml + DOEgbXMLValidator val = new DOEgbXMLValidator(); + //if it is not valid + if (!val.IsValidXmlEx(xmlreader) || val.nErrors > 0 || val.nWarnings > 0) + { + if (PrintFriendlyButton != null) + PrintFriendlyButton.Visible = false; + + if (DownloadLogButton != null) + DownloadLogButton.Visible = false; + + + //setup errorlog + string errorLog = ""; + string errorDes = ""; + if (val.nErrors > 0 || val.nWarnings > 0) + { + errorLog += "

" + "Find " + val.nErrors + " Errors and " + val.nWarnings + " Warnings

" + val.Errors + "

"; + errorDes = "Find "; + if (val.nErrors > 0) + { + errorDes += val.nErrors; + if (val.nWarnings > 0) + errorDes += " Errors and"; + else + errorDes += " Errors"; + + } + if (val.nWarnings > 0) + errorDes += val.nWarnings + " Warnings"; + } + else + { + errorLog += "

" + "Your XML File is severely deficient structurally. It may be missing element tags or is not valid XML. The test has failed.

" + val.BigError + "
" + "

"; + errorDes = "Your XML File is severely deficient structurally."; + } + // Session.Add("table", errorLog); + Session["table"] = errorLog; + + TestResultLabel.Text = ""; + + ResultSummaryLabel.Text = "

Result Summary

"; + ResultSummaryLabel.Text += "
"; + ResultSummaryLabel.Text += "" + + "" + + "" + + "" + + "" + + ""; + ResultSummaryLabel.Text += "
" + "gbXML schema Test" + "" + errorDes + "" + "Fail" + "" + "" + "More Detail" + "" + "

"; + } + //if it is valid + else if (val.nErrors == 0 && val.nWarnings == 0) + { + //run test + XMLParser parser = new XMLParser(); + + responseStream.Position = 0; + XmlReader xmlreader2 = XmlReader.Create(responseStream); + //start test + parser.StartTest(xmlreader2, DropDownList1.SelectedValue, Page.User.Identity.Name); + + //show summary table + ResultSummaryLabel.Text = parser.summaryTable; + + //show test section table + TestResultLabel.Text = parser.table; + + //store reportlist in session + Session["reportList"] = parser.ReportList; + + + LogLabel.Text = parser.log; + TableLabel.Text = parser.table; + //remove extra tag + TableLabel.Text = TableLabel.Text.Replace("", ""); + TableLabel.Text = TableLabel.Text.Replace("", ""); + TableLabel.Text = TableLabel.Text.Replace("", "
"); + DownloadLogButton.Visible = true; + PrintFriendlyButton.Visible = true; + } + //this should never happens + else + { + ResultSummaryLabel.Text = "?????????something is very wrong"; + TestResultLabel.Text = ""; + } + + } + //if the file type is not xml + else + { + if (PrintFriendlyButton != null) + PrintFriendlyButton.Visible = false; + + if (DownloadLogButton != null) + DownloadLogButton.Visible = false; + + ResultSummaryLabel.Text = ""; + TestResultLabel.Text = ""; + + ResultSummaryLabel.Text = "

Result Summary

"; + ResultSummaryLabel.Text += "
"; + ResultSummaryLabel.Text += "" + + "" + + "" + + "" + + + ""; + ResultSummaryLabel.Text += "
" + "gbXML schema Test" + "" + "You have not specified a right type of file." + "" + "Fail" + "

"; + } + } + //if there is no file + else + { + if (PrintFriendlyButton != null) + PrintFriendlyButton.Visible = false; + + if (DownloadLogButton != null) + DownloadLogButton.Visible = false; + + + ResultSummaryLabel.Text = ""; + TestResultLabel.Text = ""; + + ResultSummaryLabel.Text = "

Result Summary

"; + ResultSummaryLabel.Text += ""; + ResultSummaryLabel.Text += "" + + "" + + "" + + "" + + ""; + ResultSummaryLabel.Text += "
" + "gbXML schema Test" + "" + "You have not specified a file." + "" + "Fail" + "

"; + + } + } + + + + protected void DownloadLogButton_Click(object sender, EventArgs e) + { + Response.Clear(); + Response.ClearContent(); + Response.ClearHeaders(); + Response.AddHeader("content-disposition", "attachment;filename=Log.txt"); + Response.ContentType = "text/plain"; + Response.Write(LogLabel.Text); + Response.End(); + } + + protected void PrintFriendlyButton_Click(object sender, EventArgs e) + { + Session.Add("table", TableLabel.Text); + + string url = "PrintFriendlyTablePage.aspx"; + + ClientScript.RegisterStartupScript(this.GetType(), "OpenWindow", ""); + } + + protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e) + { + //if change the selected index clear all labels + ResultSummaryLabel.Text = ""; + TestResultLabel.Text = ""; + LogLabel.Text = ""; + TableLabel.Text = ""; + DownloadLogButton.Visible = false; + PrintFriendlyButton.Visible = false; + } + + + } +} \ No newline at end of file diff --git a/XMLValidatorWeb/Pages/TestPage.aspx.designer.cs b/XMLValidatorWeb/Pages/TestPage.aspx.designer.cs new file mode 100644 index 0000000..9c38366 --- /dev/null +++ b/XMLValidatorWeb/Pages/TestPage.aspx.designer.cs @@ -0,0 +1,105 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace XMLValidatorWeb.Pages { + + + public partial class TestPage { + + /// + /// DropDownList1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.DropDownList DropDownList1; + + /// + /// TestSummuryLabel control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label TestSummuryLabel; + + /// + /// FileUpload1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.FileUpload FileUpload1; + + /// + /// DownloadLogButton control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Button DownloadLogButton; + + /// + /// PrintFriendlyButton control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Button PrintFriendlyButton; + + /// + /// upLoadButton control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Button upLoadButton; + + /// + /// ResultSummaryLabel control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label ResultSummaryLabel; + + /// + /// TestResultLabel control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label TestResultLabel; + + /// + /// LogLabel control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label LogLabel; + + /// + /// TableLabel control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Label TableLabel; + } +} diff --git a/XMLValidatorWeb/Properties/AssemblyInfo.cs b/XMLValidatorWeb/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..5e3cdcc --- /dev/null +++ b/XMLValidatorWeb/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("XMLValidatorWeb")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("XMLValidatorWeb")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("64367132-ef23-4db1-832c-5a2800ab3d85")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/XMLValidatorWeb/Scripts/jquery-1.4.1-vsdoc.js b/XMLValidatorWeb/Scripts/jquery-1.4.1-vsdoc.js new file mode 100644 index 0000000..681241d --- /dev/null +++ b/XMLValidatorWeb/Scripts/jquery-1.4.1-vsdoc.js @@ -0,0 +1,8061 @@ +/* + * This file has been commented to support Visual Studio Intellisense. + * You should not use this file at runtime inside the browser--it is only + * intended to be used only for design-time IntelliSense. Please use the + * standard jQuery library for all production use. + * + * Comment version: 1.4.1a + */ + +/*! + * jQuery JavaScript Library v1.4.1 + * http://jquery.com/ + * + * Distributed in whole under the terms of the MIT + * + * Copyright 2010, John Resig + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2010, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Mon Jan 25 19:43:33 2010 -0500 + */ + +(function( window, undefined ) { + +// Define a local copy of jQuery +var jQuery = function( selector, context ) { + /// + /// 1: $(expression, context) - This function accepts a string containing a CSS selector which is then used to match a set of elements. + /// 2: $(html) - Create DOM elements on-the-fly from the provided String of raw HTML. + /// 3: $(elements) - Wrap jQuery functionality around a single or multiple DOM Element(s). + /// 4: $(callback) - A shorthand for $(document).ready(). + /// 5: $() - As of jQuery 1.4, if you pass no arguments in to the jQuery() method, an empty jQuery set will be returned. + /// + /// + /// 1: expression - An expression to search with. + /// 2: html - A string of HTML to create on the fly. + /// 3: elements - DOM element(s) to be encapsulated by a jQuery object. + /// 4: callback - The function to execute when the DOM is ready. + /// + /// + /// 1: context - A DOM Element, Document or jQuery to use as context. + /// + /// + + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context ); + }, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // Use the correct document accordingly with window argument (sandbox) + document = window.document, + + // A central reference to the root jQuery(document) + rootjQuery, + + // A simple way to check for HTML strings or ID strings + // (both of which we optimize for) + quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/, + + // Is it a simple selector + isSimple = /^.[^:#\[\.,]*$/, + + // Check if a string has a non-whitespace character in it + rnotwhite = /\S/, + + // Used for trimming whitespace + rtrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, + + // Keep a UserAgent string for use with jQuery.browser + userAgent = navigator.userAgent, + + // For matching the engine and version of the browser + browserMatch, + + // Has the ready events already been bound? + readyBound = false, + + // The functions to execute on DOM ready + readyList = [], + + // The ready event handler + DOMContentLoaded, + + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwnProperty = Object.prototype.hasOwnProperty, + push = Array.prototype.push, + slice = Array.prototype.slice, + indexOf = Array.prototype.indexOf; + +jQuery.fn = jQuery.prototype = { + init: function( selector, context ) { + + var match, elem, ret, doc; + + // Handle $(""), $(null), or $(undefined) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + match = quickExpr.exec( selector ); + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + doc = (context ? context.ownerDocument || context : document); + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + ret = rsingleTag.exec( selector ); + + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); + + } else { + selector = [ doc.createElement( ret[1] ) ]; + } + + } else { + ret = buildFragment( [ match[1] ], [ doc ] ); + selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes; + } + + // HANDLE: $("#id") + } else { + elem = document.getElementById( match[2] ); + + if ( elem ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $("TAG") + } else if ( !context && /^\w+$/.test( selector ) ) { + this.selector = selector; + this.context = document; + selector = document.getElementsByTagName( selector ); + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return (context || rootjQuery).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return jQuery( context ).find( selector ); + } + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if (selector.selector !== undefined) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.isArray( selector ) ? + this.setArray( selector ) : + jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.4.1", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + /// + /// The number of elements currently matched. + /// Part of Core + /// + /// + + return this.length; + }, + + toArray: function() { + /// + /// Retrieve all the DOM elements contained in the jQuery set, as an array. + /// + /// + return slice.call( this, 0 ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + /// + /// Access a single matched element. num is used to access the + /// Nth element matched. + /// Part of Core + /// + /// + /// + /// Access the element in the Nth position. + /// + + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this.slice(num)[ 0 ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + /// + /// Set the jQuery object to an array of elements, while maintaining + /// the stack. + /// Part of Core + /// + /// + /// + /// An array of elements + /// + + // Build a new jQuery matched element set + var ret = jQuery( elems || null ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + (this.selector ? " " : "") + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // Return the newly-formed element set + return ret; + }, + + // Force the current matched set of elements to become + // the specified array of elements (destroying the stack in the process) + // You should use pushStack() in order to do this, but maintain the stack + setArray: function( elems ) { + /// + /// Set the jQuery object to an array of elements. This operation is + /// completely destructive - be sure to use .pushStack() if you wish to maintain + /// the jQuery stack. + /// Part of Core + /// + /// + /// + /// An array of elements + /// + + // Resetting the length to 0, then using the native Array push + // is a super-fast way to populate an object with array-like properties + this.length = 0; + push.apply( this, elems ); + + return this; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + /// + /// Execute a function within the context of every matched element. + /// This means that every time the passed-in function is executed + /// (which is once for every element matched) the 'this' keyword + /// points to the specific element. + /// Additionally, the function, when executed, is passed a single + /// argument representing the position of the element in the matched + /// set. + /// Part of Core + /// + /// + /// + /// A function to execute + /// + + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + /// + /// Binds a function to be executed whenever the DOM is ready to be traversed and manipulated. + /// + /// The function to be executed when the DOM is ready. + + // Attach the listeners + jQuery.bindReady(); + + // If the DOM is already ready + if ( jQuery.isReady ) { + // Execute the function immediately + fn.call( document, jQuery ); + + // Otherwise, remember the function for later + } else if ( readyList ) { + // Add the function to the wait list + readyList.push( fn ); + } + + return this; + }, + + eq: function( i ) { + /// + /// Reduce the set of matched elements to a single element. + /// The position of the element in the set of matched elements + /// starts at 0 and goes to length - 1. + /// Part of Core + /// + /// + /// + /// pos The index of the element that you wish to limit to. + /// + + return i === -1 ? + this.slice( i ) : + this.slice( i, +i + 1 ); + }, + + first: function() { + /// + /// Reduce the set of matched elements to the first in the set. + /// + /// + + return this.eq( 0 ); + }, + + last: function() { + /// + /// Reduce the set of matched elements to the final one in the set. + /// + /// + + return this.eq( -1 ); + }, + + slice: function() { + /// + /// Selects a subset of the matched elements. Behaves exactly like the built-in Array slice method. + /// + /// Where to start the subset (0-based). + /// Where to end the subset (not including the end element itself). + /// If omitted, ends at the end of the selection + /// The sliced elements + + return this.pushStack( slice.apply( this, arguments ), + "slice", slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + /// + /// This member is internal. + /// + /// + /// + + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + /// + /// End the most recent 'destructive' operation, reverting the list of matched elements + /// back to its previous state. After an end operation, the list of matched elements will + /// revert to the last state of matched elements. + /// If there was no destructive operation before, an empty set is returned. + /// Part of DOM/Traversing + /// + /// + + return this.prevObject || jQuery(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + /// + /// Extend one object with one or more others, returning the original, + /// modified, object. This is a great utility for simple inheritance. + /// jQuery.extend(settings, options); + /// var settings = jQuery.extend({}, defaults, options); + /// Part of JavaScript + /// + /// + /// The object to extend + /// + /// + /// The object that will be merged into the first. + /// + /// + /// (optional) More objects to merge into the first + /// + /// + + // copy reference to target object + var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging object literal values or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || jQuery.isArray(copy) ) ) { + var clone = src && ( jQuery.isPlainObject(src) || jQuery.isArray(src) ) ? src + : jQuery.isArray(copy) ? [] : {}; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + /// + /// Run this function to give control of the $ variable back + /// to whichever library first implemented it. This helps to make + /// sure that jQuery doesn't conflict with the $ object + /// of other libraries. + /// By using this function, you will only be able to access jQuery + /// using the 'jQuery' variable. For example, where you used to do + /// $("div p"), you now must do jQuery("div p"). + /// Part of Core + /// + /// + + window.$ = _$; + + if ( deep ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // Handle when the DOM is ready + ready: function() { + /// + /// This method is internal. + /// + /// + + // Make sure that the DOM is not already loaded + if ( !jQuery.isReady ) { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 13 ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If there are functions bound, to execute + if ( readyList ) { + // Execute all of them + var fn, i = 0; + while ( (fn = readyList[ i++ ]) ) { + fn.call( document, jQuery ); + } + + // Reset the list of functions + readyList = null; + } + + // Trigger any bound ready events + if ( jQuery.fn.triggerHandler ) { + jQuery( document ).triggerHandler( "ready" ); + } + } + }, + + bindReady: function() { + if ( readyBound ) { + return; + } + + readyBound = true; + + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + return jQuery.ready(); + } + + // Mozilla, Opera and webkit nightlies currently support this event + if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else if ( document.attachEvent ) { + // ensure firing before onload, + // maybe late but safe also for iframes + document.attachEvent("onreadystatechange", DOMContentLoaded); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var toplevel = false; + + try { + toplevel = window.frameElement == null; + } catch(e) {} + + if ( document.documentElement.doScroll && toplevel ) { + doScrollCheck(); + } + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + /// + /// Determines if the parameter passed is a function. + /// + /// The object to check + /// True if the parameter is a function; otherwise false. + + return toString.call(obj) === "[object Function]"; + }, + + isArray: function( obj ) { + /// + /// Determine if the parameter passed is an array. + /// + /// Object to test whether or not it is an array. + /// True if the parameter is a function; otherwise false. + + return toString.call(obj) === "[object Array]"; + }, + + isPlainObject: function( obj ) { + /// + /// Check to see if an object is a plain object (created using "{}" or "new Object"). + /// + /// + /// The object that will be checked to see if it's a plain object. + /// + /// + + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) { + return false; + } + + // Not own constructor property must be Object + if ( obj.constructor + && !hasOwnProperty.call(obj, "constructor") + && !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || hasOwnProperty.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + /// + /// Check to see if an object is empty (contains no properties). + /// + /// + /// The object that will be checked to see if it's empty. + /// + /// + + for ( var name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw msg; + }, + + parseJSON: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( /^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@") + .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]") + .replace(/(?:^|:|,)(?:\s*\[)+/g, "")) ) { + + // Try to use the native JSON parser first + return window.JSON && window.JSON.parse ? + window.JSON.parse( data ) : + (new Function("return " + data))(); + + } else { + jQuery.error( "Invalid JSON: " + data ); + } + }, + + noop: function() { + /// + /// An empty function. + /// + /// + }, + + // Evalulates a script in a global context + globalEval: function( data ) { + /// + /// Internally evaluates a script in a global context. + /// + /// + + if ( data && rnotwhite.test(data) ) { + // Inspired by code by Andrea Giammarchi + // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html + var head = document.getElementsByTagName("head")[0] || document.documentElement, + script = document.createElement("script"); + + script.type = "text/javascript"; + + if ( jQuery.support.scriptEval ) { + script.appendChild( document.createTextNode( data ) ); + } else { + script.text = data; + } + + // Use insertBefore instead of appendChild to circumvent an IE6 bug. + // This arises when a base node is used (#2709). + head.insertBefore( script, head.firstChild ); + head.removeChild( script ); + } + }, + + nodeName: function( elem, name ) { + /// + /// Checks whether the specified element has the specified DOM node name. + /// + /// The element to examine + /// The node name to check + /// True if the specified node name matches the node's DOM node name; otherwise false + + return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + /// + /// A generic iterator function, which can be used to seemlessly + /// iterate over both objects and arrays. This function is not the same + /// as $().each() - which is used to iterate, exclusively, over a jQuery + /// object. This function can be used to iterate over anything. + /// The callback has two arguments:the key (objects) or index (arrays) as first + /// the first, and the value as the second. + /// Part of JavaScript + /// + /// + /// The object, or array, to iterate over. + /// + /// + /// The function that will be executed on every object. + /// + /// + + var name, i = 0, + length = object.length, + isObj = length === undefined || jQuery.isFunction(object); + + if ( args ) { + if ( isObj ) { + for ( name in object ) { + if ( callback.apply( object[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( object[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in object ) { + if ( callback.call( object[ name ], name, object[ name ] ) === false ) { + break; + } + } + } else { + for ( var value = object[0]; + i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {} + } + } + + return object; + }, + + trim: function( text ) { + /// + /// Remove the whitespace from the beginning and end of a string. + /// Part of JavaScript + /// + /// + /// + /// The string to trim. + /// + + return (text || "").replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( array, results ) { + /// + /// Turns anything into a true array. This is an internal method. + /// + /// Anything to turn into an actual Array + /// + /// + + var ret = results || []; + + if ( array != null ) { + // The window, strings (and functions) also have 'length' + // The extra typeof function check is to prevent crashes + // in Safari 2 (See: #3039) + if ( array.length == null || typeof array === "string" || jQuery.isFunction(array) || (typeof array !== "function" && array.setInterval) ) { + push.call( ret, array ); + } else { + jQuery.merge( ret, array ); + } + } + + return ret; + }, + + inArray: function( elem, array ) { + if ( array.indexOf ) { + return array.indexOf( elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; + }, + + merge: function( first, second ) { + /// + /// Merge two arrays together, removing all duplicates. + /// The new array is: All the results from the first array, followed + /// by the unique results from the second array. + /// Part of JavaScript + /// + /// + /// + /// The first array to merge. + /// + /// + /// The second array to merge. + /// + + var i = first.length, j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + /// + /// Filter items out of an array, by using a filter function. + /// The specified function will be passed two arguments: The + /// current array item and the index of the item in the array. The + /// function must return 'true' to keep the item in the array, + /// false to remove it. + /// }); + /// Part of JavaScript + /// + /// + /// + /// array The Array to find items in. + /// + /// + /// The function to process each item against. + /// + /// + /// Invert the selection - select the opposite of the function. + /// + + var ret = []; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) { + if ( !inv !== !callback( elems[ i ], i ) ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + /// + /// Translate all items in an array to another array of items. + /// The translation function that is provided to this method is + /// called for each item in the array and is passed one argument: + /// The item to be translated. + /// The function can then return the translated value, 'null' + /// (to remove the item), or an array of values - which will + /// be flattened into the full array. + /// Part of JavaScript + /// + /// + /// + /// array The Array to translate. + /// + /// + /// The function to process each item against. + /// + + var ret = [], value; + + // Go through the array, translating each of the items to their + // new value (or values). + for ( var i = 0, length = elems.length; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + proxy: function( fn, proxy, thisObject ) { + /// + /// Takes a function and returns a new one that will always have a particular scope. + /// + /// + /// The function whose scope will be changed. + /// + /// + /// The object to which the scope of the function should be set. + /// + /// + + if ( arguments.length === 2 ) { + if ( typeof proxy === "string" ) { + thisObject = fn; + fn = thisObject[ proxy ]; + proxy = undefined; + + } else if ( proxy && !jQuery.isFunction( proxy ) ) { + thisObject = proxy; + proxy = undefined; + } + } + + if ( !proxy && fn ) { + proxy = function() { + return fn.apply( thisObject || this, arguments ); + }; + } + + // Set the guid of unique handler to the same of original handler, so it can be removed + if ( fn ) { + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; + } + + // So proxy can be declared as an argument + return proxy; + }, + + // Use of jQuery.browser is frowned upon. + // More details: http://docs.jquery.com/Utilities/jQuery.browser + uaMatch: function( ua ) { + ua = ua.toLowerCase(); + + var match = /(webkit)[ \/]([\w.]+)/.exec( ua ) || + /(opera)(?:.*version)?[ \/]([\w.]+)/.exec( ua ) || + /(msie) ([\w.]+)/.exec( ua ) || + !/compatible/.test( ua ) && /(mozilla)(?:.*? rv:([\w.]+))?/.exec( ua ) || + []; + + return { browser: match[1] || "", version: match[2] || "0" }; + }, + + browser: {} +}); + +browserMatch = jQuery.uaMatch( userAgent ); +if ( browserMatch.browser ) { + jQuery.browser[ browserMatch.browser ] = true; + jQuery.browser.version = browserMatch.version; +} + +// Deprecated, use jQuery.browser.webkit instead +if ( jQuery.browser.webkit ) { + jQuery.browser.safari = true; +} + +if ( indexOf ) { + jQuery.inArray = function( elem, array ) { + /// + /// Determines the index of the first parameter in the array. + /// + /// The value to see if it exists in the array. + /// The array to look through for the value + /// The 0-based index of the item if it was found, otherwise -1. + + return indexOf.call( array, elem ); + }; +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); + +// Cleanup functions for the document ready method +if ( document.addEventListener ) { + DOMContentLoaded = function() { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + }; + +} else if ( document.attachEvent ) { + DOMContentLoaded = function() { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( document.readyState === "complete" ) { + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }; +} + +// The DOM ready check for Internet Explorer +function doScrollCheck() { + if ( jQuery.isReady ) { + return; + } + + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch( error ) { + setTimeout( doScrollCheck, 1 ); + return; + } + + // and execute any waiting functions + jQuery.ready(); +} + +function evalScript( i, elem ) { + /// + /// This method is internal. + /// + /// + + if ( elem.src ) { + jQuery.ajax({ + url: elem.src, + async: false, + dataType: "script" + }); + } else { + jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); + } + + if ( elem.parentNode ) { + elem.parentNode.removeChild( elem ); + } +} + +// Mutifunctional method to get and set values to a collection +// The value/s can be optionally by executed if its a function +function access( elems, key, value, exec, fn, pass ) { + var length = elems.length; + + // Setting many attributes + if ( typeof key === "object" ) { + for ( var k in key ) { + access( elems, k, key[k], exec, fn, value ); + } + return elems; + } + + // Setting one attribute + if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = !pass && exec && jQuery.isFunction(value); + + for ( var i = 0; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + + return elems; + } + + // Getting an attribute + return length ? fn( elems[0], key ) : null; +} + +function now() { + /// + /// Gets the current date. + /// + /// The current date. + + return (new Date).getTime(); +} + +// [vsdoc] The following function has been modified for IntelliSense. +// [vsdoc] Stubbing support properties to "false" for IntelliSense compat. +(function() { + + jQuery.support = {}; + + // var root = document.documentElement, + // script = document.createElement("script"), + // div = document.createElement("div"), + // id = "script" + now(); + + // div.style.display = "none"; + // div.innerHTML = "
a"; + + // var all = div.getElementsByTagName("*"), + // a = div.getElementsByTagName("a")[0]; + + // // Can't get basic test support + // if ( !all || !all.length || !a ) { + // return; + // } + + jQuery.support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: false, + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: false, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: false, + + // Get the style information from getAttribute + // (IE uses .cssText insted) + style: false, + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: false, + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: false, + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: false, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: false, + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: false, + + // Will be defined later + checkClone: false, + scriptEval: false, + noCloneEvent: false, + boxModel: false + }; + + // script.type = "text/javascript"; + // try { + // script.appendChild( document.createTextNode( "window." + id + "=1;" ) ); + // } catch(e) {} + + // root.insertBefore( script, root.firstChild ); + + // // Make sure that the execution of code works by injecting a script + // // tag with appendChild/createTextNode + // // (IE doesn't support this, fails, and uses .text instead) + // if ( window[ id ] ) { + // jQuery.support.scriptEval = true; + // delete window[ id ]; + // } + + // root.removeChild( script ); + + // if ( div.attachEvent && div.fireEvent ) { + // div.attachEvent("onclick", function click() { + // // Cloning a node shouldn't copy over any + // // bound event handlers (IE does this) + // jQuery.support.noCloneEvent = false; + // div.detachEvent("onclick", click); + // }); + // div.cloneNode(true).fireEvent("onclick"); + // } + + // div = document.createElement("div"); + // div.innerHTML = ""; + + // var fragment = document.createDocumentFragment(); + // fragment.appendChild( div.firstChild ); + + // // WebKit doesn't clone checked state correctly in fragments + // jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked; + + // // Figure out if the W3C box model works as expected + // // document.body must exist before we can do this + // jQuery(function() { + // var div = document.createElement("div"); + // div.style.width = div.style.paddingLeft = "1px"; + + // document.body.appendChild( div ); + // jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2; + // document.body.removeChild( div ).style.display = 'none'; + // div = null; + // }); + + // // Technique from Juriy Zaytsev + // // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ + // var eventSupported = function( eventName ) { + // var el = document.createElement("div"); + // eventName = "on" + eventName; + + // var isSupported = (eventName in el); + // if ( !isSupported ) { + // el.setAttribute(eventName, "return;"); + // isSupported = typeof el[eventName] === "function"; + // } + // el = null; + + // return isSupported; + // }; + + jQuery.support.submitBubbles = false; + jQuery.support.changeBubbles = false; + + // // release memory in IE + // root = script = div = all = a = null; +})(); + +jQuery.props = { + "for": "htmlFor", + "class": "className", + readonly: "readOnly", + maxlength: "maxLength", + cellspacing: "cellSpacing", + rowspan: "rowSpan", + colspan: "colSpan", + tabindex: "tabIndex", + usemap: "useMap", + frameborder: "frameBorder" +}; +var expando = "jQuery" + now(), uuid = 0, windowData = {}; +var emptyObject = {}; + +jQuery.extend({ + cache: {}, + + expando:expando, + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + "object": true, + "applet": true + }, + + data: function( elem, name, data ) { + /// + /// Store arbitrary data associated with the specified element. + /// + /// + /// The DOM element to associate with the data. + /// + /// + /// A string naming the piece of data to set. + /// + /// + /// The new data value. + /// + /// + + if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) { + return; + } + + elem = elem == window ? + windowData : + elem; + + var id = elem[ expando ], cache = jQuery.cache, thisCache; + + // Handle the case where there's no name immediately + if ( !name && !id ) { + return null; + } + + // Compute a unique ID for the element + if ( !id ) { + id = ++uuid; + } + + // Avoid generating a new cache unless none exists and we + // want to manipulate it. + if ( typeof name === "object" ) { + elem[ expando ] = id; + thisCache = cache[ id ] = jQuery.extend(true, {}, name); + } else if ( cache[ id ] ) { + thisCache = cache[ id ]; + } else if ( typeof data === "undefined" ) { + thisCache = emptyObject; + } else { + thisCache = cache[ id ] = {}; + } + + // Prevent overriding the named cache with undefined values + if ( data !== undefined ) { + elem[ expando ] = id; + thisCache[ name ] = data; + } + + return typeof name === "string" ? thisCache[ name ] : thisCache; + }, + + removeData: function( elem, name ) { + if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) { + return; + } + + elem = elem == window ? + windowData : + elem; + + var id = elem[ expando ], cache = jQuery.cache, thisCache = cache[ id ]; + + // If we want to remove a specific section of the element's data + if ( name ) { + if ( thisCache ) { + // Remove the section of cache data + delete thisCache[ name ]; + + // If we've removed all the data, remove the element's cache + if ( jQuery.isEmptyObject(thisCache) ) { + jQuery.removeData( elem ); + } + } + + // Otherwise, we want to remove all of the element's data + } else { + // Clean up the element expando + try { + delete elem[ expando ]; + } catch( e ) { + // IE has trouble directly removing the expando + // but it's ok with using removeAttribute + if ( elem.removeAttribute ) { + elem.removeAttribute( expando ); + } + } + + // Completely remove the data cache + delete cache[ id ]; + } + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + /// + /// Store arbitrary data associated with the matched elements. + /// + /// + /// A string naming the piece of data to set. + /// + /// + /// The new data value. + /// + /// + + if ( typeof key === "undefined" && this.length ) { + return jQuery.data( this[0] ); + + } else if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + var parts = key.split("."); + parts[1] = parts[1] ? "." + parts[1] : ""; + + if ( value === undefined ) { + var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); + + if ( data === undefined && this.length ) { + data = jQuery.data( this[0], key ); + } + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + } else { + return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function() { + jQuery.data( this, key, value ); + }); + } + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); +jQuery.extend({ + queue: function( elem, type, data ) { + if ( !elem ) { + return; + } + + type = (type || "fx") + "queue"; + var q = jQuery.data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( !data ) { + return q || []; + } + + if ( !q || jQuery.isArray(data) ) { + q = jQuery.data( elem, type, jQuery.makeArray(data) ); + + } else { + q.push( data ); + } + + return q; + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), fn = queue.shift(); + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + } + + if ( fn ) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift("inprogress"); + } + + fn.call(elem, function() { + jQuery.dequeue(elem, type); + }); + } + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + /// + /// 1: queue() - Returns a reference to the first element's queue (which is an array of functions). + /// 2: queue(callback) - Adds a new function, to be executed, onto the end of the queue of all matched elements. + /// 3: queue(queue) - Replaces the queue of all matched element with this new queue (the array of functions). + /// + /// The function to add to the queue. + /// + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + } + + if ( data === undefined ) { + return jQuery.queue( this[0], type ); + } + return this.each(function( i, elem ) { + var queue = jQuery.queue( this, type, data ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + /// + /// Removes a queued function from the front of the queue and executes it. + /// + /// The type of queue to access. + /// + + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + /// + /// Set a timer to delay execution of subsequent items in the queue. + /// + /// + /// An integer indicating the number of milliseconds to delay execution of the next item in the queue. + /// + /// + /// A string containing the name of the queue. Defaults to fx, the standard effects queue. + /// + /// + + time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; + type = type || "fx"; + + return this.queue( type, function() { + var elem = this; + setTimeout(function() { + jQuery.dequeue( elem, type ); + }, time ); + }); + }, + + clearQueue: function( type ) { + /// + /// Remove from the queue all items that have not yet been run. + /// + /// + /// A string containing the name of the queue. Defaults to fx, the standard effects queue. + /// + /// + + return this.queue( type || "fx", [] ); + } +}); +var rclass = /[\n\t]/g, + rspace = /\s+/, + rreturn = /\r/g, + rspecialurl = /href|src|style/, + rtype = /(button|input)/i, + rfocusable = /(button|input|object|select|textarea)/i, + rclickable = /^(a|area)$/i, + rradiocheck = /radio|checkbox/; + +jQuery.fn.extend({ + attr: function( name, value ) { + /// + /// Set a single property to a computed value, on all matched elements. + /// Instead of a value, a function is provided, that computes the value. + /// Part of DOM/Attributes + /// + /// + /// + /// The name of the property to set. + /// + /// + /// A function returning the value to set. + /// + + return access( this, name, value, true, jQuery.attr ); + }, + + removeAttr: function( name, fn ) { + /// + /// Remove an attribute from each of the matched elements. + /// Part of DOM/Attributes + /// + /// + /// An attribute to remove. + /// + /// + + return this.each(function(){ + jQuery.attr( this, name, "" ); + if ( this.nodeType === 1 ) { + this.removeAttribute( name ); + } + }); + }, + + addClass: function( value ) { + /// + /// Adds the specified class(es) to each of the set of matched elements. + /// Part of DOM/Attributes + /// + /// + /// One or more class names to be added to the class attribute of each matched element. + /// + /// + + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + self.addClass( value.call(this, i, self.attr("class")) ); + }); + } + + if ( value && typeof value === "string" ) { + var classNames = (value || "").split( rspace ); + + for ( var i = 0, l = this.length; i < l; i++ ) { + var elem = this[i]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className ) { + elem.className = value; + + } else { + var className = " " + elem.className + " "; + for ( var c = 0, cl = classNames.length; c < cl; c++ ) { + if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) { + elem.className += " " + classNames[c]; + } + } + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + /// + /// Removes all or the specified class(es) from the set of matched elements. + /// Part of DOM/Attributes + /// + /// + /// (Optional) A class name to be removed from the class attribute of each matched element. + /// + /// + + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + self.removeClass( value.call(this, i, self.attr("class")) ); + }); + } + + if ( (value && typeof value === "string") || value === undefined ) { + var classNames = (value || "").split(rspace); + + for ( var i = 0, l = this.length; i < l; i++ ) { + var elem = this[i]; + + if ( elem.nodeType === 1 && elem.className ) { + if ( value ) { + var className = (" " + elem.className + " ").replace(rclass, " "); + for ( var c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[c] + " ", " "); + } + elem.className = className.substring(1, className.length - 1); + + } else { + elem.className = ""; + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + /// + /// Add or remove a class from each element in the set of matched elements, depending + /// on either the class's presence or the value of the switch argument. + /// + /// + /// A class name to be toggled for each element in the matched set. + /// + /// + /// A boolean value to determine whether the class should be added or removed. + /// + /// + + var type = typeof value, isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function(i) { + var self = jQuery(this); + self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, i = 0, self = jQuery(this), + state = stateVal, + classNames = value.split( rspace ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space seperated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery.data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery.data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + /// + /// Checks the current selection against a class and returns whether at least one selection has a given class. + /// + /// The class to check against + /// True if at least one element in the selection has the class, otherwise false. + + var className = " " + selector + " "; + for ( var i = 0, l = this.length; i < l; i++ ) { + if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + /// + /// Set the value of every matched element. + /// Part of DOM/Attributes + /// + /// + /// + /// A string of text or an array of strings to set as the value property of each + /// matched element. + /// + + if ( value === undefined ) { + var elem = this[0]; + + if ( elem ) { + if ( jQuery.nodeName( elem, "option" ) ) { + return (elem.attributes.value || {}).specified ? elem.value : elem.text; + } + + // We need to handle select boxes special + if ( jQuery.nodeName( elem, "select" ) ) { + var index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + if ( option.selected ) { + // Get the specifc value for the option + value = jQuery(option).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + } + + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) { + return elem.getAttribute("value") === null ? "on" : elem.value; + } + + + // Everything else, we just grab the value + return (elem.value || "").replace(rreturn, ""); + + } + + return undefined; + } + + var isFunction = jQuery.isFunction(value); + + return this.each(function(i) { + var self = jQuery(this), val = value; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call(this, i, self.val()); + } + + // Typecast each time if the value is a Function and the appended + // value is therefore different each time. + if ( typeof val === "number" ) { + val += ""; + } + + if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) { + this.checked = jQuery.inArray( self.val(), val ) >= 0; + + } else if ( jQuery.nodeName( this, "select" ) ) { + var values = jQuery.makeArray(val); + + jQuery( "option", this ).each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + this.selectedIndex = -1; + } + + } else { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + attrFn: { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }, + + attr: function( elem, name, value, pass ) { + /// + /// This method is internal. + /// + /// + + // don't set attributes on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { + return undefined; + } + + if ( pass && name in jQuery.attrFn ) { + return jQuery(elem)[name](value); + } + + var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), + // Whether we are setting (or getting) + set = value !== undefined; + + // Try to normalize/fix the name + name = notxml && jQuery.props[ name ] || name; + + // Only do all the following if this is a node (faster for style) + if ( elem.nodeType === 1 ) { + // These attributes require special treatment + var special = rspecialurl.test( name ); + + // Safari mis-reports the default selected property of an option + // Accessing the parent's selectedIndex property fixes it + if ( name === "selected" && !jQuery.support.optSelected ) { + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + + // If applicable, access the attribute via the DOM 0 way + if ( name in elem && notxml && !special ) { + if ( set ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } + + elem[ name ] = value; + } + + // browsers index elements by id/name on forms, give priority to attributes. + if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) { + return elem.getAttributeNode( name ).nodeValue; + } + + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + if ( name === "tabIndex" ) { + var attributeNode = elem.getAttributeNode( "tabIndex" ); + + return attributeNode && attributeNode.specified ? + attributeNode.value : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + + return elem[ name ]; + } + + if ( !jQuery.support.style && notxml && name === "style" ) { + if ( set ) { + elem.style.cssText = "" + value; + } + + return elem.style.cssText; + } + + if ( set ) { + // convert the value to a string (all browsers do this but IE) see #1070 + elem.setAttribute( name, "" + value ); + } + + var attr = !jQuery.support.hrefNormalized && notxml && special ? + // Some attributes require a special call on IE + elem.getAttribute( name, 2 ) : + elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return attr === null ? undefined : attr; + } + + // elem is actually elem.style ... set the style + // Using attr for specific style information is now deprecated. Use style insead. + return jQuery.style( elem, name, value ); + } +}); +var fcleanup = function( nm ) { + return nm.replace(/[^\w\s\.\|`]/g, function( ch ) { + return "\\" + ch; + }); +}; + +/* + * A number of helper functions used for managing events. + * Many of the ideas behind this code originated from + * Dean Edwards' addEvent library. + */ +jQuery.event = { + + // Bind an event to an element + // Original by Dean Edwards + add: function( elem, types, handler, data ) { + /// + /// This method is internal. + /// + /// + + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // For whatever reason, IE has trouble passing the window object + // around, causing it to be cloned in the process + if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) { + elem = window; + } + + // Make sure that the function being executed has a unique ID + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // if data is passed, bind to handler + if ( data !== undefined ) { + // Create temporary function pointer to original handler + var fn = handler; + + // Create unique handler function, wrapped around original handler + handler = jQuery.proxy( fn ); + + // Store data in unique handler + handler.data = data; + } + + // Init the element's event structure + var events = jQuery.data( elem, "events" ) || jQuery.data( elem, "events", {} ), + handle = jQuery.data( elem, "handle" ), eventHandle; + + if ( !handle ) { + eventHandle = function() { + // Handle the second event of a trigger and when + // an event is called after a page has unloaded + return typeof jQuery !== "undefined" && !jQuery.event.triggered ? + jQuery.event.handle.apply( eventHandle.elem, arguments ) : + undefined; + }; + + handle = jQuery.data( elem, "handle", eventHandle ); + } + + // If no handle is found then we must be trying to bind to one of the + // banned noData elements + if ( !handle ) { + return; + } + + // Add elem as a property of the handle function + // This is to prevent a memory leak with non-native + // event in IE. + handle.elem = elem; + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = types.split( /\s+/ ); + + var type, i = 0; + + while ( (type = types[ i++ ]) ) { + // Namespaced event handlers + var namespaces = type.split("."); + type = namespaces.shift(); + + if ( i > 1 ) { + handler = jQuery.proxy( handler ); + + if ( data !== undefined ) { + handler.data = data; + } + } + + handler.type = namespaces.slice(0).sort().join("."); + + // Get the current list of functions bound to this event + var handlers = events[ type ], + special = this.special[ type ] || {}; + + // Init the event handler queue + if ( !handlers ) { + handlers = events[ type ] = {}; + + // Check for a special event handler + // Only use addEventListener/attachEvent if the special + // events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, handler) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, handle, false ); + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, handle ); + } + } + } + + if ( special.add ) { + var modifiedHandler = special.add.call( elem, handler, data, namespaces, handlers ); + if ( modifiedHandler && jQuery.isFunction( modifiedHandler ) ) { + modifiedHandler.guid = modifiedHandler.guid || handler.guid; + modifiedHandler.data = modifiedHandler.data || handler.data; + modifiedHandler.type = modifiedHandler.type || handler.type; + handler = modifiedHandler; + } + } + + // Add the function to the element's handler list + handlers[ handler.guid ] = handler; + + // Keep track of which events have been used, for global triggering + this.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler ) { + /// + /// This method is internal. + /// + /// + + // don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + var events = jQuery.data( elem, "events" ), ret, type, fn; + + if ( events ) { + // Unbind all events for the element + if ( types === undefined || (typeof types === "string" && types.charAt(0) === ".") ) { + for ( type in events ) { + this.remove( elem, type + (types || "") ); + } + } else { + // types is actually an event object here + if ( types.type ) { + handler = types.handler; + types = types.type; + } + + // Handle multiple events separated by a space + // jQuery(...).unbind("mouseover mouseout", fn); + types = types.split(/\s+/); + var i = 0; + while ( (type = types[ i++ ]) ) { + // Namespaced event handlers + var namespaces = type.split("."); + type = namespaces.shift(); + var all = !namespaces.length, + cleaned = jQuery.map( namespaces.slice(0).sort(), fcleanup ), + namespace = new RegExp("(^|\\.)" + cleaned.join("\\.(?:.*\\.)?") + "(\\.|$)"), + special = this.special[ type ] || {}; + + if ( events[ type ] ) { + // remove the given handler for the given type + if ( handler ) { + fn = events[ type ][ handler.guid ]; + delete events[ type ][ handler.guid ]; + + // remove all handlers for the given type + } else { + for ( var handle in events[ type ] ) { + // Handle the removal of namespaced events + if ( all || namespace.test( events[ type ][ handle ].type ) ) { + delete events[ type ][ handle ]; + } + } + } + + if ( special.remove ) { + special.remove.call( elem, namespaces, fn); + } + + // remove generic event handler if no more handlers exist + for ( ret in events[ type ] ) { + break; + } + if ( !ret ) { + if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, jQuery.data( elem, "handle" ), false ); + } else if ( elem.detachEvent ) { + elem.detachEvent( "on" + type, jQuery.data( elem, "handle" ) ); + } + } + ret = null; + delete events[ type ]; + } + } + } + } + + // Remove the expando if it's no longer used + for ( ret in events ) { + break; + } + if ( !ret ) { + var handle = jQuery.data( elem, "handle" ); + if ( handle ) { + handle.elem = null; + } + jQuery.removeData( elem, "events" ); + jQuery.removeData( elem, "handle" ); + } + } + }, + + // bubbling is internal + trigger: function( event, data, elem /*, bubbling */ ) { + /// + /// This method is internal. + /// + /// + + // Event object or event type + var type = event.type || event, + bubbling = arguments[3]; + + if ( !bubbling ) { + event = typeof event === "object" ? + // jQuery.Event object + event[expando] ? event : + // Object literal + jQuery.extend( jQuery.Event(type), event ) : + // Just the event type (string) + jQuery.Event(type); + + if ( type.indexOf("!") >= 0 ) { + event.type = type = type.slice(0, -1); + event.exclusive = true; + } + + // Handle a global trigger + if ( !elem ) { + // Don't bubble custom events when global (to avoid too much overhead) + event.stopPropagation(); + + // Only trigger if we've ever bound an event for it + if ( this.global[ type ] ) { + jQuery.each( jQuery.cache, function() { + if ( this.events && this.events[type] ) { + jQuery.event.trigger( event, data, this.handle.elem ); + } + }); + } + } + + // Handle triggering a single element + + // don't do events on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { + return undefined; + } + + // Clean up in case it is reused + event.result = undefined; + event.target = elem; + + // Clone the incoming data, if any + data = jQuery.makeArray( data ); + data.unshift( event ); + } + + event.currentTarget = elem; + + // Trigger the event, it is assumed that "handle" is a function + var handle = jQuery.data( elem, "handle" ); + if ( handle ) { + handle.apply( elem, data ); + } + + var parent = elem.parentNode || elem.ownerDocument; + + // Trigger an inline bound script + try { + if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) { + if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) { + event.result = false; + } + } + + // prevent IE from throwing an error for some elements with some event types, see #3533 + } catch (e) {} + + if ( !event.isPropagationStopped() && parent ) { + jQuery.event.trigger( event, data, parent, true ); + + } else if ( !event.isDefaultPrevented() ) { + var target = event.target, old, + isClick = jQuery.nodeName(target, "a") && type === "click"; + + if ( !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) { + try { + if ( target[ type ] ) { + // Make sure that we don't accidentally re-trigger the onFOO events + old = target[ "on" + type ]; + + if ( old ) { + target[ "on" + type ] = null; + } + + this.triggered = true; + target[ type ](); + } + + // prevent IE from throwing an error for some elements with some event types, see #3533 + } catch (e) {} + + if ( old ) { + target[ "on" + type ] = old; + } + + this.triggered = false; + } + } + }, + + handle: function( event ) { + /// + /// This method is internal. + /// + /// + + // returned undefined or false + var all, handlers; + + event = arguments[0] = jQuery.event.fix( event || window.event ); + event.currentTarget = this; + + // Namespaced event handlers + var namespaces = event.type.split("."); + event.type = namespaces.shift(); + + // Cache this now, all = true means, any handler + all = !namespaces.length && !event.exclusive; + + var namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)"); + + handlers = ( jQuery.data(this, "events") || {} )[ event.type ]; + + for ( var j in handlers ) { + var handler = handlers[ j ]; + + // Filter the functions by class + if ( all || namespace.test(handler.type) ) { + // Pass in a reference to the handler function itself + // So that we can later remove it + event.handler = handler; + event.data = handler.data; + + var ret = handler.apply( this, arguments ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + + if ( event.isImmediatePropagationStopped() ) { + break; + } + + } + } + + return event.result; + }, + + props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), + + fix: function( event ) { + /// + /// This method is internal. + /// + /// + + if ( event[ expando ] ) { + return event; + } + + // store a copy of the original event object + // and "clone" to set read-only properties + var originalEvent = event; + event = jQuery.Event( originalEvent ); + + for ( var i = this.props.length, prop; i; ) { + prop = this.props[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary + if ( !event.target ) { + event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either + } + + // check if target is a textnode (safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && event.fromElement ) { + event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; + } + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && event.clientX != null ) { + var doc = document.documentElement, body = document.body; + event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); + event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); + } + + // Add which for key events + if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) { + event.which = event.charCode || event.keyCode; + } + + // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) + if ( !event.metaKey && event.ctrlKey ) { + event.metaKey = event.ctrlKey; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && event.button !== undefined ) { + event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); + } + + return event; + }, + + // Deprecated, use jQuery.guid instead + guid: 1E8, + + // Deprecated, use jQuery.proxy instead + proxy: jQuery.proxy, + + special: { + ready: { + // Make sure the ready event is setup + setup: jQuery.bindReady, + teardown: jQuery.noop + }, + + live: { + add: function( proxy, data, namespaces, live ) { + jQuery.extend( proxy, data || {} ); + + proxy.guid += data.selector + data.live; + data.liveProxy = proxy; + + jQuery.event.add( this, data.live, liveHandler, data ); + + }, + + remove: function( namespaces ) { + if ( namespaces.length ) { + var remove = 0, name = new RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)"); + + jQuery.each( (jQuery.data(this, "events").live || {}), function() { + if ( name.test(this.type) ) { + remove++; + } + }); + + if ( remove < 1 ) { + jQuery.event.remove( this, namespaces[0], liveHandler ); + } + } + }, + special: {} + }, + beforeunload: { + setup: function( data, namespaces, fn ) { + // We only want to do this special case on windows + if ( this.setInterval ) { + this.onbeforeunload = fn; + } + + return false; + }, + teardown: function( namespaces, fn ) { + if ( this.onbeforeunload === fn ) { + this.onbeforeunload = null; + } + } + } + } +}; + +jQuery.Event = function( src ) { + // Allow instantiation without the 'new' keyword + if ( !this.preventDefault ) { + return new jQuery.Event( src ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + // Event type + } else { + this.type = src; + } + + // timeStamp is buggy for some events on Firefox(#3843) + // So we won't rely on the native value + this.timeStamp = now(); + + // Mark it as fixed + this[ expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return true; +} + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + } + // otherwise set the returnValue property of the original event to false (IE) + e.returnValue = false; + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Checks if an event happened on an element within another element +// Used in jQuery.event.special.mouseenter and mouseleave handlers +var withinElement = function( event ) { + // Check if mouse(over|out) are still within the same parent element + var parent = event.relatedTarget; + + // Traverse up the tree + while ( parent && parent !== this ) { + // Firefox sometimes assigns relatedTarget a XUL element + // which we cannot access the parentNode property of + try { + parent = parent.parentNode; + + // assuming we've left the element since we most likely mousedover a xul element + } catch(e) { + break; + } + } + + if ( parent !== this ) { + // set the correct event type + event.type = event.data; + + // handle event if we actually just moused on to a non sub-element + jQuery.event.handle.apply( this, arguments ); + } + +}, + +// In case of event delegation, we only need to rename the event.type, +// liveHandler will take care of the rest. +delegate = function( event ) { + event.type = event.data; + jQuery.event.handle.apply( this, arguments ); +}; + +// Create mouseenter and mouseleave events +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + setup: function( data ) { + jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); + }, + teardown: function( data ) { + jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); + } + }; +}); + +// submit delegation +if ( !jQuery.support.submitBubbles ) { + +jQuery.event.special.submit = { + setup: function( data, namespaces, fn ) { + if ( this.nodeName.toLowerCase() !== "form" ) { + jQuery.event.add(this, "click.specialSubmit." + fn.guid, function( e ) { + var elem = e.target, type = elem.type; + + if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { + return trigger( "submit", this, arguments ); + } + }); + + jQuery.event.add(this, "keypress.specialSubmit." + fn.guid, function( e ) { + var elem = e.target, type = elem.type; + + if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { + return trigger( "submit", this, arguments ); + } + }); + + } else { + return false; + } + }, + + remove: function( namespaces, fn ) { + jQuery.event.remove( this, "click.specialSubmit" + (fn ? "."+fn.guid : "") ); + jQuery.event.remove( this, "keypress.specialSubmit" + (fn ? "."+fn.guid : "") ); + } +}; + +} + +// change delegation, happens here so we have bind. +if ( !jQuery.support.changeBubbles ) { + +var formElems = /textarea|input|select/i; + +function getVal( elem ) { + var type = elem.type, val = elem.value; + + if ( type === "radio" || type === "checkbox" ) { + val = elem.checked; + + } else if ( type === "select-multiple" ) { + val = elem.selectedIndex > -1 ? + jQuery.map( elem.options, function( elem ) { + return elem.selected; + }).join("-") : + ""; + + } else if ( elem.nodeName.toLowerCase() === "select" ) { + val = elem.selectedIndex; + } + + return val; +} + +function testChange( e ) { + var elem = e.target, data, val; + + if ( !formElems.test( elem.nodeName ) || elem.readOnly ) { + return; + } + + data = jQuery.data( elem, "_change_data" ); + val = getVal(elem); + + // the current data will be also retrieved by beforeactivate + if ( e.type !== "focusout" || elem.type !== "radio" ) { + jQuery.data( elem, "_change_data", val ); + } + + if ( data === undefined || val === data ) { + return; + } + + if ( data != null || val ) { + e.type = "change"; + return jQuery.event.trigger( e, arguments[1], elem ); + } +} + +jQuery.event.special.change = { + filters: { + focusout: testChange, + + click: function( e ) { + var elem = e.target, type = elem.type; + + if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) { + return testChange.call( this, e ); + } + }, + + // Change has to be called before submit + // Keydown will be called before keypress, which is used in submit-event delegation + keydown: function( e ) { + var elem = e.target, type = elem.type; + + if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") || + (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || + type === "select-multiple" ) { + return testChange.call( this, e ); + } + }, + + // Beforeactivate happens also before the previous element is blurred + // with this event you can't trigger a change event, but you can store + // information/focus[in] is not needed anymore + beforeactivate: function( e ) { + var elem = e.target; + + if ( elem.nodeName.toLowerCase() === "input" && elem.type === "radio" ) { + jQuery.data( elem, "_change_data", getVal(elem) ); + } + } + }, + setup: function( data, namespaces, fn ) { + for ( var type in changeFilters ) { + jQuery.event.add( this, type + ".specialChange." + fn.guid, changeFilters[type] ); + } + + return formElems.test( this.nodeName ); + }, + remove: function( namespaces, fn ) { + for ( var type in changeFilters ) { + jQuery.event.remove( this, type + ".specialChange" + (fn ? "."+fn.guid : ""), changeFilters[type] ); + } + + return formElems.test( this.nodeName ); + } +}; + +var changeFilters = jQuery.event.special.change.filters; + +} + +function trigger( type, elem, args ) { + args[0].type = type; + return jQuery.event.handle.apply( elem, args ); +} + +// Create "bubbling" focus and blur events +if ( document.addEventListener ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + jQuery.event.special[ fix ] = { + setup: function() { + /// + /// This method is internal. + /// + /// + + this.addEventListener( orig, handler, true ); + }, + teardown: function() { + /// + /// This method is internal. + /// + /// + + this.removeEventListener( orig, handler, true ); + } + }; + + function handler( e ) { + e = jQuery.event.fix( e ); + e.type = fix; + return jQuery.event.handle.call( this, e ); + } + }); +} + +// jQuery.each(["bind", "one"], function( i, name ) { +// jQuery.fn[ name ] = function( type, data, fn ) { +// // Handle object literals +// if ( typeof type === "object" ) { +// for ( var key in type ) { +// this[ name ](key, data, type[key], fn); +// } +// return this; +// } +// +// if ( jQuery.isFunction( data ) ) { +// fn = data; +// data = undefined; +// } +// +// var handler = name === "one" ? jQuery.proxy( fn, function( event ) { +// jQuery( this ).unbind( event, handler ); +// return fn.apply( this, arguments ); +// }) : fn; +// +// return type === "unload" && name !== "one" ? +// this.one( type, data, fn ) : +// this.each(function() { +// jQuery.event.add( this, type, handler, data ); +// }); +// }; +// }); + +jQuery.fn[ "bind" ] = function( type, data, fn ) { + /// + /// Binds a handler to one or more events for each matched element. Can also bind custom events. + /// + /// One or more event types separated by a space. Built-in event type values are: blur, focus, load, resize, scroll, unload, click, dblclick, mousedown, mouseup, mousemove, mouseover, mouseout, mouseenter, mouseleave, change, select, submit, keydown, keypress, keyup, error . + /// Additional data passed to the event handler as event.data + /// A function to bind to the event on each of the set of matched elements. function callback(eventObject) such that this corresponds to the dom element. + + // Handle object literals + if ( typeof type === "object" ) { + for ( var key in type ) { + this[ "bind" ](key, data, type[key], fn); + } + return this; + } + + if ( jQuery.isFunction( data ) ) { + fn = data; + data = undefined; + } + + var handler = "bind" === "one" ? jQuery.proxy( fn, function( event ) { + jQuery( this ).unbind( event, handler ); + return fn.apply( this, arguments ); + }) : fn; + + return type === "unload" && "bind" !== "one" ? + this.one( type, data, fn ) : + this.each(function() { + jQuery.event.add( this, type, handler, data ); + }); +}; + +jQuery.fn[ "one" ] = function( type, data, fn ) { + /// + /// Binds a handler to one or more events to be executed exactly once for each matched element. + /// + /// One or more event types separated by a space. Built-in event type values are: blur, focus, load, resize, scroll, unload, click, dblclick, mousedown, mouseup, mousemove, mouseover, mouseout, mouseenter, mouseleave, change, select, submit, keydown, keypress, keyup, error . + /// Additional data passed to the event handler as event.data + /// A function to bind to the event on each of the set of matched elements. function callback(eventObject) such that this corresponds to the dom element. + + // Handle object literals + if ( typeof type === "object" ) { + for ( var key in type ) { + this[ "one" ](key, data, type[key], fn); + } + return this; + } + + if ( jQuery.isFunction( data ) ) { + fn = data; + data = undefined; + } + + var handler = "one" === "one" ? jQuery.proxy( fn, function( event ) { + jQuery( this ).unbind( event, handler ); + return fn.apply( this, arguments ); + }) : fn; + + return type === "unload" && "one" !== "one" ? + this.one( type, data, fn ) : + this.each(function() { + jQuery.event.add( this, type, handler, data ); + }); +}; + +jQuery.fn.extend({ + unbind: function( type, fn ) { + /// + /// Unbinds a handler from one or more events for each matched element. + /// + /// One or more event types separated by a space. Built-in event type values are: blur, focus, load, resize, scroll, unload, click, dblclick, mousedown, mouseup, mousemove, mouseover, mouseout, mouseenter, mouseleave, change, select, submit, keydown, keypress, keyup, error . + /// A function to bind to the event on each of the set of matched elements. function callback(eventObject) such that this corresponds to the dom element. + + // Handle object literals + if ( typeof type === "object" && !type.preventDefault ) { + for ( var key in type ) { + this.unbind(key, type[key]); + } + return this; + } + + return this.each(function() { + jQuery.event.remove( this, type, fn ); + }); + }, + trigger: function( type, data ) { + /// + /// Triggers a type of event on every matched element. + /// + /// One or more event types separated by a space. Built-in event type values are: blur, focus, load, resize, scroll, unload, click, dblclick, mousedown, mouseup, mousemove, mouseover, mouseout, mouseenter, mouseleave, change, select, submit, keydown, keypress, keyup, error . + /// Additional data passed to the event handler as additional arguments. + /// This parameter is undocumented. + + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + + triggerHandler: function( type, data ) { + /// + /// Triggers all bound event handlers on an element for a specific event type without executing the browser's default actions. + /// + /// One or more event types separated by a space. Built-in event type values are: blur, focus, load, resize, scroll, unload, click, dblclick, mousedown, mouseup, mousemove, mouseover, mouseout, mouseenter, mouseleave, change, select, submit, keydown, keypress, keyup, error . + /// Additional data passed to the event handler as additional arguments. + /// This parameter is undocumented. + + if ( this[0] ) { + var event = jQuery.Event( type ); + event.preventDefault(); + event.stopPropagation(); + jQuery.event.trigger( event, data, this[0] ); + return event.result; + } + }, + + toggle: function( fn ) { + /// + /// Toggles among two or more function calls every other click. + /// + /// The functions among which to toggle execution + + // Save reference to arguments for access in closure + var args = arguments, i = 1; + + // link all the functions, so any of them can unbind this click handler + while ( i < args.length ) { + jQuery.proxy( fn, args[ i++ ] ); + } + + return this.click( jQuery.proxy( fn, function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + })); + }, + + hover: function( fnOver, fnOut ) { + /// + /// Simulates hovering (moving the mouse on or off of an object). + /// + /// The function to fire when the mouse is moved over a matched element. + /// The function to fire when the mouse is moved off of a matched element. + + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +// jQuery.each(["live", "die"], function( i, name ) { +// jQuery.fn[ name ] = function( types, data, fn ) { +// var type, i = 0; +// +// if ( jQuery.isFunction( data ) ) { +// fn = data; +// data = undefined; +// } +// +// types = (types || "").split( /\s+/ ); +// +// while ( (type = types[ i++ ]) != null ) { +// type = type === "focus" ? "focusin" : // focus --> focusin +// type === "blur" ? "focusout" : // blur --> focusout +// type === "hover" ? types.push("mouseleave") && "mouseenter" : // hover support +// type; +// +// if ( name === "live" ) { +// // bind live handler +// jQuery( this.context ).bind( liveConvert( type, this.selector ), { +// data: data, selector: this.selector, live: type +// }, fn ); +// +// } else { +// // unbind live handler +// jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null ); +// } +// } +// +// return this; +// } +// }); + +jQuery.fn[ "live" ] = function( types, data, fn ) { + /// + /// Attach a handler to the event for all elements which match the current selector, now or + /// in the future. + /// + /// + /// A string containing a JavaScript event type, such as "click" or "keydown". + /// + /// + /// A map of data that will be passed to the event handler. + /// + /// + /// A function to execute at the time the event is triggered. + /// + /// + + var type, i = 0; + + if ( jQuery.isFunction( data ) ) { + fn = data; + data = undefined; + } + + types = (types || "").split( /\s+/ ); + + while ( (type = types[ i++ ]) != null ) { + type = type === "focus" ? "focusin" : // focus --> focusin + type === "blur" ? "focusout" : // blur --> focusout + type === "hover" ? types.push("mouseleave") && "mouseenter" : // hover support + type; + + if ( "live" === "live" ) { + // bind live handler + jQuery( this.context ).bind( liveConvert( type, this.selector ), { + data: data, selector: this.selector, live: type + }, fn ); + + } else { + // unbind live handler + jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null ); + } + } + + return this; +} + +jQuery.fn[ "die" ] = function( types, data, fn ) { + /// + /// Remove all event handlers previously attached using .live() from the elements. + /// + /// + /// A string containing a JavaScript event type, such as click or keydown. + /// + /// + /// The function that is to be no longer executed. + /// + /// + + var type, i = 0; + + if ( jQuery.isFunction( data ) ) { + fn = data; + data = undefined; + } + + types = (types || "").split( /\s+/ ); + + while ( (type = types[ i++ ]) != null ) { + type = type === "focus" ? "focusin" : // focus --> focusin + type === "blur" ? "focusout" : // blur --> focusout + type === "hover" ? types.push("mouseleave") && "mouseenter" : // hover support + type; + + if ( "die" === "live" ) { + // bind live handler + jQuery( this.context ).bind( liveConvert( type, this.selector ), { + data: data, selector: this.selector, live: type + }, fn ); + + } else { + // unbind live handler + jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null ); + } + } + + return this; +} + +function liveHandler( event ) { + var stop, elems = [], selectors = [], args = arguments, + related, match, fn, elem, j, i, l, data, + live = jQuery.extend({}, jQuery.data( this, "events" ).live); + + // Make sure we avoid non-left-click bubbling in Firefox (#3861) + if ( event.button && event.type === "click" ) { + return; + } + + for ( j in live ) { + fn = live[j]; + if ( fn.live === event.type || + fn.altLive && jQuery.inArray(event.type, fn.altLive) > -1 ) { + + data = fn.data; + if ( !(data.beforeFilter && data.beforeFilter[event.type] && + !data.beforeFilter[event.type](event)) ) { + selectors.push( fn.selector ); + } + } else { + delete live[j]; + } + } + + match = jQuery( event.target ).closest( selectors, event.currentTarget ); + + for ( i = 0, l = match.length; i < l; i++ ) { + for ( j in live ) { + fn = live[j]; + elem = match[i].elem; + related = null; + + if ( match[i].selector === fn.selector ) { + // Those two events require additional checking + if ( fn.live === "mouseenter" || fn.live === "mouseleave" ) { + related = jQuery( event.relatedTarget ).closest( fn.selector )[0]; + } + + if ( !related || related !== elem ) { + elems.push({ elem: elem, fn: fn }); + } + } + } + } + + for ( i = 0, l = elems.length; i < l; i++ ) { + match = elems[i]; + event.currentTarget = match.elem; + event.data = match.fn.data; + if ( match.fn.apply( match.elem, args ) === false ) { + stop = false; + break; + } + } + + return stop; +} + +function liveConvert( type, selector ) { + return "live." + (type ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&"); +} + +// jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + +// "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + +// "change select submit keydown keypress keyup error").split(" "), function( i, name ) { +// +// // Handle event binding +// jQuery.fn[ name ] = function( fn ) { +// return fn ? this.bind( name, fn ) : this.trigger( name ); +// }; +// +// if ( jQuery.attrFn ) { +// jQuery.attrFn[ name ] = true; +// } +// }); + +jQuery.fn[ "blur" ] = function( fn ) { + /// + /// 1: blur() - Triggers the blur event of each matched element. + /// 2: blur(fn) - Binds a function to the blur event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "blur", fn ) : this.trigger( "blur" ); +}; + +jQuery.fn[ "focus" ] = function( fn ) { + /// + /// 1: focus() - Triggers the focus event of each matched element. + /// 2: focus(fn) - Binds a function to the focus event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "focus", fn ) : this.trigger( "focus" ); +}; + +jQuery.fn[ "focusin" ] = function( fn ) { + /// + /// Bind an event handler to the "focusin" JavaScript event. + /// + /// + /// A function to execute each time the event is triggered. + /// + /// + + return fn ? this.bind( "focusin", fn ) : this.trigger( "focusin" ); +}; + +jQuery.fn[ "focusout" ] = function( fn ) { + /// + /// Bind an event handler to the "focusout" JavaScript event. + /// + /// + /// A function to execute each time the event is triggered. + /// + /// + + return fn ? this.bind( "focusout", fn ) : this.trigger( "focusout" ); +}; + +jQuery.fn[ "load" ] = function( fn ) { + /// + /// 1: load() - Triggers the load event of each matched element. + /// 2: load(fn) - Binds a function to the load event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "load", fn ) : this.trigger( "load" ); +}; + +jQuery.fn[ "resize" ] = function( fn ) { + /// + /// 1: resize() - Triggers the resize event of each matched element. + /// 2: resize(fn) - Binds a function to the resize event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "resize", fn ) : this.trigger( "resize" ); +}; + +jQuery.fn[ "scroll" ] = function( fn ) { + /// + /// 1: scroll() - Triggers the scroll event of each matched element. + /// 2: scroll(fn) - Binds a function to the scroll event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "scroll", fn ) : this.trigger( "scroll" ); +}; + +jQuery.fn[ "unload" ] = function( fn ) { + /// + /// 1: unload() - Triggers the unload event of each matched element. + /// 2: unload(fn) - Binds a function to the unload event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "unload", fn ) : this.trigger( "unload" ); +}; + +jQuery.fn[ "click" ] = function( fn ) { + /// + /// 1: click() - Triggers the click event of each matched element. + /// 2: click(fn) - Binds a function to the click event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "click", fn ) : this.trigger( "click" ); +}; + +jQuery.fn[ "dblclick" ] = function( fn ) { + /// + /// 1: dblclick() - Triggers the dblclick event of each matched element. + /// 2: dblclick(fn) - Binds a function to the dblclick event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "dblclick", fn ) : this.trigger( "dblclick" ); +}; + +jQuery.fn[ "mousedown" ] = function( fn ) { + /// + /// Binds a function to the mousedown event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "mousedown", fn ) : this.trigger( "mousedown" ); +}; + +jQuery.fn[ "mouseup" ] = function( fn ) { + /// + /// Bind a function to the mouseup event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "mouseup", fn ) : this.trigger( "mouseup" ); +}; + +jQuery.fn[ "mousemove" ] = function( fn ) { + /// + /// Bind a function to the mousemove event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "mousemove", fn ) : this.trigger( "mousemove" ); +}; + +jQuery.fn[ "mouseover" ] = function( fn ) { + /// + /// Bind a function to the mouseover event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "mouseover", fn ) : this.trigger( "mouseover" ); +}; + +jQuery.fn[ "mouseout" ] = function( fn ) { + /// + /// Bind a function to the mouseout event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "mouseout", fn ) : this.trigger( "mouseout" ); +}; + +jQuery.fn[ "mouseenter" ] = function( fn ) { + /// + /// Bind a function to the mouseenter event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "mouseenter", fn ) : this.trigger( "mouseenter" ); +}; + +jQuery.fn[ "mouseleave" ] = function( fn ) { + /// + /// Bind a function to the mouseleave event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "mouseleave", fn ) : this.trigger( "mouseleave" ); +}; + +jQuery.fn[ "change" ] = function( fn ) { + /// + /// 1: change() - Triggers the change event of each matched element. + /// 2: change(fn) - Binds a function to the change event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "change", fn ) : this.trigger( "change" ); +}; + +jQuery.fn[ "select" ] = function( fn ) { + /// + /// 1: select() - Triggers the select event of each matched element. + /// 2: select(fn) - Binds a function to the select event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "select", fn ) : this.trigger( "select" ); +}; + +jQuery.fn[ "submit" ] = function( fn ) { + /// + /// 1: submit() - Triggers the submit event of each matched element. + /// 2: submit(fn) - Binds a function to the submit event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "submit", fn ) : this.trigger( "submit" ); +}; + +jQuery.fn[ "keydown" ] = function( fn ) { + /// + /// 1: keydown() - Triggers the keydown event of each matched element. + /// 2: keydown(fn) - Binds a function to the keydown event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "keydown", fn ) : this.trigger( "keydown" ); +}; + +jQuery.fn[ "keypress" ] = function( fn ) { + /// + /// 1: keypress() - Triggers the keypress event of each matched element. + /// 2: keypress(fn) - Binds a function to the keypress event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "keypress", fn ) : this.trigger( "keypress" ); +}; + +jQuery.fn[ "keyup" ] = function( fn ) { + /// + /// 1: keyup() - Triggers the keyup event of each matched element. + /// 2: keyup(fn) - Binds a function to the keyup event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "keyup", fn ) : this.trigger( "keyup" ); +}; + +jQuery.fn[ "error" ] = function( fn ) { + /// + /// 1: error() - Triggers the error event of each matched element. + /// 2: error(fn) - Binds a function to the error event of each matched element. + /// + /// The function to execute. + /// + + return fn ? this.bind( "error", fn ) : this.trigger( "error" ); +}; + +// Prevent memory leaks in IE +// Window isn't included so as not to unbind existing unload events +// More info: +// - http://isaacschlueter.com/2006/10/msie-memory-leaks/ +if ( window.attachEvent && !window.addEventListener ) { + window.attachEvent("onunload", function() { + for ( var id in jQuery.cache ) { + if ( jQuery.cache[ id ].handle ) { + // Try/Catch is to handle iframes being unloaded, see #4280 + try { + jQuery.event.remove( jQuery.cache[ id ].handle.elem ); + } catch(e) {} + } + } + }); +} +/*! + * Sizzle CSS Selector Engine - v1.0 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function(){ + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function(selector, context, results, seed) { + results = results || []; + var origContext = context = context || document; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var parts = [], m, set, checkSet, extra, prune = true, contextXML = isXML(context), + soFar = selector; + + // Reset the position of the chunker regexp (start from head) + while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context ); + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) { + selector += parts.shift(); + } + + set = posProcess( selector, set ); + } + } + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + var ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; + } + + if ( context ) { + var ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray(set); + } else { + prune = false; + } + + while ( parts.length ) { + var cur = parts.pop(), pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + Sizzle.error( cur || selector ); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + } else if ( context && context.nodeType === 1 ) { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + } else { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function(results){ + /// + /// Removes all duplicate elements from an array of elements. + /// + /// The array to translate + /// The array after translation. + + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort(sortOrder); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[i-1] ) { + results.splice(i--, 1); + } + } + } + } + + return results; +}; + +Sizzle.matches = function(expr, set){ + return Sizzle(expr, null, null, set); +}; + +Sizzle.find = function(expr, context, isXML){ + var set, match; + + if ( !expr ) { + return []; + } + + for ( var i = 0, l = Expr.order.length; i < l; i++ ) { + var type = Expr.order[i], match; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + var left = match[1]; + match.splice(1,1); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace(/\\/g, ""); + set = Expr.find[ type ]( match, context, isXML ); + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = context.getElementsByTagName("*"); + } + + return {set: set, expr: expr}; +}; + +Sizzle.filter = function(expr, set, inplace, not){ + var old = expr, result = [], curLoop = set, match, anyFound, + isXMLFilter = set && set[0] && isXML(set[0]); + + while ( expr && set.length ) { + for ( var type in Expr.filter ) { + if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { + var filter = Expr.filter[ type ], found, item, left = match[1]; + anyFound = false; + + match.splice(1,1); + + if ( left.substr( left.length - 1 ) === "\\" ) { + continue; + } + + if ( curLoop === result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + var pass = not ^ !!found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + } else { + curLoop[i] = false; + } + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr === old ) { + if ( anyFound == null ) { + Sizzle.error( expr ); + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +Sizzle.error = function( msg ) { + throw "Syntax error, unrecognized expression: " + msg; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + match: { + ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ + }, + leftMatch: {}, + attrMap: { + "class": "className", + "for": "htmlFor" + }, + attrHandle: { + href: function(elem){ + return elem.getAttribute("href"); + } + }, + relative: { + "+": function(checkSet, part){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !/\W/.test(part), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag ) { + part = part.toLowerCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + ">": function(checkSet, part){ + var isPartStr = typeof part === "string"; + + if ( isPartStr && !/\W/.test(part) ) { + part = part.toLowerCase(); + + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; + } + } + } else { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + "": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( typeof part === "string" && !/\W/.test(part) ) { + var nodeCheck = part = part.toLowerCase(); + checkFn = dirNodeCheck; + } + + checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); + }, + "~": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( typeof part === "string" && !/\W/.test(part) ) { + var nodeCheck = part = part.toLowerCase(); + checkFn = dirNodeCheck; + } + + checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); + } + }, + find: { + ID: function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? [m] : []; + } + }, + NAME: function(match, context){ + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], results = context.getElementsByName(match[1]); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + TAG: function(match, context){ + return context.getElementsByTagName(match[1]); + } + }, + preFilter: { + CLASS: function(match, curLoop, inplace, result, not, isXML){ + match = " " + match[1].replace(/\\/g, "") + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) { + if ( !inplace ) { + result.push( elem ); + } + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + ID: function(match){ + return match[1].replace(/\\/g, ""); + }, + TAG: function(match, curLoop){ + return match[1].toLowerCase(); + }, + CHILD: function(match){ + if ( match[1] === "nth" ) { + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + ATTR: function(match, curLoop, inplace, result, not, isXML){ + var name = match[1].replace(/\\/g, ""); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + PSEUDO: function(match, curLoop, inplace, result, not){ + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + if ( !inplace ) { + result.push.apply( result, ret ); + } + return false; + } + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + POS: function(match){ + match.unshift( true ); + return match; + } + }, + filters: { + enabled: function(elem){ + return elem.disabled === false && elem.type !== "hidden"; + }, + disabled: function(elem){ + return elem.disabled === true; + }, + checked: function(elem){ + return elem.checked === true; + }, + selected: function(elem){ + // Accessing this property makes selected-by-default + // options in Safari work properly + elem.parentNode.selectedIndex; + return elem.selected === true; + }, + parent: function(elem){ + return !!elem.firstChild; + }, + empty: function(elem){ + return !elem.firstChild; + }, + has: function(elem, i, match){ + /// + /// Internal use only; use hasClass('class') + /// + /// + + return !!Sizzle( match[3], elem ).length; + }, + header: function(elem){ + return /h\d/i.test( elem.nodeName ); + }, + text: function(elem){ + return "text" === elem.type; + }, + radio: function(elem){ + return "radio" === elem.type; + }, + checkbox: function(elem){ + return "checkbox" === elem.type; + }, + file: function(elem){ + return "file" === elem.type; + }, + password: function(elem){ + return "password" === elem.type; + }, + submit: function(elem){ + return "submit" === elem.type; + }, + image: function(elem){ + return "image" === elem.type; + }, + reset: function(elem){ + return "reset" === elem.type; + }, + button: function(elem){ + return "button" === elem.type || elem.nodeName.toLowerCase() === "button"; + }, + input: function(elem){ + return /input|select|textarea|button/i.test(elem.nodeName); + } + }, + setFilters: { + first: function(elem, i){ + return i === 0; + }, + last: function(elem, i, match, array){ + return i === array.length - 1; + }, + even: function(elem, i){ + return i % 2 === 0; + }, + odd: function(elem, i){ + return i % 2 === 1; + }, + lt: function(elem, i, match){ + return i < match[3] - 0; + }, + gt: function(elem, i, match){ + return i > match[3] - 0; + }, + nth: function(elem, i, match){ + return match[3] - 0 === i; + }, + eq: function(elem, i, match){ + return match[3] - 0 === i; + } + }, + filter: { + PSEUDO: function(elem, match, i, array){ + var name = match[1], filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; + } else if ( name === "not" ) { + var not = match[3]; + + for ( var i = 0, l = not.length; i < l; i++ ) { + if ( not[i] === elem ) { + return false; + } + } + + return true; + } else { + Sizzle.error( "Syntax error, unrecognized expression: " + name ); + } + }, + CHILD: function(elem, match){ + var type = match[1], node = elem; + switch (type) { + case 'only': + case 'first': + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + if ( type === "first" ) { + return true; + } + node = elem; + case 'last': + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + return true; + case 'nth': + var first = match[2], last = match[3]; + + if ( first === 1 && last === 0 ) { + return true; + } + + var doneName = match[0], + parent = elem.parentNode; + + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { + var count = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + parent.sizcache = doneName; + } + + var diff = elem.nodeIndex - last; + if ( first === 0 ) { + return diff === 0; + } else { + return ( diff % first === 0 && diff / first >= 0 ); + } + } + }, + ID: function(elem, match){ + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + TAG: function(elem, match){ + return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; + }, + CLASS: function(elem, match){ + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + ATTR: function(elem, match){ + var name = match[1], + result = Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value !== check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + POS: function(elem, match, i, array){ + var name = match[2], filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, function(all, num){ + return "\\" + (num - 0 + 1); + })); +} + +var makeArray = function(array, results) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 ); + +// Provide a fallback method if it does not work +} catch(e){ + makeArray = function(array, results) { + var ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + } else { + if ( typeof array.length === "number" ) { + for ( var i = 0, l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + } else { + for ( var i = 0; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + if ( a == b ) { + hasDuplicate = true; + } + return a.compareDocumentPosition ? -1 : 1; + } + + var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( "sourceIndex" in document.documentElement ) { + sortOrder = function( a, b ) { + if ( !a.sourceIndex || !b.sourceIndex ) { + if ( a == b ) { + hasDuplicate = true; + } + return a.sourceIndex ? -1 : 1; + } + + var ret = a.sourceIndex - b.sourceIndex; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( document.createRange ) { + sortOrder = function( a, b ) { + if ( !a.ownerDocument || !b.ownerDocument ) { + if ( a == b ) { + hasDuplicate = true; + } + return a.ownerDocument ? -1 : 1; + } + + var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); + aRange.setStart(a, 0); + aRange.setEnd(a, 0); + bRange.setStart(b, 0); + bRange.setEnd(b, 0); + var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} + +// Utility function for retreiving the text value of an array of DOM nodes +function getText( elems ) { + var ret = "", elem; + + for ( var i = 0; elems[i]; i++ ) { + elem = elems[i]; + + // Get the text from text nodes and CDATA nodes + if ( elem.nodeType === 3 || elem.nodeType === 4 ) { + ret += elem.nodeValue; + + // Traverse everything else, except comment nodes + } else if ( elem.nodeType !== 8 ) { + ret += getText( elem.childNodes ); + } + } + + return ret; +} + +// [vsdoc] The following function has been modified for IntelliSense. +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + // var form = document.createElement("div"), + // id = "script" + (new Date).getTime(); + // form.innerHTML = ""; + + // // Inject it into the root element, check its status, and remove it quickly + // var root = document.documentElement; + // root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + // if ( document.getElementById( id ) ) { + Expr.find.ID = function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; + } + }; + + Expr.filter.ID = function(elem, match){ + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + // } + + // root.removeChild( form ); + root = form = null; // release memory in IE +})(); + +// [vsdoc] The following function has been modified for IntelliSense. +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + // var div = document.createElement("div"); + // div.appendChild( document.createComment("") ); + + // Make sure no comments are found + // if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function(match, context){ + var results = context.getElementsByTagName(match[1]); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + // } + + // Check to see if an attribute returns normalized href attributes + // div.innerHTML = ""; + // if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + // div.firstChild.getAttribute("href") !== "#" ) { + Expr.attrHandle.href = function(elem){ + return elem.getAttribute("href", 2); + }; + // } + + div = null; // release memory in IE +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, div = document.createElement("div"); + div.innerHTML = "

"; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function(query, context, extra, seed){ + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && context.nodeType === 9 && !isXML(context) ) { + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(e){} + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + div = null; // release memory in IE + })(); +} + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "
"; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) { + return; + } + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function(match, context, isXML) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + div = null; // release memory in IE +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( elem.nodeName.toLowerCase() === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem.sizcache = doneName; + elem.sizset = i; + } + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +var contains = document.compareDocumentPosition ? function(a, b){ + /// + /// Check to see if a DOM node is within another DOM node. + /// + /// + /// The DOM element that may contain the other element. + /// + /// + /// The DOM node that may be contained by the other element. + /// + /// + + return a.compareDocumentPosition(b) & 16; +} : function(a, b){ + /// + /// Check to see if a DOM node is within another DOM node. + /// + /// + /// The DOM element that may contain the other element. + /// + /// + /// The DOM node that may be contained by the other element. + /// + /// + + return a !== b && (a.contains ? a.contains(b) : true); +}; + +var isXML = function(elem){ + /// + /// Determines if the parameter passed is an XML document. + /// + /// The object to test + /// True if the parameter is an XML document; otherwise false. + + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +var posProcess = function(selector, context){ + var tmpSet = [], later = "", match, + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.filters; +jQuery.unique = Sizzle.uniqueSort; +jQuery.getText = getText; +jQuery.isXMLDoc = isXML; +jQuery.contains = contains; + +return; + +window.Sizzle = Sizzle; + +})(); +var runtil = /Until$/, + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // Note: This RegExp should be improved, or likely pulled from Sizzle + rmultiselector = /,/, + slice = Array.prototype.slice; + +// Implement the identical functionality for filter and not +var winnow = function( elements, qualifier, keep ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return (elem === qualifier) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return (jQuery.inArray( elem, qualifier ) >= 0) === keep; + }); +}; + +jQuery.fn.extend({ + find: function( selector ) { + /// + /// Searches for all elements that match the specified expression. + /// This method is a good way to find additional descendant + /// elements with which to process. + /// All searching is done using a jQuery expression. The expression can be + /// written using CSS 1-3 Selector syntax, or basic XPath. + /// Part of DOM/Traversing + /// + /// + /// + /// An expression to search with. + /// + /// + + var ret = this.pushStack( "", "find", selector ), length = 0; + + for ( var i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( var n = length; n < ret.length; n++ ) { + for ( var r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + /// + /// Reduce the set of matched elements to those that have a descendant that matches the + /// selector or DOM element. + /// + /// + /// A string containing a selector expression to match elements against. + /// + /// + + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + /// + /// Removes any elements inside the array of elements from the set + /// of matched elements. This method is used to remove one or more + /// elements from a jQuery object. + /// Part of DOM/Traversing + /// + /// + /// A set of elements to remove from the jQuery set of matched elements. + /// + /// + + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + /// + /// Removes all elements from the set of matched elements that do not + /// pass the specified filter. This method is used to narrow down + /// the results of a search. + /// }) + /// Part of DOM/Traversing + /// + /// + /// + /// A function to use for filtering + /// + /// + + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + /// + /// Checks the current selection against an expression and returns true, + /// if at least one element of the selection fits the given expression. + /// Does return false, if no element fits or the expression is not valid. + /// filter(String) is used internally, therefore all rules that apply there + /// apply here, too. + /// Part of DOM/Traversing + /// + /// + /// + /// The expression with which to filter + /// + + return !!selector && jQuery.filter( selector, this ).length > 0; + }, + + closest: function( selectors, context ) { + /// + /// Get a set of elements containing the closest parent element that matches the specified selector, the starting element included. + /// + /// + /// A string containing a selector expression to match elements against. + /// + /// + /// A DOM element within which a matching element may be found. If no context is passed + /// in then the context of the jQuery set will be used instead. + /// + /// + + if ( jQuery.isArray( selectors ) ) { + var ret = [], cur = this[0], match, matches = {}, selector; + + if ( cur && selectors.length ) { + for ( var i = 0, l = selectors.length; i < l; i++ ) { + selector = selectors[i]; + + if ( !matches[selector] ) { + matches[selector] = jQuery.expr.match.POS.test( selector ) ? + jQuery( selector, context || this.context ) : + selector; + } + } + + while ( cur && cur.ownerDocument && cur !== context ) { + for ( selector in matches ) { + match = matches[selector]; + + if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) { + ret.push({ selector: selector, elem: cur }); + delete matches[selector]; + } + } + cur = cur.parentNode; + } + } + + return ret; + } + + var pos = jQuery.expr.match.POS.test( selectors ) ? + jQuery( selectors, context || this.context ) : null; + + return this.map(function( i, cur ) { + while ( cur && cur.ownerDocument && cur !== context ) { + if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selectors) ) { + return cur; + } + cur = cur.parentNode; + } + return null; + }); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + /// + /// Searches every matched element for the object and returns + /// the index of the element, if found, starting with zero. + /// Returns -1 if the object wasn't found. + /// Part of Core + /// + /// + /// + /// Object to search for + /// + + if ( !elem || typeof elem === "string" ) { + return jQuery.inArray( this[0], + // If it receives a string, the selector is used + // If it receives nothing, the siblings are used + elem ? jQuery( elem ) : this.parent().children() ); + } + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + /// + /// Adds one or more Elements to the set of matched elements. + /// Part of DOM/Traversing + /// + /// + /// A string containing a selector expression to match additional elements against. + /// + /// + /// Add some elements rooted against the specified context. + /// + /// + + var set = typeof selector === "string" ? + jQuery( selector, context || this.context ) : + jQuery.makeArray( selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + andSelf: function() { + /// + /// Adds the previous selection to the current selection. + /// + /// + + return this.add( this.prevObject ); + } +}); + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + next: function( elem ) { + return jQuery.nth( elem, 2, "nextSibling" ); + }, + prev: function( elem ) { + return jQuery.nth( elem, 2, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + siblings: function( elem ) { + return jQuery.sibling( elem.parentNode.firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.makeArray( elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, slice.call(arguments).join(",") ); + }; +}); + +jQuery.fn[ "parentsUntil" ] = function( until, selector ) { + /// + /// Get the ancestors of each element in the current set of matched elements, up to but not + /// including the element matched by the selector. + /// + /// + /// A string containing a selector expression to indicate where to stop matching ancestor + /// elements. + /// + /// + + var fn = function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + } + + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( "parentsUntil" ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( "parentsUntil" ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, "parentsUntil", slice.call(arguments).join(",") ); +}; + +jQuery.fn[ "nextUntil" ] = function( until, selector ) { + /// + /// Get all following siblings of each element up to but not including the element matched + /// by the selector. + /// + /// + /// A string containing a selector expression to indicate where to stop matching following + /// sibling elements. + /// + /// + + var fn = function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + } + + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( "nextUntil" ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( "nextUntil" ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, "nextUntil", slice.call(arguments).join(",") ); +}; + +jQuery.fn[ "prevUntil" ] = function( until, selector ) { + /// + /// Get all preceding siblings of each element up to but not including the element matched + /// by the selector. + /// + /// + /// A string containing a selector expression to indicate where to stop matching preceding + /// sibling elements. + /// + /// + + var fn = function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + } + + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( "prevUntil" ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( "prevUntil" ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, "prevUntil", slice.call(arguments).join(",") ); +}; + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + /// + /// This member is internal only. + /// + /// + + var matched = [], cur = elem[dir]; + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + nth: function( cur, result, dir, elem ) { + /// + /// This member is internal only. + /// + /// + + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } + } + + return cur; + }, + + sibling: function( n, elem ) { + /// + /// This member is internal only. + /// + /// + + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); +var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /(<([\w:]+)[^>]*?)\/>/g, + rselfClosing = /^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i, + rtagName = /<([\w:]+)/, + rtbody = /"; + }, + wrapMap = { + option: [ 1, "" ], + legend: [ 1, "
", "
" ], + thead: [ 1, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + col: [ 2, "", "
" ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }; + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE can't serialize and + + + " rel="stylesheet" /> + + + + + + + - +
-
- - -
+ + + + + diff --git a/XMLValidatorWeb/MasterPage.Master.designer.cs b/XMLValidatorWeb/MasterPage.Master.designer.cs index 2dc02df..11b45f0 100644 --- a/XMLValidatorWeb/MasterPage.Master.designer.cs +++ b/XMLValidatorWeb/MasterPage.Master.designer.cs @@ -39,15 +39,6 @@ public partial class MasterPage { /// protected global::System.Web.UI.HtmlControls.HtmlImage Img1; - /// - /// Img2 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.HtmlControls.HtmlImage Img2; - /// /// ContentPlaceHolder1 control. /// diff --git a/XMLValidatorWeb/Pages/AjaxHandler.ashx b/XMLValidatorWeb/Pages/AjaxHandler.ashx new file mode 100644 index 0000000..5517416 --- /dev/null +++ b/XMLValidatorWeb/Pages/AjaxHandler.ashx @@ -0,0 +1 @@ +<%@ WebHandler Language="C#" CodeBehind="AjaxHandler.ashx.cs" Class="XMLValidatorWeb.AjaxHandler" %> diff --git a/XMLValidatorWeb/Pages/AjaxHandler.ashx.cs b/XMLValidatorWeb/Pages/AjaxHandler.ashx.cs new file mode 100644 index 0000000..2089aaa --- /dev/null +++ b/XMLValidatorWeb/Pages/AjaxHandler.ashx.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using XMLValidatorWeb.SupportFiles; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; +using System.IO; +using System.Xml; +using DOEgbXML; +using log4net; + +namespace XMLValidatorWeb +{ + /// + /// Summary description for AjaxHandler + /// + public class AjaxHandler : IHttpHandler + { + private static readonly ILog logger = + LogManager.GetLogger(typeof(XMLParser)); + + public void ProcessRequest(HttpContext context) + { + var formdata = context.Request.Form; + string testcaseName = formdata["testcase"].Replace('+',' '); + string schemaversion = formdata["schema"]; + gbXMLReport gbr = new gbXMLReport(); + gbr.gbxml_testcase = testcaseName; + gbr.gbxml_version = schemaversion; + + logger.Info("Received XML file from user at UTC time " + DateTime.UtcNow); + var file = context.Request.Files[0]; + if (file.ContentType == "text/xml") + { + logger.Info("File has extension XML."); + DOEgbXMLValidator val = new DOEgbXMLValidator(schemaversion); + XMLParser parser = new XMLParser(); + //if there is a file + //valadate it by pass in input stream as xmlreader + Stream responseStream = file.InputStream; + XmlReader xmlreader = XmlReader.Create(responseStream); + + //if it is not valid + if (!val.IsValidXmlEx(xmlreader) || val.nErrors > 0 || val.nWarnings > 0) + { + //if (PrintFriendlyButton != null) + // PrintFriendlyButton.Visible = false; + + //if (DownloadLogButton != null) + // DownloadLogButton.Visible = false; + + + //setup errorlog + if (val.nErrors > 0 || val.nWarnings > 0) + { + gbr.XMLSchemaErrors = val.nErrors.ToString(); + gbr.XMLSchemaWarnings = val.nWarnings.ToString(); + logger.Info("Found " + val.nErrors + " Errors and " + val.nWarnings + " Warnings " + val.Errors); + gbr.message = val.Errors; + gbr.schema_compliance_results = "FAIL"; + gbr.detailed_compliance_results = "DID NOT ATTEMPT DUE TO SCHEMA FAILURE"; + + } + else + { + gbr.XMLSchemaWarnings = "Infinity"; + gbr.XMLSchemaErrors = "Infinity"; + + logger.Info("Your XML File is severely deficient structurally. It may be missing element tags or is not valid XML. The test has failed. " + val.BigError); + gbr.message = "Your XML File is severely deficient structurally."; + gbr.schema_compliance_results = "FAIL"; + gbr.detailed_compliance_results = "DID NOT ATTEMPT DUE TO SCHEMA FAILURE"; + } + } + else{ + //the xml itself is totally valid + gbr.schema_compliance_results = "PASS"; + gbr.message = "The XML uploaded is validated against schema " + gbr.gbxml_version; + gbr.XMLSchemaErrors = val.nErrors.ToString(); + gbr.XMLSchemaWarnings = val.nWarnings.ToString(); + + //run test + + responseStream.Position = 0; + XmlReader xmlreader2 = XmlReader.Create(responseStream); + //start test + parser.StartTest(xmlreader2, testcaseName, ref gbr); + + //see if any of the PassOverall are failed + var campusProps = gbr.CampusReport; + var surffailures = campusProps.SurfacesReport.FindAll(x => x.FoundMatch == false); + if (surffailures.Count > 0) gbr.detailed_compliance_results = "FAIL"; + var spacefailures = campusProps.SpacesReport.FindAll(x => x.FoundMatch == false); + if (spacefailures.Count > 0) gbr.detailed_compliance_results = "FAIL"; + var surfsummaryfail = campusProps.SurfacesSummary.FindAll(x => x.PassedAllTests == false); + if (surfsummaryfail.Count > 0) gbr.detailed_compliance_results = "FAIL"; + var spacesummaryfail = campusProps.SpacesSummary.FindAll(x => x.PassedAllTests == false); + if (spacesummaryfail.Count > 0) gbr.detailed_compliance_results = "FAIL"; + //TODO: building summary, stories summary + } + } + else{ + //the stuff is not even xml + logger.Info("Your file does not end in .xml"); + gbr.message = "The file does not end in .xml"; + gbr.schema_compliance_results = "FAIL"; + } + + context.Response.ContentType = "application/json"; + context.Response.Write(JsonConvert.SerializeObject(gbr)); + } + + public bool IsReusable + { + get + { + return false; + } + } + } +} \ No newline at end of file diff --git a/XMLValidatorWeb/Pages/TestPage.aspx b/XMLValidatorWeb/Pages/TestPage.aspx index fbd353f..d38377d 100644 --- a/XMLValidatorWeb/Pages/TestPage.aspx +++ b/XMLValidatorWeb/Pages/TestPage.aspx @@ -2,6 +2,7 @@ CodeBehind="TestPage.aspx.cs" Inherits="XMLValidatorWeb.Pages.TestPage" %> + @@ -11,42 +12,467 @@ w.focus(); } + + + + + + " rel="stylesheet" /> + -
-

- gbXML Validator -

-
-
- Select Which Test You Want To Run: - - -
-
- -
-
-
- Select Your XML File Here: - - - -
-
-
- -
-
- - -
- +
+
+
+ +
+
+
+

+ gbXML Vendor Certification Validator +

+
+
+ + + + + + + + + + + + + +

Select Which gbXML Schema You Wish to Test Against:

+ + +
+

Select Which Test You Want To Run:

+
+ + +
+

Select Your File for Validation:

+
+ +
+ +
+

Test Description

+
+ +
+ +
+ + + + <%--
+ Select Your XML File Here: + + + +
--%> + <%----%> + <%-- + --%> +
+
+ + + +
+
+ +
+
+ +
+ <%-- +
+ --%> +
+
+ + diff --git a/XMLValidatorWeb/Pages/TestPage.aspx.cs b/XMLValidatorWeb/Pages/TestPage.aspx.cs index 93baa69..57f8840 100644 --- a/XMLValidatorWeb/Pages/TestPage.aspx.cs +++ b/XMLValidatorWeb/Pages/TestPage.aspx.cs @@ -2,9 +2,15 @@ using System.Collections.Generic; using System.Web.UI; using System.Web.UI.WebControls; +using System.Text.RegularExpressions; using DOEgbXML; using System.Xml; using System.IO; +using System.Web.Services; +using Newtonsoft.Json.Linq; +using XMLValidatorWeb.SupportFiles; +using System.Web; +using System.Reflection; namespace XMLValidatorWeb.Pages { @@ -35,6 +41,31 @@ protected void Page_Load(object sender, EventArgs e) DropDownList1.Items.Add(new ListItem(detail.testName, detail.testName)); } + if (DropDownList2 != null) + { + string selectedValue = DropDownList2.SelectedValue; + + //clear all iteam + DropDownList2.Items.Clear(); + //get all of the available XSDs + var root = AppDomain.CurrentDomain.BaseDirectory; + var path = root + "SupportFiles//XSD"; + string[] files = Directory.GetFiles(path, "*.xsd"); + for(int i = 0; i < files.Length; i++) + files[i] = Path.GetFileName(files[i]); + + + foreach (string file in files) + //if test is the one selected before select it + if (file == selectedValue) + { + DropDownList2.Items.Add(new ListItem(file, file, true)); + DropDownList2.SelectedValue = selectedValue; + } + else + DropDownList2.Items.Add(new ListItem(file, file)); + } + if (TestSummuryLabel != null) { //show the test summary of the selected test @@ -47,155 +78,260 @@ protected void Page_Load(object sender, EventArgs e) } } - protected void upLoadButton_Click1(object sender, EventArgs e) + [WebMethod] + public static CampusReport UploadTest(HttpContext context) { - if (FileUpload1.HasFile) - { - if (FileUpload1.PostedFile.ContentType == "text/xml") - { - //if there is a file - //valadate it by pass in input stream as xmlreader - Stream responseStream = FileUpload1.PostedFile.InputStream; - XmlReader xmlreader = XmlReader.Create(responseStream); - - - //validating xml - DOEgbXMLValidator val = new DOEgbXMLValidator(); - //if it is not valid - if (!val.IsValidXmlEx(xmlreader) || val.nErrors > 0 || val.nWarnings > 0) - { - if (PrintFriendlyButton != null) - PrintFriendlyButton.Visible = false; + var r = context; + CampusReport c = new CampusReport(); + //if there is a file + //valadate it by pass in input stream as xmlreader - if (DownloadLogButton != null) - DownloadLogButton.Visible = false; + return c; + } + [WebMethod] + public static string GetResults() + { + //open log file and save as a string + try + { + var root = AppDomain.CurrentDomain.BaseDirectory; + string path = root+"log-file.txt"; + string logblog = File.ReadAllText(path); + int len = logblog.Length; + return logblog; + } + catch(Exception e) + { + return "Error: We're sorry, we could not read this test's log file. Please contact gbxml.org to report this problem."; + } + } - //setup errorlog - string errorLog = ""; - string errorDes = ""; - if (val.nErrors > 0 || val.nWarnings > 0) - { - errorLog += "

" + "Find " + val.nErrors + " Errors and " + val.nWarnings + " Warnings

" + val.Errors + "

"; - errorDes = "Find "; - if (val.nErrors > 0) - { - errorDes += val.nErrors; - if (val.nWarnings > 0) - errorDes += " Errors and"; - else - errorDes += " Errors"; - - } - if (val.nWarnings > 0) - errorDes += val.nWarnings + " Warnings"; - } - else + [WebMethod] + public static string GetErrorSummary() + { + try + { + var root = AppDomain.CurrentDomain.BaseDirectory; + string readpath = root + "log-file.txt"; + string writepath = root + "log-file-summary.txt"; + + List tempStrings = new List(); + bool write = false; + bool errors = false; + int startIndex = 0; + int linecount = 0; + foreach (string line in File.ReadLines(readpath)) + { + Match m = Regex.Match(line, "START:"); + if (m.Success) + { + startIndex = tempStrings.Count == 0 ? 0 : tempStrings.Count; //designed to keep the list short + write = true; + linecount = 0; + } + if (write) + { + tempStrings.Add(line); + linecount++; + } + Match errormatch = Regex.Match(line, "TEST FILE FAILURE|FATAL"); //removed MATCH FAILED as this is only a failure of SurfaceMatch subtests, not the whole test + if (errormatch.Success) + { + errors = true; + } + Match mend = Regex.Match(line, "END:"); + if (mend.Success) + { + if(!errors) { - errorLog += "

" + "Your XML File is severely deficient structurally. It may be missing element tags or is not valid XML. The test has failed.

" + val.BigError + "
" + "

"; - errorDes = "Your XML File is severely deficient structurally."; + tempStrings.RemoveRange(startIndex, linecount); } - // Session.Add("table", errorLog); - Session["table"] = errorLog; - - TestResultLabel.Text = ""; - - ResultSummaryLabel.Text = "

Result Summary

"; - ResultSummaryLabel.Text += "
"; - ResultSummaryLabel.Text += "" + - "" + - "" + - "" + - "" + - ""; - ResultSummaryLabel.Text += "
" + "gbXML schema Test" + "" + errorDes + "" + "Fail" + "" + "" + "More Detail" + "" + "

"; + write = false; + errors = false; } - //if it is valid - else if (val.nErrors == 0 && val.nWarnings == 0) - { - //run test - XMLParser parser = new XMLParser(); - - responseStream.Position = 0; - XmlReader xmlreader2 = XmlReader.Create(responseStream); - //start test - parser.StartTest(xmlreader2, DropDownList1.SelectedValue, Page.User.Identity.Name); - - //show summary table - ResultSummaryLabel.Text = parser.summaryTable; - - //show test section table - TestResultLabel.Text = parser.table; - - //store reportlist in session - Session["reportList"] = parser.ReportList; - + + } - LogLabel.Text = parser.log; - TableLabel.Text = parser.table; - //remove extra tag - TableLabel.Text = TableLabel.Text.Replace("", ""); - TableLabel.Text = TableLabel.Text.Replace("", ""); - TableLabel.Text = TableLabel.Text.Replace("", "
"); - DownloadLogButton.Visible = true; - PrintFriendlyButton.Visible = true; - } - //this should never happens - else + if(tempStrings.Count > 0) + { + using (StreamWriter writetext = new StreamWriter(writepath)) { - ResultSummaryLabel.Text = "?????????something is very wrong"; - TestResultLabel.Text = ""; + foreach (string line in tempStrings) + { + writetext.WriteLine(line); + } } + readpath = writepath; + string logsummary = File.ReadAllText(readpath); + return logsummary; } - //if the file type is not xml else { - if (PrintFriendlyButton != null) - PrintFriendlyButton.Visible = false; - - if (DownloadLogButton != null) - DownloadLogButton.Visible = false; - - ResultSummaryLabel.Text = ""; - TestResultLabel.Text = ""; - - ResultSummaryLabel.Text = "

Result Summary

"; - ResultSummaryLabel.Text += "
"; - ResultSummaryLabel.Text += "" + - "" + - "" + - "" + - - ""; - ResultSummaryLabel.Text += "
" + "gbXML schema Test" + "" + "You have not specified a right type of file." + "" + "Fail" + "

"; + return "Note for user. There are no errors to report!"; } + + } - //if there is no file - else + catch(Exception e) { - if (PrintFriendlyButton != null) - PrintFriendlyButton.Visible = false; - - if (DownloadLogButton != null) - DownloadLogButton.Visible = false; - - - ResultSummaryLabel.Text = ""; - TestResultLabel.Text = ""; - - ResultSummaryLabel.Text = "

Result Summary

"; - ResultSummaryLabel.Text += ""; - ResultSummaryLabel.Text += "" + - "" + - "" + - "" + - ""; - ResultSummaryLabel.Text += "
" + "gbXML schema Test" + "" + "You have not specified a file." + "" + "Fail" + "

"; - + return "Error: We're sorry, we could not read this test's log file. Please contact gbxml.org to report this problem."; } } + //protected void upLoadButton_Click1(object sender, EventArgs e) + //{ + // if (FileUpload1.HasFile) + // { + // if (FileUpload1.PostedFile.ContentType == "text/xml") + // { + // //if there is a file + // //valadate it by pass in input stream as xmlreader + // Stream responseStream = FileUpload1.PostedFile.InputStream; + // XmlReader xmlreader = XmlReader.Create(responseStream); + + + // //initialize instances for testing + // DOEgbXMLValidator val = new DOEgbXMLValidator(); + // XMLParser parser = new XMLParser(); + // //if it is not valid + // if (!val.IsValidXmlEx(xmlreader) || val.nErrors > 0 || val.nWarnings > 0) + // { + // if (PrintFriendlyButton != null) + // PrintFriendlyButton.Visible = false; + + // if (DownloadLogButton != null) + // DownloadLogButton.Visible = false; + + + // //setup errorlog + // string errorLog = ""; + // string errorDes = ""; + // if (val.nErrors > 0 || val.nWarnings > 0) + // { + // errorLog += "

" + "Find " + val.nErrors + " Errors and " + val.nWarnings + " Warnings

" + val.Errors + "

"; + // errorDes = "Find "; + // if (val.nErrors > 0) + // { + // errorDes += val.nErrors; + // if (val.nWarnings > 0) + // errorDes += " Errors and"; + // else + // errorDes += " Errors"; + + // } + // if (val.nWarnings > 0) + // errorDes += val.nWarnings + " Warnings"; + // } + // else + // { + // errorLog += "

" + "Your XML File is severely deficient structurally. It may be missing element tags or is not valid XML. The test has failed.

" + val.BigError + "
" + "

"; + // errorDes = "Your XML File is severely deficient structurally."; + // } + // // Session.Add("table", errorLog); + // Session["table"] = errorLog; + + // TestResultLabel.Text = ""; + + // ResultSummaryLabel.Text = "

Result Summary

"; + // ResultSummaryLabel.Text += "
"; + // ResultSummaryLabel.Text += "" + + // "" + + // "" + + // "" + + // "" + + // ""; + // ResultSummaryLabel.Text += "
" + "gbXML schema Test" + "" + errorDes + "" + "Fail" + "" + "" + "More Detail" + "" + "

"; + // } + // //if it is valid + // else if (val.nErrors == 0 && val.nWarnings == 0) + // { + // //run test + + // responseStream.Position = 0; + // XmlReader xmlreader2 = XmlReader.Create(responseStream); + // //start test + // parser.StartTest(xmlreader2, DropDownList1.SelectedValue, Page.User.Identity.Name); + + // string results = parser.browserjson; + // results = results.Replace(@"\", @"\\"); + // ClientScriptManager cs = Page.ClientScript; + // cs.RegisterStartupScript(GetType(), "Startup", "init('" + results + "');", true); + // //show summary table + // ResultSummaryLabel.Text = parser.summaryTable; + + // //show test section table + // TestResultLabel.Text = parser.table; + + // //store reportlist in session + // Session["reportList"] = parser.ReportList; + + + // LogLabel.Text = parser.log; + // TableLabel.Text = parser.table; + // //remove extra tag + // //TableLabel.Text = TableLabel.Text.Replace("", ""); + // //TableLabel.Text = TableLabel.Text.Replace("", ""); + // //TableLabel.Text = TableLabel.Text.Replace("", "
"); + // //DownloadLogButton.Visible = true; + // //PrintFriendlyButton.Visible = true; + // } + // //this should never happens + // else + // { + // ResultSummaryLabel.Text = "?????????something is very wrong"; + // TestResultLabel.Text = ""; + // } + + // } + // //if the file type is not xml + // else + // { + // if (PrintFriendlyButton != null) + // PrintFriendlyButton.Visible = false; + + // if (DownloadLogButton != null) + // DownloadLogButton.Visible = false; + + // ResultSummaryLabel.Text = ""; + // TestResultLabel.Text = ""; + + // ResultSummaryLabel.Text = "

Result Summary

"; + // ResultSummaryLabel.Text += "
"; + // ResultSummaryLabel.Text += "" + + // "" + + // "" + + // "" + + + // ""; + // ResultSummaryLabel.Text += "
" + "gbXML schema Test" + "" + "You have not specified a right type of file." + "" + "Fail" + "

"; + // } + // } + // //if there is no file + // else + // { + // if (PrintFriendlyButton != null) + // PrintFriendlyButton.Visible = false; + + // if (DownloadLogButton != null) + // DownloadLogButton.Visible = false; + + + // ResultSummaryLabel.Text = ""; + // TestResultLabel.Text = ""; + + // ResultSummaryLabel.Text = "

Result Summary

"; + // ResultSummaryLabel.Text += ""; + // ResultSummaryLabel.Text += "" + + // "" + + // "" + + // "" + + // ""; + // ResultSummaryLabel.Text += "
" + "gbXML schema Test" + "" + "You have not specified a file." + "" + "Fail" + "

"; + + // } + //} protected void DownloadLogButton_Click(object sender, EventArgs e) @@ -218,17 +354,29 @@ protected void PrintFriendlyButton_Click(object sender, EventArgs e) ClientScript.RegisterStartupScript(this.GetType(), "OpenWindow", ""); } + //TODO: REMOVE? protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e) { //if change the selected index clear all labels - ResultSummaryLabel.Text = ""; - TestResultLabel.Text = ""; - LogLabel.Text = ""; - TableLabel.Text = ""; - DownloadLogButton.Visible = false; - PrintFriendlyButton.Visible = false; + //ResultSummaryLabel.Text = ""; + //TestResultLabel.Text = ""; + //LogLabel.Text = ""; + //TableLabel.Text = ""; + //DownloadLogButton.Visible = false; + //PrintFriendlyButton.Visible = false; } + //TODO: REMOVE? + protected void DropDownList2_SelectedIndexChanged(object sender, EventArgs e) + { + //if change the selected index clear all labels + //ResultSummaryLabel.Text = ""; + //TestResultLabel.Text = ""; + //LogLabel.Text = ""; + //TableLabel.Text = ""; + //DownloadLogButton.Visible = false; + //PrintFriendlyButton.Visible = false; + } } } \ No newline at end of file diff --git a/XMLValidatorWeb/Pages/TestPage.aspx.designer.cs b/XMLValidatorWeb/Pages/TestPage.aspx.designer.cs index 9c38366..9a46972 100644 --- a/XMLValidatorWeb/Pages/TestPage.aspx.designer.cs +++ b/XMLValidatorWeb/Pages/TestPage.aspx.designer.cs @@ -13,76 +13,31 @@ namespace XMLValidatorWeb.Pages { public partial class TestPage { /// - /// DropDownList1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.DropDownList DropDownList1; - - /// - /// TestSummuryLabel control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.Label TestSummuryLabel; - - /// - /// FileUpload1 control. + /// DropDownList2 control. /// /// /// Auto-generated field. /// To modify move field declaration from designer file to code-behind file. /// - protected global::System.Web.UI.WebControls.FileUpload FileUpload1; + protected global::System.Web.UI.WebControls.DropDownList DropDownList2; /// - /// DownloadLogButton control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.Button DownloadLogButton; - - /// - /// PrintFriendlyButton control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.Button PrintFriendlyButton; - - /// - /// upLoadButton control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.Button upLoadButton; - - /// - /// ResultSummaryLabel control. + /// DropDownList1 control. /// /// /// Auto-generated field. /// To modify move field declaration from designer file to code-behind file. /// - protected global::System.Web.UI.WebControls.Label ResultSummaryLabel; + protected global::System.Web.UI.WebControls.DropDownList DropDownList1; /// - /// TestResultLabel control. + /// TestSummuryLabel control. /// /// /// Auto-generated field. /// To modify move field declaration from designer file to code-behind file. /// - protected global::System.Web.UI.WebControls.Label TestResultLabel; + protected global::System.Web.UI.WebControls.Label TestSummuryLabel; /// /// LogLabel control. diff --git a/XMLValidatorWeb/Scripts/FileSaver.js b/XMLValidatorWeb/Scripts/FileSaver.js new file mode 100644 index 0000000..239db12 --- /dev/null +++ b/XMLValidatorWeb/Scripts/FileSaver.js @@ -0,0 +1,188 @@ +/* FileSaver.js + * A saveAs() FileSaver implementation. + * 1.3.2 + * 2016-06-16 18:25:19 + * + * By Eli Grey, http://eligrey.com + * License: MIT + * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md + */ + +/*global self */ +/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ + +/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ + +var saveAs = saveAs || (function(view) { + "use strict"; + // IE <10 is explicitly unsupported + if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) { + return; + } + var + doc = view.document + // only get URL when necessary in case Blob.js hasn't overridden it yet + , get_URL = function() { + return view.URL || view.webkitURL || view; + } + , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") + , can_use_save_link = "download" in save_link + , click = function(node) { + var event = new MouseEvent("click"); + node.dispatchEvent(event); + } + , is_safari = /constructor/i.test(view.HTMLElement) + , is_chrome_ios =/CriOS\/[\d]+/.test(navigator.userAgent) + , throw_outside = function(ex) { + (view.setImmediate || view.setTimeout)(function() { + throw ex; + }, 0); + } + , force_saveable_type = "application/octet-stream" + // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to + , arbitrary_revoke_timeout = 1000 * 40 // in ms + , revoke = function(file) { + var revoker = function() { + if (typeof file === "string") { // file is an object URL + get_URL().revokeObjectURL(file); + } else { // file is a File + file.remove(); + } + }; + setTimeout(revoker, arbitrary_revoke_timeout); + } + , dispatch = function(filesaver, event_types, event) { + event_types = [].concat(event_types); + var i = event_types.length; + while (i--) { + var listener = filesaver["on" + event_types[i]]; + if (typeof listener === "function") { + try { + listener.call(filesaver, event || filesaver); + } catch (ex) { + throw_outside(ex); + } + } + } + } + , auto_bom = function(blob) { + // prepend BOM for UTF-8 XML and text/* types (including HTML) + // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF + if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { + return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type}); + } + return blob; + } + , FileSaver = function(blob, name, no_auto_bom) { + if (!no_auto_bom) { + blob = auto_bom(blob); + } + // First try a.download, then web filesystem, then object URLs + var + filesaver = this + , type = blob.type + , force = type === force_saveable_type + , object_url + , dispatch_all = function() { + dispatch(filesaver, "writestart progress write writeend".split(" ")); + } + // on any filesys errors revert to saving with object URLs + , fs_error = function() { + if ((is_chrome_ios || (force && is_safari)) && view.FileReader) { + // Safari doesn't allow downloading of blob urls + var reader = new FileReader(); + reader.onloadend = function() { + var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;'); + var popup = view.open(url, '_blank'); + if(!popup) view.location.href = url; + url=undefined; // release reference before dispatching + filesaver.readyState = filesaver.DONE; + dispatch_all(); + }; + reader.readAsDataURL(blob); + filesaver.readyState = filesaver.INIT; + return; + } + // don't create more object URLs than needed + if (!object_url) { + object_url = get_URL().createObjectURL(blob); + } + if (force) { + view.location.href = object_url; + } else { + var opened = view.open(object_url, "_blank"); + if (!opened) { + // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html + view.location.href = object_url; + } + } + filesaver.readyState = filesaver.DONE; + dispatch_all(); + revoke(object_url); + } + ; + filesaver.readyState = filesaver.INIT; + + if (can_use_save_link) { + object_url = get_URL().createObjectURL(blob); + setTimeout(function() { + save_link.href = object_url; + save_link.download = name; + click(save_link); + dispatch_all(); + revoke(object_url); + filesaver.readyState = filesaver.DONE; + }); + return; + } + + fs_error(); + } + , FS_proto = FileSaver.prototype + , saveAs = function(blob, name, no_auto_bom) { + return new FileSaver(blob, name || blob.name || "download", no_auto_bom); + } + ; + // IE 10+ (native saveAs) + if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) { + return function(blob, name, no_auto_bom) { + name = name || blob.name || "download"; + + if (!no_auto_bom) { + blob = auto_bom(blob); + } + return navigator.msSaveOrOpenBlob(blob, name); + }; + } + + FS_proto.abort = function(){}; + FS_proto.readyState = FS_proto.INIT = 0; + FS_proto.WRITING = 1; + FS_proto.DONE = 2; + + FS_proto.error = + FS_proto.onwritestart = + FS_proto.onprogress = + FS_proto.onwrite = + FS_proto.onabort = + FS_proto.onerror = + FS_proto.onwriteend = + null; + + return saveAs; +}( + typeof self !== "undefined" && self + || typeof window !== "undefined" && window + || this.content +)); +// `self` is undefined in Firefox for Android content script context +// while `this` is nsIContentFrameMessageManager +// with an attribute `content` that corresponds to the window + +if (typeof module !== "undefined" && module.exports) { + module.exports.saveAs = saveAs; +} else if ((typeof define !== "undefined" && define !== null) && (define.amd !== null)) { + define([], function() { + return saveAs; + }); +} diff --git a/XMLValidatorWeb/Scripts/jquery-1.4.1-vsdoc.js b/XMLValidatorWeb/Scripts/jquery-1.4.1-vsdoc.js deleted file mode 100644 index 681241d..0000000 --- a/XMLValidatorWeb/Scripts/jquery-1.4.1-vsdoc.js +++ /dev/null @@ -1,8061 +0,0 @@ -/* - * This file has been commented to support Visual Studio Intellisense. - * You should not use this file at runtime inside the browser--it is only - * intended to be used only for design-time IntelliSense. Please use the - * standard jQuery library for all production use. - * - * Comment version: 1.4.1a - */ - -/*! - * jQuery JavaScript Library v1.4.1 - * http://jquery.com/ - * - * Distributed in whole under the terms of the MIT - * - * Copyright 2010, John Resig - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2010, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Mon Jan 25 19:43:33 2010 -0500 - */ - -(function( window, undefined ) { - -// Define a local copy of jQuery -var jQuery = function( selector, context ) { - /// - /// 1: $(expression, context) - This function accepts a string containing a CSS selector which is then used to match a set of elements. - /// 2: $(html) - Create DOM elements on-the-fly from the provided String of raw HTML. - /// 3: $(elements) - Wrap jQuery functionality around a single or multiple DOM Element(s). - /// 4: $(callback) - A shorthand for $(document).ready(). - /// 5: $() - As of jQuery 1.4, if you pass no arguments in to the jQuery() method, an empty jQuery set will be returned. - /// - /// - /// 1: expression - An expression to search with. - /// 2: html - A string of HTML to create on the fly. - /// 3: elements - DOM element(s) to be encapsulated by a jQuery object. - /// 4: callback - The function to execute when the DOM is ready. - /// - /// - /// 1: context - A DOM Element, Document or jQuery to use as context. - /// - /// - - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.fn.init( selector, context ); - }, - - // Map over jQuery in case of overwrite - _jQuery = window.jQuery, - - // Map over the $ in case of overwrite - _$ = window.$, - - // Use the correct document accordingly with window argument (sandbox) - document = window.document, - - // A central reference to the root jQuery(document) - rootjQuery, - - // A simple way to check for HTML strings or ID strings - // (both of which we optimize for) - quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/, - - // Is it a simple selector - isSimple = /^.[^:#\[\.,]*$/, - - // Check if a string has a non-whitespace character in it - rnotwhite = /\S/, - - // Used for trimming whitespace - rtrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g, - - // Match a standalone tag - rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, - - // Keep a UserAgent string for use with jQuery.browser - userAgent = navigator.userAgent, - - // For matching the engine and version of the browser - browserMatch, - - // Has the ready events already been bound? - readyBound = false, - - // The functions to execute on DOM ready - readyList = [], - - // The ready event handler - DOMContentLoaded, - - // Save a reference to some core methods - toString = Object.prototype.toString, - hasOwnProperty = Object.prototype.hasOwnProperty, - push = Array.prototype.push, - slice = Array.prototype.slice, - indexOf = Array.prototype.indexOf; - -jQuery.fn = jQuery.prototype = { - init: function( selector, context ) { - - var match, elem, ret, doc; - - // Handle $(""), $(null), or $(undefined) - if ( !selector ) { - return this; - } - - // Handle $(DOMElement) - if ( selector.nodeType ) { - this.context = this[0] = selector; - this.length = 1; - return this; - } - - // Handle HTML strings - if ( typeof selector === "string" ) { - // Are we dealing with HTML string or an ID? - match = quickExpr.exec( selector ); - - // Verify a match, and that no context was specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - doc = (context ? context.ownerDocument || context : document); - - // If a single string is passed in and it's a single tag - // just do a createElement and skip the rest - ret = rsingleTag.exec( selector ); - - if ( ret ) { - if ( jQuery.isPlainObject( context ) ) { - selector = [ document.createElement( ret[1] ) ]; - jQuery.fn.attr.call( selector, context, true ); - - } else { - selector = [ doc.createElement( ret[1] ) ]; - } - - } else { - ret = buildFragment( [ match[1] ], [ doc ] ); - selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes; - } - - // HANDLE: $("#id") - } else { - elem = document.getElementById( match[2] ); - - if ( elem ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id !== match[2] ) { - return rootjQuery.find( selector ); - } - - // Otherwise, we inject the element directly into the jQuery object - this.length = 1; - this[0] = elem; - } - - this.context = document; - this.selector = selector; - return this; - } - - // HANDLE: $("TAG") - } else if ( !context && /^\w+$/.test( selector ) ) { - this.selector = selector; - this.context = document; - selector = document.getElementsByTagName( selector ); - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return (context || rootjQuery).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return jQuery( context ).find( selector ); - } - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return rootjQuery.ready( selector ); - } - - if (selector.selector !== undefined) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.isArray( selector ) ? - this.setArray( selector ) : - jQuery.makeArray( selector, this ); - }, - - // Start with an empty selector - selector: "", - - // The current version of jQuery being used - jquery: "1.4.1", - - // The default length of a jQuery object is 0 - length: 0, - - // The number of elements contained in the matched element set - size: function() { - /// - /// The number of elements currently matched. - /// Part of Core - /// - /// - - return this.length; - }, - - toArray: function() { - /// - /// Retrieve all the DOM elements contained in the jQuery set, as an array. - /// - /// - return slice.call( this, 0 ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - /// - /// Access a single matched element. num is used to access the - /// Nth element matched. - /// Part of Core - /// - /// - /// - /// Access the element in the Nth position. - /// - - return num == null ? - - // Return a 'clean' array - this.toArray() : - - // Return just the object - ( num < 0 ? this.slice(num)[ 0 ] : this[ num ] ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems, name, selector ) { - /// - /// Set the jQuery object to an array of elements, while maintaining - /// the stack. - /// Part of Core - /// - /// - /// - /// An array of elements - /// - - // Build a new jQuery matched element set - var ret = jQuery( elems || null ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - ret.context = this.context; - - if ( name === "find" ) { - ret.selector = this.selector + (this.selector ? " " : "") + selector; - } else if ( name ) { - ret.selector = this.selector + "." + name + "(" + selector + ")"; - } - - // Return the newly-formed element set - return ret; - }, - - // Force the current matched set of elements to become - // the specified array of elements (destroying the stack in the process) - // You should use pushStack() in order to do this, but maintain the stack - setArray: function( elems ) { - /// - /// Set the jQuery object to an array of elements. This operation is - /// completely destructive - be sure to use .pushStack() if you wish to maintain - /// the jQuery stack. - /// Part of Core - /// - /// - /// - /// An array of elements - /// - - // Resetting the length to 0, then using the native Array push - // is a super-fast way to populate an object with array-like properties - this.length = 0; - push.apply( this, elems ); - - return this; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - /// - /// Execute a function within the context of every matched element. - /// This means that every time the passed-in function is executed - /// (which is once for every element matched) the 'this' keyword - /// points to the specific element. - /// Additionally, the function, when executed, is passed a single - /// argument representing the position of the element in the matched - /// set. - /// Part of Core - /// - /// - /// - /// A function to execute - /// - - return jQuery.each( this, callback, args ); - }, - - ready: function( fn ) { - /// - /// Binds a function to be executed whenever the DOM is ready to be traversed and manipulated. - /// - /// The function to be executed when the DOM is ready. - - // Attach the listeners - jQuery.bindReady(); - - // If the DOM is already ready - if ( jQuery.isReady ) { - // Execute the function immediately - fn.call( document, jQuery ); - - // Otherwise, remember the function for later - } else if ( readyList ) { - // Add the function to the wait list - readyList.push( fn ); - } - - return this; - }, - - eq: function( i ) { - /// - /// Reduce the set of matched elements to a single element. - /// The position of the element in the set of matched elements - /// starts at 0 and goes to length - 1. - /// Part of Core - /// - /// - /// - /// pos The index of the element that you wish to limit to. - /// - - return i === -1 ? - this.slice( i ) : - this.slice( i, +i + 1 ); - }, - - first: function() { - /// - /// Reduce the set of matched elements to the first in the set. - /// - /// - - return this.eq( 0 ); - }, - - last: function() { - /// - /// Reduce the set of matched elements to the final one in the set. - /// - /// - - return this.eq( -1 ); - }, - - slice: function() { - /// - /// Selects a subset of the matched elements. Behaves exactly like the built-in Array slice method. - /// - /// Where to start the subset (0-based). - /// Where to end the subset (not including the end element itself). - /// If omitted, ends at the end of the selection - /// The sliced elements - - return this.pushStack( slice.apply( this, arguments ), - "slice", slice.call(arguments).join(",") ); - }, - - map: function( callback ) { - /// - /// This member is internal. - /// - /// - /// - - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, - - end: function() { - /// - /// End the most recent 'destructive' operation, reverting the list of matched elements - /// back to its previous state. After an end operation, the list of matched elements will - /// revert to the last state of matched elements. - /// If there was no destructive operation before, an empty set is returned. - /// Part of DOM/Traversing - /// - /// - - return this.prevObject || jQuery(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: [].sort, - splice: [].splice -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.fn.init.prototype = jQuery.fn; - -jQuery.extend = jQuery.fn.extend = function() { - /// - /// Extend one object with one or more others, returning the original, - /// modified, object. This is a great utility for simple inheritance. - /// jQuery.extend(settings, options); - /// var settings = jQuery.extend({}, defaults, options); - /// Part of JavaScript - /// - /// - /// The object to extend - /// - /// - /// The object that will be merged into the first. - /// - /// - /// (optional) More objects to merge into the first - /// - /// - - // copy reference to target object - var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( length === i ) { - target = this; - --i; - } - - for ( ; i < length; i++ ) { - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging object literal values or arrays - if ( deep && copy && ( jQuery.isPlainObject(copy) || jQuery.isArray(copy) ) ) { - var clone = src && ( jQuery.isPlainObject(src) || jQuery.isArray(src) ) ? src - : jQuery.isArray(copy) ? [] : {}; - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend({ - noConflict: function( deep ) { - /// - /// Run this function to give control of the $ variable back - /// to whichever library first implemented it. This helps to make - /// sure that jQuery doesn't conflict with the $ object - /// of other libraries. - /// By using this function, you will only be able to access jQuery - /// using the 'jQuery' variable. For example, where you used to do - /// $("div p"), you now must do jQuery("div p"). - /// Part of Core - /// - /// - - window.$ = _$; - - if ( deep ) { - window.jQuery = _jQuery; - } - - return jQuery; - }, - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // Handle when the DOM is ready - ready: function() { - /// - /// This method is internal. - /// - /// - - // Make sure that the DOM is not already loaded - if ( !jQuery.isReady ) { - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( !document.body ) { - return setTimeout( jQuery.ready, 13 ); - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If there are functions bound, to execute - if ( readyList ) { - // Execute all of them - var fn, i = 0; - while ( (fn = readyList[ i++ ]) ) { - fn.call( document, jQuery ); - } - - // Reset the list of functions - readyList = null; - } - - // Trigger any bound ready events - if ( jQuery.fn.triggerHandler ) { - jQuery( document ).triggerHandler( "ready" ); - } - } - }, - - bindReady: function() { - if ( readyBound ) { - return; - } - - readyBound = true; - - // Catch cases where $(document).ready() is called after the - // browser event has already occurred. - if ( document.readyState === "complete" ) { - return jQuery.ready(); - } - - // Mozilla, Opera and webkit nightlies currently support this event - if ( document.addEventListener ) { - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", jQuery.ready, false ); - - // If IE event model is used - } else if ( document.attachEvent ) { - // ensure firing before onload, - // maybe late but safe also for iframes - document.attachEvent("onreadystatechange", DOMContentLoaded); - - // A fallback to window.onload, that will always work - window.attachEvent( "onload", jQuery.ready ); - - // If IE and not a frame - // continually check to see if the document is ready - var toplevel = false; - - try { - toplevel = window.frameElement == null; - } catch(e) {} - - if ( document.documentElement.doScroll && toplevel ) { - doScrollCheck(); - } - } - }, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - /// - /// Determines if the parameter passed is a function. - /// - /// The object to check - /// True if the parameter is a function; otherwise false. - - return toString.call(obj) === "[object Function]"; - }, - - isArray: function( obj ) { - /// - /// Determine if the parameter passed is an array. - /// - /// Object to test whether or not it is an array. - /// True if the parameter is a function; otherwise false. - - return toString.call(obj) === "[object Array]"; - }, - - isPlainObject: function( obj ) { - /// - /// Check to see if an object is a plain object (created using "{}" or "new Object"). - /// - /// - /// The object that will be checked to see if it's a plain object. - /// - /// - - // Must be an Object. - // Because of IE, we also have to check the presence of the constructor property. - // Make sure that DOM nodes and window objects don't pass through, as well - if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) { - return false; - } - - // Not own constructor property must be Object - if ( obj.constructor - && !hasOwnProperty.call(obj, "constructor") - && !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) { - return false; - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - - var key; - for ( key in obj ) {} - - return key === undefined || hasOwnProperty.call( obj, key ); - }, - - isEmptyObject: function( obj ) { - /// - /// Check to see if an object is empty (contains no properties). - /// - /// - /// The object that will be checked to see if it's empty. - /// - /// - - for ( var name in obj ) { - return false; - } - return true; - }, - - error: function( msg ) { - throw msg; - }, - - parseJSON: function( data ) { - if ( typeof data !== "string" || !data ) { - return null; - } - - // Make sure the incoming data is actual JSON - // Logic borrowed from http://json.org/json2.js - if ( /^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@") - .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]") - .replace(/(?:^|:|,)(?:\s*\[)+/g, "")) ) { - - // Try to use the native JSON parser first - return window.JSON && window.JSON.parse ? - window.JSON.parse( data ) : - (new Function("return " + data))(); - - } else { - jQuery.error( "Invalid JSON: " + data ); - } - }, - - noop: function() { - /// - /// An empty function. - /// - /// - }, - - // Evalulates a script in a global context - globalEval: function( data ) { - /// - /// Internally evaluates a script in a global context. - /// - /// - - if ( data && rnotwhite.test(data) ) { - // Inspired by code by Andrea Giammarchi - // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html - var head = document.getElementsByTagName("head")[0] || document.documentElement, - script = document.createElement("script"); - - script.type = "text/javascript"; - - if ( jQuery.support.scriptEval ) { - script.appendChild( document.createTextNode( data ) ); - } else { - script.text = data; - } - - // Use insertBefore instead of appendChild to circumvent an IE6 bug. - // This arises when a base node is used (#2709). - head.insertBefore( script, head.firstChild ); - head.removeChild( script ); - } - }, - - nodeName: function( elem, name ) { - /// - /// Checks whether the specified element has the specified DOM node name. - /// - /// The element to examine - /// The node name to check - /// True if the specified node name matches the node's DOM node name; otherwise false - - return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); - }, - - // args is for internal usage only - each: function( object, callback, args ) { - /// - /// A generic iterator function, which can be used to seemlessly - /// iterate over both objects and arrays. This function is not the same - /// as $().each() - which is used to iterate, exclusively, over a jQuery - /// object. This function can be used to iterate over anything. - /// The callback has two arguments:the key (objects) or index (arrays) as first - /// the first, and the value as the second. - /// Part of JavaScript - /// - /// - /// The object, or array, to iterate over. - /// - /// - /// The function that will be executed on every object. - /// - /// - - var name, i = 0, - length = object.length, - isObj = length === undefined || jQuery.isFunction(object); - - if ( args ) { - if ( isObj ) { - for ( name in object ) { - if ( callback.apply( object[ name ], args ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.apply( object[ i++ ], args ) === false ) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if ( isObj ) { - for ( name in object ) { - if ( callback.call( object[ name ], name, object[ name ] ) === false ) { - break; - } - } - } else { - for ( var value = object[0]; - i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {} - } - } - - return object; - }, - - trim: function( text ) { - /// - /// Remove the whitespace from the beginning and end of a string. - /// Part of JavaScript - /// - /// - /// - /// The string to trim. - /// - - return (text || "").replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( array, results ) { - /// - /// Turns anything into a true array. This is an internal method. - /// - /// Anything to turn into an actual Array - /// - /// - - var ret = results || []; - - if ( array != null ) { - // The window, strings (and functions) also have 'length' - // The extra typeof function check is to prevent crashes - // in Safari 2 (See: #3039) - if ( array.length == null || typeof array === "string" || jQuery.isFunction(array) || (typeof array !== "function" && array.setInterval) ) { - push.call( ret, array ); - } else { - jQuery.merge( ret, array ); - } - } - - return ret; - }, - - inArray: function( elem, array ) { - if ( array.indexOf ) { - return array.indexOf( elem ); - } - - for ( var i = 0, length = array.length; i < length; i++ ) { - if ( array[ i ] === elem ) { - return i; - } - } - - return -1; - }, - - merge: function( first, second ) { - /// - /// Merge two arrays together, removing all duplicates. - /// The new array is: All the results from the first array, followed - /// by the unique results from the second array. - /// Part of JavaScript - /// - /// - /// - /// The first array to merge. - /// - /// - /// The second array to merge. - /// - - var i = first.length, j = 0; - - if ( typeof second.length === "number" ) { - for ( var l = second.length; j < l; j++ ) { - first[ i++ ] = second[ j ]; - } - } else { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, inv ) { - /// - /// Filter items out of an array, by using a filter function. - /// The specified function will be passed two arguments: The - /// current array item and the index of the item in the array. The - /// function must return 'true' to keep the item in the array, - /// false to remove it. - /// }); - /// Part of JavaScript - /// - /// - /// - /// array The Array to find items in. - /// - /// - /// The function to process each item against. - /// - /// - /// Invert the selection - select the opposite of the function. - /// - - var ret = []; - - // Go through the array, only saving the items - // that pass the validator function - for ( var i = 0, length = elems.length; i < length; i++ ) { - if ( !inv !== !callback( elems[ i ], i ) ) { - ret.push( elems[ i ] ); - } - } - - return ret; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - /// - /// Translate all items in an array to another array of items. - /// The translation function that is provided to this method is - /// called for each item in the array and is passed one argument: - /// The item to be translated. - /// The function can then return the translated value, 'null' - /// (to remove the item), or an array of values - which will - /// be flattened into the full array. - /// Part of JavaScript - /// - /// - /// - /// array The Array to translate. - /// - /// - /// The function to process each item against. - /// - - var ret = [], value; - - // Go through the array, translating each of the items to their - // new value (or values). - for ( var i = 0, length = elems.length; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - - return ret.concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - proxy: function( fn, proxy, thisObject ) { - /// - /// Takes a function and returns a new one that will always have a particular scope. - /// - /// - /// The function whose scope will be changed. - /// - /// - /// The object to which the scope of the function should be set. - /// - /// - - if ( arguments.length === 2 ) { - if ( typeof proxy === "string" ) { - thisObject = fn; - fn = thisObject[ proxy ]; - proxy = undefined; - - } else if ( proxy && !jQuery.isFunction( proxy ) ) { - thisObject = proxy; - proxy = undefined; - } - } - - if ( !proxy && fn ) { - proxy = function() { - return fn.apply( thisObject || this, arguments ); - }; - } - - // Set the guid of unique handler to the same of original handler, so it can be removed - if ( fn ) { - proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; - } - - // So proxy can be declared as an argument - return proxy; - }, - - // Use of jQuery.browser is frowned upon. - // More details: http://docs.jquery.com/Utilities/jQuery.browser - uaMatch: function( ua ) { - ua = ua.toLowerCase(); - - var match = /(webkit)[ \/]([\w.]+)/.exec( ua ) || - /(opera)(?:.*version)?[ \/]([\w.]+)/.exec( ua ) || - /(msie) ([\w.]+)/.exec( ua ) || - !/compatible/.test( ua ) && /(mozilla)(?:.*? rv:([\w.]+))?/.exec( ua ) || - []; - - return { browser: match[1] || "", version: match[2] || "0" }; - }, - - browser: {} -}); - -browserMatch = jQuery.uaMatch( userAgent ); -if ( browserMatch.browser ) { - jQuery.browser[ browserMatch.browser ] = true; - jQuery.browser.version = browserMatch.version; -} - -// Deprecated, use jQuery.browser.webkit instead -if ( jQuery.browser.webkit ) { - jQuery.browser.safari = true; -} - -if ( indexOf ) { - jQuery.inArray = function( elem, array ) { - /// - /// Determines the index of the first parameter in the array. - /// - /// The value to see if it exists in the array. - /// The array to look through for the value - /// The 0-based index of the item if it was found, otherwise -1. - - return indexOf.call( array, elem ); - }; -} - -// All jQuery objects should point back to these -rootjQuery = jQuery(document); - -// Cleanup functions for the document ready method -if ( document.addEventListener ) { - DOMContentLoaded = function() { - document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - jQuery.ready(); - }; - -} else if ( document.attachEvent ) { - DOMContentLoaded = function() { - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( document.readyState === "complete" ) { - document.detachEvent( "onreadystatechange", DOMContentLoaded ); - jQuery.ready(); - } - }; -} - -// The DOM ready check for Internet Explorer -function doScrollCheck() { - if ( jQuery.isReady ) { - return; - } - - try { - // If IE is used, use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - document.documentElement.doScroll("left"); - } catch( error ) { - setTimeout( doScrollCheck, 1 ); - return; - } - - // and execute any waiting functions - jQuery.ready(); -} - -function evalScript( i, elem ) { - /// - /// This method is internal. - /// - /// - - if ( elem.src ) { - jQuery.ajax({ - url: elem.src, - async: false, - dataType: "script" - }); - } else { - jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); - } - - if ( elem.parentNode ) { - elem.parentNode.removeChild( elem ); - } -} - -// Mutifunctional method to get and set values to a collection -// The value/s can be optionally by executed if its a function -function access( elems, key, value, exec, fn, pass ) { - var length = elems.length; - - // Setting many attributes - if ( typeof key === "object" ) { - for ( var k in key ) { - access( elems, k, key[k], exec, fn, value ); - } - return elems; - } - - // Setting one attribute - if ( value !== undefined ) { - // Optionally, function values get executed if exec is true - exec = !pass && exec && jQuery.isFunction(value); - - for ( var i = 0; i < length; i++ ) { - fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); - } - - return elems; - } - - // Getting an attribute - return length ? fn( elems[0], key ) : null; -} - -function now() { - /// - /// Gets the current date. - /// - /// The current date. - - return (new Date).getTime(); -} - -// [vsdoc] The following function has been modified for IntelliSense. -// [vsdoc] Stubbing support properties to "false" for IntelliSense compat. -(function() { - - jQuery.support = {}; - - // var root = document.documentElement, - // script = document.createElement("script"), - // div = document.createElement("div"), - // id = "script" + now(); - - // div.style.display = "none"; - // div.innerHTML = "
a"; - - // var all = div.getElementsByTagName("*"), - // a = div.getElementsByTagName("a")[0]; - - // // Can't get basic test support - // if ( !all || !all.length || !a ) { - // return; - // } - - jQuery.support = { - // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: false, - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - tbody: false, - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - htmlSerialize: false, - - // Get the style information from getAttribute - // (IE uses .cssText insted) - style: false, - - // Make sure that URLs aren't manipulated - // (IE normalizes it by default) - hrefNormalized: false, - - // Make sure that element opacity exists - // (IE uses filter instead) - // Use a regex to work around a WebKit issue. See #5145 - opacity: false, - - // Verify style float existence - // (IE uses styleFloat instead of cssFloat) - cssFloat: false, - - // Make sure that if no value is specified for a checkbox - // that it defaults to "on". - // (WebKit defaults to "" instead) - checkOn: false, - - // Make sure that a selected-by-default option has a working selected property. - // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) - optSelected: false, - - // Will be defined later - checkClone: false, - scriptEval: false, - noCloneEvent: false, - boxModel: false - }; - - // script.type = "text/javascript"; - // try { - // script.appendChild( document.createTextNode( "window." + id + "=1;" ) ); - // } catch(e) {} - - // root.insertBefore( script, root.firstChild ); - - // // Make sure that the execution of code works by injecting a script - // // tag with appendChild/createTextNode - // // (IE doesn't support this, fails, and uses .text instead) - // if ( window[ id ] ) { - // jQuery.support.scriptEval = true; - // delete window[ id ]; - // } - - // root.removeChild( script ); - - // if ( div.attachEvent && div.fireEvent ) { - // div.attachEvent("onclick", function click() { - // // Cloning a node shouldn't copy over any - // // bound event handlers (IE does this) - // jQuery.support.noCloneEvent = false; - // div.detachEvent("onclick", click); - // }); - // div.cloneNode(true).fireEvent("onclick"); - // } - - // div = document.createElement("div"); - // div.innerHTML = ""; - - // var fragment = document.createDocumentFragment(); - // fragment.appendChild( div.firstChild ); - - // // WebKit doesn't clone checked state correctly in fragments - // jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked; - - // // Figure out if the W3C box model works as expected - // // document.body must exist before we can do this - // jQuery(function() { - // var div = document.createElement("div"); - // div.style.width = div.style.paddingLeft = "1px"; - - // document.body.appendChild( div ); - // jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2; - // document.body.removeChild( div ).style.display = 'none'; - // div = null; - // }); - - // // Technique from Juriy Zaytsev - // // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ - // var eventSupported = function( eventName ) { - // var el = document.createElement("div"); - // eventName = "on" + eventName; - - // var isSupported = (eventName in el); - // if ( !isSupported ) { - // el.setAttribute(eventName, "return;"); - // isSupported = typeof el[eventName] === "function"; - // } - // el = null; - - // return isSupported; - // }; - - jQuery.support.submitBubbles = false; - jQuery.support.changeBubbles = false; - - // // release memory in IE - // root = script = div = all = a = null; -})(); - -jQuery.props = { - "for": "htmlFor", - "class": "className", - readonly: "readOnly", - maxlength: "maxLength", - cellspacing: "cellSpacing", - rowspan: "rowSpan", - colspan: "colSpan", - tabindex: "tabIndex", - usemap: "useMap", - frameborder: "frameBorder" -}; -var expando = "jQuery" + now(), uuid = 0, windowData = {}; -var emptyObject = {}; - -jQuery.extend({ - cache: {}, - - expando:expando, - - // The following elements throw uncatchable exceptions if you - // attempt to add expando properties to them. - noData: { - "embed": true, - "object": true, - "applet": true - }, - - data: function( elem, name, data ) { - /// - /// Store arbitrary data associated with the specified element. - /// - /// - /// The DOM element to associate with the data. - /// - /// - /// A string naming the piece of data to set. - /// - /// - /// The new data value. - /// - /// - - if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) { - return; - } - - elem = elem == window ? - windowData : - elem; - - var id = elem[ expando ], cache = jQuery.cache, thisCache; - - // Handle the case where there's no name immediately - if ( !name && !id ) { - return null; - } - - // Compute a unique ID for the element - if ( !id ) { - id = ++uuid; - } - - // Avoid generating a new cache unless none exists and we - // want to manipulate it. - if ( typeof name === "object" ) { - elem[ expando ] = id; - thisCache = cache[ id ] = jQuery.extend(true, {}, name); - } else if ( cache[ id ] ) { - thisCache = cache[ id ]; - } else if ( typeof data === "undefined" ) { - thisCache = emptyObject; - } else { - thisCache = cache[ id ] = {}; - } - - // Prevent overriding the named cache with undefined values - if ( data !== undefined ) { - elem[ expando ] = id; - thisCache[ name ] = data; - } - - return typeof name === "string" ? thisCache[ name ] : thisCache; - }, - - removeData: function( elem, name ) { - if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) { - return; - } - - elem = elem == window ? - windowData : - elem; - - var id = elem[ expando ], cache = jQuery.cache, thisCache = cache[ id ]; - - // If we want to remove a specific section of the element's data - if ( name ) { - if ( thisCache ) { - // Remove the section of cache data - delete thisCache[ name ]; - - // If we've removed all the data, remove the element's cache - if ( jQuery.isEmptyObject(thisCache) ) { - jQuery.removeData( elem ); - } - } - - // Otherwise, we want to remove all of the element's data - } else { - // Clean up the element expando - try { - delete elem[ expando ]; - } catch( e ) { - // IE has trouble directly removing the expando - // but it's ok with using removeAttribute - if ( elem.removeAttribute ) { - elem.removeAttribute( expando ); - } - } - - // Completely remove the data cache - delete cache[ id ]; - } - } -}); - -jQuery.fn.extend({ - data: function( key, value ) { - /// - /// Store arbitrary data associated with the matched elements. - /// - /// - /// A string naming the piece of data to set. - /// - /// - /// The new data value. - /// - /// - - if ( typeof key === "undefined" && this.length ) { - return jQuery.data( this[0] ); - - } else if ( typeof key === "object" ) { - return this.each(function() { - jQuery.data( this, key ); - }); - } - - var parts = key.split("."); - parts[1] = parts[1] ? "." + parts[1] : ""; - - if ( value === undefined ) { - var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); - - if ( data === undefined && this.length ) { - data = jQuery.data( this[0], key ); - } - return data === undefined && parts[1] ? - this.data( parts[0] ) : - data; - } else { - return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function() { - jQuery.data( this, key, value ); - }); - } - }, - - removeData: function( key ) { - return this.each(function() { - jQuery.removeData( this, key ); - }); - } -}); -jQuery.extend({ - queue: function( elem, type, data ) { - if ( !elem ) { - return; - } - - type = (type || "fx") + "queue"; - var q = jQuery.data( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( !data ) { - return q || []; - } - - if ( !q || jQuery.isArray(data) ) { - q = jQuery.data( elem, type, jQuery.makeArray(data) ); - - } else { - q.push( data ); - } - - return q; - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), fn = queue.shift(); - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - } - - if ( fn ) { - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift("inprogress"); - } - - fn.call(elem, function() { - jQuery.dequeue(elem, type); - }); - } - } -}); - -jQuery.fn.extend({ - queue: function( type, data ) { - /// - /// 1: queue() - Returns a reference to the first element's queue (which is an array of functions). - /// 2: queue(callback) - Adds a new function, to be executed, onto the end of the queue of all matched elements. - /// 3: queue(queue) - Replaces the queue of all matched element with this new queue (the array of functions). - /// - /// The function to add to the queue. - /// - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - } - - if ( data === undefined ) { - return jQuery.queue( this[0], type ); - } - return this.each(function( i, elem ) { - var queue = jQuery.queue( this, type, data ); - - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); - }, - dequeue: function( type ) { - /// - /// Removes a queued function from the front of the queue and executes it. - /// - /// The type of queue to access. - /// - - return this.each(function() { - jQuery.dequeue( this, type ); - }); - }, - - // Based off of the plugin by Clint Helfers, with permission. - // http://blindsignals.com/index.php/2009/07/jquery-delay/ - delay: function( time, type ) { - /// - /// Set a timer to delay execution of subsequent items in the queue. - /// - /// - /// An integer indicating the number of milliseconds to delay execution of the next item in the queue. - /// - /// - /// A string containing the name of the queue. Defaults to fx, the standard effects queue. - /// - /// - - time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; - type = type || "fx"; - - return this.queue( type, function() { - var elem = this; - setTimeout(function() { - jQuery.dequeue( elem, type ); - }, time ); - }); - }, - - clearQueue: function( type ) { - /// - /// Remove from the queue all items that have not yet been run. - /// - /// - /// A string containing the name of the queue. Defaults to fx, the standard effects queue. - /// - /// - - return this.queue( type || "fx", [] ); - } -}); -var rclass = /[\n\t]/g, - rspace = /\s+/, - rreturn = /\r/g, - rspecialurl = /href|src|style/, - rtype = /(button|input)/i, - rfocusable = /(button|input|object|select|textarea)/i, - rclickable = /^(a|area)$/i, - rradiocheck = /radio|checkbox/; - -jQuery.fn.extend({ - attr: function( name, value ) { - /// - /// Set a single property to a computed value, on all matched elements. - /// Instead of a value, a function is provided, that computes the value. - /// Part of DOM/Attributes - /// - /// - /// - /// The name of the property to set. - /// - /// - /// A function returning the value to set. - /// - - return access( this, name, value, true, jQuery.attr ); - }, - - removeAttr: function( name, fn ) { - /// - /// Remove an attribute from each of the matched elements. - /// Part of DOM/Attributes - /// - /// - /// An attribute to remove. - /// - /// - - return this.each(function(){ - jQuery.attr( this, name, "" ); - if ( this.nodeType === 1 ) { - this.removeAttribute( name ); - } - }); - }, - - addClass: function( value ) { - /// - /// Adds the specified class(es) to each of the set of matched elements. - /// Part of DOM/Attributes - /// - /// - /// One or more class names to be added to the class attribute of each matched element. - /// - /// - - if ( jQuery.isFunction(value) ) { - return this.each(function(i) { - var self = jQuery(this); - self.addClass( value.call(this, i, self.attr("class")) ); - }); - } - - if ( value && typeof value === "string" ) { - var classNames = (value || "").split( rspace ); - - for ( var i = 0, l = this.length; i < l; i++ ) { - var elem = this[i]; - - if ( elem.nodeType === 1 ) { - if ( !elem.className ) { - elem.className = value; - - } else { - var className = " " + elem.className + " "; - for ( var c = 0, cl = classNames.length; c < cl; c++ ) { - if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) { - elem.className += " " + classNames[c]; - } - } - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - /// - /// Removes all or the specified class(es) from the set of matched elements. - /// Part of DOM/Attributes - /// - /// - /// (Optional) A class name to be removed from the class attribute of each matched element. - /// - /// - - if ( jQuery.isFunction(value) ) { - return this.each(function(i) { - var self = jQuery(this); - self.removeClass( value.call(this, i, self.attr("class")) ); - }); - } - - if ( (value && typeof value === "string") || value === undefined ) { - var classNames = (value || "").split(rspace); - - for ( var i = 0, l = this.length; i < l; i++ ) { - var elem = this[i]; - - if ( elem.nodeType === 1 && elem.className ) { - if ( value ) { - var className = (" " + elem.className + " ").replace(rclass, " "); - for ( var c = 0, cl = classNames.length; c < cl; c++ ) { - className = className.replace(" " + classNames[c] + " ", " "); - } - elem.className = className.substring(1, className.length - 1); - - } else { - elem.className = ""; - } - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - /// - /// Add or remove a class from each element in the set of matched elements, depending - /// on either the class's presence or the value of the switch argument. - /// - /// - /// A class name to be toggled for each element in the matched set. - /// - /// - /// A boolean value to determine whether the class should be added or removed. - /// - /// - - var type = typeof value, isBool = typeof stateVal === "boolean"; - - if ( jQuery.isFunction( value ) ) { - return this.each(function(i) { - var self = jQuery(this); - self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal ); - }); - } - - return this.each(function() { - if ( type === "string" ) { - // toggle individual class names - var className, i = 0, self = jQuery(this), - state = stateVal, - classNames = value.split( rspace ); - - while ( (className = classNames[ i++ ]) ) { - // check each className given, space seperated list - state = isBool ? state : !self.hasClass( className ); - self[ state ? "addClass" : "removeClass" ]( className ); - } - - } else if ( type === "undefined" || type === "boolean" ) { - if ( this.className ) { - // store className if set - jQuery.data( this, "__className__", this.className ); - } - - // toggle whole className - this.className = this.className || value === false ? "" : jQuery.data( this, "__className__" ) || ""; - } - }); - }, - - hasClass: function( selector ) { - /// - /// Checks the current selection against a class and returns whether at least one selection has a given class. - /// - /// The class to check against - /// True if at least one element in the selection has the class, otherwise false. - - var className = " " + selector + " "; - for ( var i = 0, l = this.length; i < l; i++ ) { - if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { - return true; - } - } - - return false; - }, - - val: function( value ) { - /// - /// Set the value of every matched element. - /// Part of DOM/Attributes - /// - /// - /// - /// A string of text or an array of strings to set as the value property of each - /// matched element. - /// - - if ( value === undefined ) { - var elem = this[0]; - - if ( elem ) { - if ( jQuery.nodeName( elem, "option" ) ) { - return (elem.attributes.value || {}).specified ? elem.value : elem.text; - } - - // We need to handle select boxes special - if ( jQuery.nodeName( elem, "select" ) ) { - var index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type === "select-one"; - - // Nothing was selected - if ( index < 0 ) { - return null; - } - - // Loop through all the selected options - for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { - var option = options[ i ]; - - if ( option.selected ) { - // Get the specifc value for the option - value = jQuery(option).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - } - - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) { - return elem.getAttribute("value") === null ? "on" : elem.value; - } - - - // Everything else, we just grab the value - return (elem.value || "").replace(rreturn, ""); - - } - - return undefined; - } - - var isFunction = jQuery.isFunction(value); - - return this.each(function(i) { - var self = jQuery(this), val = value; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call(this, i, self.val()); - } - - // Typecast each time if the value is a Function and the appended - // value is therefore different each time. - if ( typeof val === "number" ) { - val += ""; - } - - if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) { - this.checked = jQuery.inArray( self.val(), val ) >= 0; - - } else if ( jQuery.nodeName( this, "select" ) ) { - var values = jQuery.makeArray(val); - - jQuery( "option", this ).each(function() { - this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; - }); - - if ( !values.length ) { - this.selectedIndex = -1; - } - - } else { - this.value = val; - } - }); - } -}); - -jQuery.extend({ - attrFn: { - val: true, - css: true, - html: true, - text: true, - data: true, - width: true, - height: true, - offset: true - }, - - attr: function( elem, name, value, pass ) { - /// - /// This method is internal. - /// - /// - - // don't set attributes on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { - return undefined; - } - - if ( pass && name in jQuery.attrFn ) { - return jQuery(elem)[name](value); - } - - var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), - // Whether we are setting (or getting) - set = value !== undefined; - - // Try to normalize/fix the name - name = notxml && jQuery.props[ name ] || name; - - // Only do all the following if this is a node (faster for style) - if ( elem.nodeType === 1 ) { - // These attributes require special treatment - var special = rspecialurl.test( name ); - - // Safari mis-reports the default selected property of an option - // Accessing the parent's selectedIndex property fixes it - if ( name === "selected" && !jQuery.support.optSelected ) { - var parent = elem.parentNode; - if ( parent ) { - parent.selectedIndex; - - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - } - - // If applicable, access the attribute via the DOM 0 way - if ( name in elem && notxml && !special ) { - if ( set ) { - // We can't allow the type property to be changed (since it causes problems in IE) - if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) { - jQuery.error( "type property can't be changed" ); - } - - elem[ name ] = value; - } - - // browsers index elements by id/name on forms, give priority to attributes. - if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) { - return elem.getAttributeNode( name ).nodeValue; - } - - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - if ( name === "tabIndex" ) { - var attributeNode = elem.getAttributeNode( "tabIndex" ); - - return attributeNode && attributeNode.specified ? - attributeNode.value : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } - - return elem[ name ]; - } - - if ( !jQuery.support.style && notxml && name === "style" ) { - if ( set ) { - elem.style.cssText = "" + value; - } - - return elem.style.cssText; - } - - if ( set ) { - // convert the value to a string (all browsers do this but IE) see #1070 - elem.setAttribute( name, "" + value ); - } - - var attr = !jQuery.support.hrefNormalized && notxml && special ? - // Some attributes require a special call on IE - elem.getAttribute( name, 2 ) : - elem.getAttribute( name ); - - // Non-existent attributes return null, we normalize to undefined - return attr === null ? undefined : attr; - } - - // elem is actually elem.style ... set the style - // Using attr for specific style information is now deprecated. Use style insead. - return jQuery.style( elem, name, value ); - } -}); -var fcleanup = function( nm ) { - return nm.replace(/[^\w\s\.\|`]/g, function( ch ) { - return "\\" + ch; - }); -}; - -/* - * A number of helper functions used for managing events. - * Many of the ideas behind this code originated from - * Dean Edwards' addEvent library. - */ -jQuery.event = { - - // Bind an event to an element - // Original by Dean Edwards - add: function( elem, types, handler, data ) { - /// - /// This method is internal. - /// - /// - - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // For whatever reason, IE has trouble passing the window object - // around, causing it to be cloned in the process - if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) { - elem = window; - } - - // Make sure that the function being executed has a unique ID - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // if data is passed, bind to handler - if ( data !== undefined ) { - // Create temporary function pointer to original handler - var fn = handler; - - // Create unique handler function, wrapped around original handler - handler = jQuery.proxy( fn ); - - // Store data in unique handler - handler.data = data; - } - - // Init the element's event structure - var events = jQuery.data( elem, "events" ) || jQuery.data( elem, "events", {} ), - handle = jQuery.data( elem, "handle" ), eventHandle; - - if ( !handle ) { - eventHandle = function() { - // Handle the second event of a trigger and when - // an event is called after a page has unloaded - return typeof jQuery !== "undefined" && !jQuery.event.triggered ? - jQuery.event.handle.apply( eventHandle.elem, arguments ) : - undefined; - }; - - handle = jQuery.data( elem, "handle", eventHandle ); - } - - // If no handle is found then we must be trying to bind to one of the - // banned noData elements - if ( !handle ) { - return; - } - - // Add elem as a property of the handle function - // This is to prevent a memory leak with non-native - // event in IE. - handle.elem = elem; - - // Handle multiple events separated by a space - // jQuery(...).bind("mouseover mouseout", fn); - types = types.split( /\s+/ ); - - var type, i = 0; - - while ( (type = types[ i++ ]) ) { - // Namespaced event handlers - var namespaces = type.split("."); - type = namespaces.shift(); - - if ( i > 1 ) { - handler = jQuery.proxy( handler ); - - if ( data !== undefined ) { - handler.data = data; - } - } - - handler.type = namespaces.slice(0).sort().join("."); - - // Get the current list of functions bound to this event - var handlers = events[ type ], - special = this.special[ type ] || {}; - - // Init the event handler queue - if ( !handlers ) { - handlers = events[ type ] = {}; - - // Check for a special event handler - // Only use addEventListener/attachEvent if the special - // events handler returns false - if ( !special.setup || special.setup.call( elem, data, namespaces, handler) === false ) { - // Bind the global event handler to the element - if ( elem.addEventListener ) { - elem.addEventListener( type, handle, false ); - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, handle ); - } - } - } - - if ( special.add ) { - var modifiedHandler = special.add.call( elem, handler, data, namespaces, handlers ); - if ( modifiedHandler && jQuery.isFunction( modifiedHandler ) ) { - modifiedHandler.guid = modifiedHandler.guid || handler.guid; - modifiedHandler.data = modifiedHandler.data || handler.data; - modifiedHandler.type = modifiedHandler.type || handler.type; - handler = modifiedHandler; - } - } - - // Add the function to the element's handler list - handlers[ handler.guid ] = handler; - - // Keep track of which events have been used, for global triggering - this.global[ type ] = true; - } - - // Nullify elem to prevent memory leaks in IE - elem = null; - }, - - global: {}, - - // Detach an event or set of events from an element - remove: function( elem, types, handler ) { - /// - /// This method is internal. - /// - /// - - // don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - var events = jQuery.data( elem, "events" ), ret, type, fn; - - if ( events ) { - // Unbind all events for the element - if ( types === undefined || (typeof types === "string" && types.charAt(0) === ".") ) { - for ( type in events ) { - this.remove( elem, type + (types || "") ); - } - } else { - // types is actually an event object here - if ( types.type ) { - handler = types.handler; - types = types.type; - } - - // Handle multiple events separated by a space - // jQuery(...).unbind("mouseover mouseout", fn); - types = types.split(/\s+/); - var i = 0; - while ( (type = types[ i++ ]) ) { - // Namespaced event handlers - var namespaces = type.split("."); - type = namespaces.shift(); - var all = !namespaces.length, - cleaned = jQuery.map( namespaces.slice(0).sort(), fcleanup ), - namespace = new RegExp("(^|\\.)" + cleaned.join("\\.(?:.*\\.)?") + "(\\.|$)"), - special = this.special[ type ] || {}; - - if ( events[ type ] ) { - // remove the given handler for the given type - if ( handler ) { - fn = events[ type ][ handler.guid ]; - delete events[ type ][ handler.guid ]; - - // remove all handlers for the given type - } else { - for ( var handle in events[ type ] ) { - // Handle the removal of namespaced events - if ( all || namespace.test( events[ type ][ handle ].type ) ) { - delete events[ type ][ handle ]; - } - } - } - - if ( special.remove ) { - special.remove.call( elem, namespaces, fn); - } - - // remove generic event handler if no more handlers exist - for ( ret in events[ type ] ) { - break; - } - if ( !ret ) { - if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { - if ( elem.removeEventListener ) { - elem.removeEventListener( type, jQuery.data( elem, "handle" ), false ); - } else if ( elem.detachEvent ) { - elem.detachEvent( "on" + type, jQuery.data( elem, "handle" ) ); - } - } - ret = null; - delete events[ type ]; - } - } - } - } - - // Remove the expando if it's no longer used - for ( ret in events ) { - break; - } - if ( !ret ) { - var handle = jQuery.data( elem, "handle" ); - if ( handle ) { - handle.elem = null; - } - jQuery.removeData( elem, "events" ); - jQuery.removeData( elem, "handle" ); - } - } - }, - - // bubbling is internal - trigger: function( event, data, elem /*, bubbling */ ) { - /// - /// This method is internal. - /// - /// - - // Event object or event type - var type = event.type || event, - bubbling = arguments[3]; - - if ( !bubbling ) { - event = typeof event === "object" ? - // jQuery.Event object - event[expando] ? event : - // Object literal - jQuery.extend( jQuery.Event(type), event ) : - // Just the event type (string) - jQuery.Event(type); - - if ( type.indexOf("!") >= 0 ) { - event.type = type = type.slice(0, -1); - event.exclusive = true; - } - - // Handle a global trigger - if ( !elem ) { - // Don't bubble custom events when global (to avoid too much overhead) - event.stopPropagation(); - - // Only trigger if we've ever bound an event for it - if ( this.global[ type ] ) { - jQuery.each( jQuery.cache, function() { - if ( this.events && this.events[type] ) { - jQuery.event.trigger( event, data, this.handle.elem ); - } - }); - } - } - - // Handle triggering a single element - - // don't do events on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { - return undefined; - } - - // Clean up in case it is reused - event.result = undefined; - event.target = elem; - - // Clone the incoming data, if any - data = jQuery.makeArray( data ); - data.unshift( event ); - } - - event.currentTarget = elem; - - // Trigger the event, it is assumed that "handle" is a function - var handle = jQuery.data( elem, "handle" ); - if ( handle ) { - handle.apply( elem, data ); - } - - var parent = elem.parentNode || elem.ownerDocument; - - // Trigger an inline bound script - try { - if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) { - if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) { - event.result = false; - } - } - - // prevent IE from throwing an error for some elements with some event types, see #3533 - } catch (e) {} - - if ( !event.isPropagationStopped() && parent ) { - jQuery.event.trigger( event, data, parent, true ); - - } else if ( !event.isDefaultPrevented() ) { - var target = event.target, old, - isClick = jQuery.nodeName(target, "a") && type === "click"; - - if ( !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) { - try { - if ( target[ type ] ) { - // Make sure that we don't accidentally re-trigger the onFOO events - old = target[ "on" + type ]; - - if ( old ) { - target[ "on" + type ] = null; - } - - this.triggered = true; - target[ type ](); - } - - // prevent IE from throwing an error for some elements with some event types, see #3533 - } catch (e) {} - - if ( old ) { - target[ "on" + type ] = old; - } - - this.triggered = false; - } - } - }, - - handle: function( event ) { - /// - /// This method is internal. - /// - /// - - // returned undefined or false - var all, handlers; - - event = arguments[0] = jQuery.event.fix( event || window.event ); - event.currentTarget = this; - - // Namespaced event handlers - var namespaces = event.type.split("."); - event.type = namespaces.shift(); - - // Cache this now, all = true means, any handler - all = !namespaces.length && !event.exclusive; - - var namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)"); - - handlers = ( jQuery.data(this, "events") || {} )[ event.type ]; - - for ( var j in handlers ) { - var handler = handlers[ j ]; - - // Filter the functions by class - if ( all || namespace.test(handler.type) ) { - // Pass in a reference to the handler function itself - // So that we can later remove it - event.handler = handler; - event.data = handler.data; - - var ret = handler.apply( this, arguments ); - - if ( ret !== undefined ) { - event.result = ret; - if ( ret === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - - if ( event.isImmediatePropagationStopped() ) { - break; - } - - } - } - - return event.result; - }, - - props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), - - fix: function( event ) { - /// - /// This method is internal. - /// - /// - - if ( event[ expando ] ) { - return event; - } - - // store a copy of the original event object - // and "clone" to set read-only properties - var originalEvent = event; - event = jQuery.Event( originalEvent ); - - for ( var i = this.props.length, prop; i; ) { - prop = this.props[ --i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Fix target property, if necessary - if ( !event.target ) { - event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either - } - - // check if target is a textnode (safari) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - // Add relatedTarget, if necessary - if ( !event.relatedTarget && event.fromElement ) { - event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; - } - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && event.clientX != null ) { - var doc = document.documentElement, body = document.body; - event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); - event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); - } - - // Add which for key events - if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) { - event.which = event.charCode || event.keyCode; - } - - // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) - if ( !event.metaKey && event.ctrlKey ) { - event.metaKey = event.ctrlKey; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && event.button !== undefined ) { - event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); - } - - return event; - }, - - // Deprecated, use jQuery.guid instead - guid: 1E8, - - // Deprecated, use jQuery.proxy instead - proxy: jQuery.proxy, - - special: { - ready: { - // Make sure the ready event is setup - setup: jQuery.bindReady, - teardown: jQuery.noop - }, - - live: { - add: function( proxy, data, namespaces, live ) { - jQuery.extend( proxy, data || {} ); - - proxy.guid += data.selector + data.live; - data.liveProxy = proxy; - - jQuery.event.add( this, data.live, liveHandler, data ); - - }, - - remove: function( namespaces ) { - if ( namespaces.length ) { - var remove = 0, name = new RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)"); - - jQuery.each( (jQuery.data(this, "events").live || {}), function() { - if ( name.test(this.type) ) { - remove++; - } - }); - - if ( remove < 1 ) { - jQuery.event.remove( this, namespaces[0], liveHandler ); - } - } - }, - special: {} - }, - beforeunload: { - setup: function( data, namespaces, fn ) { - // We only want to do this special case on windows - if ( this.setInterval ) { - this.onbeforeunload = fn; - } - - return false; - }, - teardown: function( namespaces, fn ) { - if ( this.onbeforeunload === fn ) { - this.onbeforeunload = null; - } - } - } - } -}; - -jQuery.Event = function( src ) { - // Allow instantiation without the 'new' keyword - if ( !this.preventDefault ) { - return new jQuery.Event( src ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - // Event type - } else { - this.type = src; - } - - // timeStamp is buggy for some events on Firefox(#3843) - // So we won't rely on the native value - this.timeStamp = now(); - - // Mark it as fixed - this[ expando ] = true; -}; - -function returnFalse() { - return false; -} -function returnTrue() { - return true; -} - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - preventDefault: function() { - this.isDefaultPrevented = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - - // if preventDefault exists run it on the original event - if ( e.preventDefault ) { - e.preventDefault(); - } - // otherwise set the returnValue property of the original event to false (IE) - e.returnValue = false; - }, - stopPropagation: function() { - this.isPropagationStopped = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - // if stopPropagation exists run it on the original event - if ( e.stopPropagation ) { - e.stopPropagation(); - } - // otherwise set the cancelBubble property of the original event to true (IE) - e.cancelBubble = true; - }, - stopImmediatePropagation: function() { - this.isImmediatePropagationStopped = returnTrue; - this.stopPropagation(); - }, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse -}; - -// Checks if an event happened on an element within another element -// Used in jQuery.event.special.mouseenter and mouseleave handlers -var withinElement = function( event ) { - // Check if mouse(over|out) are still within the same parent element - var parent = event.relatedTarget; - - // Traverse up the tree - while ( parent && parent !== this ) { - // Firefox sometimes assigns relatedTarget a XUL element - // which we cannot access the parentNode property of - try { - parent = parent.parentNode; - - // assuming we've left the element since we most likely mousedover a xul element - } catch(e) { - break; - } - } - - if ( parent !== this ) { - // set the correct event type - event.type = event.data; - - // handle event if we actually just moused on to a non sub-element - jQuery.event.handle.apply( this, arguments ); - } - -}, - -// In case of event delegation, we only need to rename the event.type, -// liveHandler will take care of the rest. -delegate = function( event ) { - event.type = event.data; - jQuery.event.handle.apply( this, arguments ); -}; - -// Create mouseenter and mouseleave events -jQuery.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - setup: function( data ) { - jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); - }, - teardown: function( data ) { - jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); - } - }; -}); - -// submit delegation -if ( !jQuery.support.submitBubbles ) { - -jQuery.event.special.submit = { - setup: function( data, namespaces, fn ) { - if ( this.nodeName.toLowerCase() !== "form" ) { - jQuery.event.add(this, "click.specialSubmit." + fn.guid, function( e ) { - var elem = e.target, type = elem.type; - - if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { - return trigger( "submit", this, arguments ); - } - }); - - jQuery.event.add(this, "keypress.specialSubmit." + fn.guid, function( e ) { - var elem = e.target, type = elem.type; - - if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { - return trigger( "submit", this, arguments ); - } - }); - - } else { - return false; - } - }, - - remove: function( namespaces, fn ) { - jQuery.event.remove( this, "click.specialSubmit" + (fn ? "."+fn.guid : "") ); - jQuery.event.remove( this, "keypress.specialSubmit" + (fn ? "."+fn.guid : "") ); - } -}; - -} - -// change delegation, happens here so we have bind. -if ( !jQuery.support.changeBubbles ) { - -var formElems = /textarea|input|select/i; - -function getVal( elem ) { - var type = elem.type, val = elem.value; - - if ( type === "radio" || type === "checkbox" ) { - val = elem.checked; - - } else if ( type === "select-multiple" ) { - val = elem.selectedIndex > -1 ? - jQuery.map( elem.options, function( elem ) { - return elem.selected; - }).join("-") : - ""; - - } else if ( elem.nodeName.toLowerCase() === "select" ) { - val = elem.selectedIndex; - } - - return val; -} - -function testChange( e ) { - var elem = e.target, data, val; - - if ( !formElems.test( elem.nodeName ) || elem.readOnly ) { - return; - } - - data = jQuery.data( elem, "_change_data" ); - val = getVal(elem); - - // the current data will be also retrieved by beforeactivate - if ( e.type !== "focusout" || elem.type !== "radio" ) { - jQuery.data( elem, "_change_data", val ); - } - - if ( data === undefined || val === data ) { - return; - } - - if ( data != null || val ) { - e.type = "change"; - return jQuery.event.trigger( e, arguments[1], elem ); - } -} - -jQuery.event.special.change = { - filters: { - focusout: testChange, - - click: function( e ) { - var elem = e.target, type = elem.type; - - if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) { - return testChange.call( this, e ); - } - }, - - // Change has to be called before submit - // Keydown will be called before keypress, which is used in submit-event delegation - keydown: function( e ) { - var elem = e.target, type = elem.type; - - if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") || - (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || - type === "select-multiple" ) { - return testChange.call( this, e ); - } - }, - - // Beforeactivate happens also before the previous element is blurred - // with this event you can't trigger a change event, but you can store - // information/focus[in] is not needed anymore - beforeactivate: function( e ) { - var elem = e.target; - - if ( elem.nodeName.toLowerCase() === "input" && elem.type === "radio" ) { - jQuery.data( elem, "_change_data", getVal(elem) ); - } - } - }, - setup: function( data, namespaces, fn ) { - for ( var type in changeFilters ) { - jQuery.event.add( this, type + ".specialChange." + fn.guid, changeFilters[type] ); - } - - return formElems.test( this.nodeName ); - }, - remove: function( namespaces, fn ) { - for ( var type in changeFilters ) { - jQuery.event.remove( this, type + ".specialChange" + (fn ? "."+fn.guid : ""), changeFilters[type] ); - } - - return formElems.test( this.nodeName ); - } -}; - -var changeFilters = jQuery.event.special.change.filters; - -} - -function trigger( type, elem, args ) { - args[0].type = type; - return jQuery.event.handle.apply( elem, args ); -} - -// Create "bubbling" focus and blur events -if ( document.addEventListener ) { - jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - jQuery.event.special[ fix ] = { - setup: function() { - /// - /// This method is internal. - /// - /// - - this.addEventListener( orig, handler, true ); - }, - teardown: function() { - /// - /// This method is internal. - /// - /// - - this.removeEventListener( orig, handler, true ); - } - }; - - function handler( e ) { - e = jQuery.event.fix( e ); - e.type = fix; - return jQuery.event.handle.call( this, e ); - } - }); -} - -// jQuery.each(["bind", "one"], function( i, name ) { -// jQuery.fn[ name ] = function( type, data, fn ) { -// // Handle object literals -// if ( typeof type === "object" ) { -// for ( var key in type ) { -// this[ name ](key, data, type[key], fn); -// } -// return this; -// } -// -// if ( jQuery.isFunction( data ) ) { -// fn = data; -// data = undefined; -// } -// -// var handler = name === "one" ? jQuery.proxy( fn, function( event ) { -// jQuery( this ).unbind( event, handler ); -// return fn.apply( this, arguments ); -// }) : fn; -// -// return type === "unload" && name !== "one" ? -// this.one( type, data, fn ) : -// this.each(function() { -// jQuery.event.add( this, type, handler, data ); -// }); -// }; -// }); - -jQuery.fn[ "bind" ] = function( type, data, fn ) { - /// - /// Binds a handler to one or more events for each matched element. Can also bind custom events. - /// - /// One or more event types separated by a space. Built-in event type values are: blur, focus, load, resize, scroll, unload, click, dblclick, mousedown, mouseup, mousemove, mouseover, mouseout, mouseenter, mouseleave, change, select, submit, keydown, keypress, keyup, error . - /// Additional data passed to the event handler as event.data - /// A function to bind to the event on each of the set of matched elements. function callback(eventObject) such that this corresponds to the dom element. - - // Handle object literals - if ( typeof type === "object" ) { - for ( var key in type ) { - this[ "bind" ](key, data, type[key], fn); - } - return this; - } - - if ( jQuery.isFunction( data ) ) { - fn = data; - data = undefined; - } - - var handler = "bind" === "one" ? jQuery.proxy( fn, function( event ) { - jQuery( this ).unbind( event, handler ); - return fn.apply( this, arguments ); - }) : fn; - - return type === "unload" && "bind" !== "one" ? - this.one( type, data, fn ) : - this.each(function() { - jQuery.event.add( this, type, handler, data ); - }); -}; - -jQuery.fn[ "one" ] = function( type, data, fn ) { - /// - /// Binds a handler to one or more events to be executed exactly once for each matched element. - /// - /// One or more event types separated by a space. Built-in event type values are: blur, focus, load, resize, scroll, unload, click, dblclick, mousedown, mouseup, mousemove, mouseover, mouseout, mouseenter, mouseleave, change, select, submit, keydown, keypress, keyup, error . - /// Additional data passed to the event handler as event.data - /// A function to bind to the event on each of the set of matched elements. function callback(eventObject) such that this corresponds to the dom element. - - // Handle object literals - if ( typeof type === "object" ) { - for ( var key in type ) { - this[ "one" ](key, data, type[key], fn); - } - return this; - } - - if ( jQuery.isFunction( data ) ) { - fn = data; - data = undefined; - } - - var handler = "one" === "one" ? jQuery.proxy( fn, function( event ) { - jQuery( this ).unbind( event, handler ); - return fn.apply( this, arguments ); - }) : fn; - - return type === "unload" && "one" !== "one" ? - this.one( type, data, fn ) : - this.each(function() { - jQuery.event.add( this, type, handler, data ); - }); -}; - -jQuery.fn.extend({ - unbind: function( type, fn ) { - /// - /// Unbinds a handler from one or more events for each matched element. - /// - /// One or more event types separated by a space. Built-in event type values are: blur, focus, load, resize, scroll, unload, click, dblclick, mousedown, mouseup, mousemove, mouseover, mouseout, mouseenter, mouseleave, change, select, submit, keydown, keypress, keyup, error . - /// A function to bind to the event on each of the set of matched elements. function callback(eventObject) such that this corresponds to the dom element. - - // Handle object literals - if ( typeof type === "object" && !type.preventDefault ) { - for ( var key in type ) { - this.unbind(key, type[key]); - } - return this; - } - - return this.each(function() { - jQuery.event.remove( this, type, fn ); - }); - }, - trigger: function( type, data ) { - /// - /// Triggers a type of event on every matched element. - /// - /// One or more event types separated by a space. Built-in event type values are: blur, focus, load, resize, scroll, unload, click, dblclick, mousedown, mouseup, mousemove, mouseover, mouseout, mouseenter, mouseleave, change, select, submit, keydown, keypress, keyup, error . - /// Additional data passed to the event handler as additional arguments. - /// This parameter is undocumented. - - return this.each(function() { - jQuery.event.trigger( type, data, this ); - }); - }, - - triggerHandler: function( type, data ) { - /// - /// Triggers all bound event handlers on an element for a specific event type without executing the browser's default actions. - /// - /// One or more event types separated by a space. Built-in event type values are: blur, focus, load, resize, scroll, unload, click, dblclick, mousedown, mouseup, mousemove, mouseover, mouseout, mouseenter, mouseleave, change, select, submit, keydown, keypress, keyup, error . - /// Additional data passed to the event handler as additional arguments. - /// This parameter is undocumented. - - if ( this[0] ) { - var event = jQuery.Event( type ); - event.preventDefault(); - event.stopPropagation(); - jQuery.event.trigger( event, data, this[0] ); - return event.result; - } - }, - - toggle: function( fn ) { - /// - /// Toggles among two or more function calls every other click. - /// - /// The functions among which to toggle execution - - // Save reference to arguments for access in closure - var args = arguments, i = 1; - - // link all the functions, so any of them can unbind this click handler - while ( i < args.length ) { - jQuery.proxy( fn, args[ i++ ] ); - } - - return this.click( jQuery.proxy( fn, function( event ) { - // Figure out which function to execute - var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i; - jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 ); - - // Make sure that clicks stop - event.preventDefault(); - - // and execute the function - return args[ lastToggle ].apply( this, arguments ) || false; - })); - }, - - hover: function( fnOver, fnOut ) { - /// - /// Simulates hovering (moving the mouse on or off of an object). - /// - /// The function to fire when the mouse is moved over a matched element. - /// The function to fire when the mouse is moved off of a matched element. - - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -}); - -// jQuery.each(["live", "die"], function( i, name ) { -// jQuery.fn[ name ] = function( types, data, fn ) { -// var type, i = 0; -// -// if ( jQuery.isFunction( data ) ) { -// fn = data; -// data = undefined; -// } -// -// types = (types || "").split( /\s+/ ); -// -// while ( (type = types[ i++ ]) != null ) { -// type = type === "focus" ? "focusin" : // focus --> focusin -// type === "blur" ? "focusout" : // blur --> focusout -// type === "hover" ? types.push("mouseleave") && "mouseenter" : // hover support -// type; -// -// if ( name === "live" ) { -// // bind live handler -// jQuery( this.context ).bind( liveConvert( type, this.selector ), { -// data: data, selector: this.selector, live: type -// }, fn ); -// -// } else { -// // unbind live handler -// jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null ); -// } -// } -// -// return this; -// } -// }); - -jQuery.fn[ "live" ] = function( types, data, fn ) { - /// - /// Attach a handler to the event for all elements which match the current selector, now or - /// in the future. - /// - /// - /// A string containing a JavaScript event type, such as "click" or "keydown". - /// - /// - /// A map of data that will be passed to the event handler. - /// - /// - /// A function to execute at the time the event is triggered. - /// - /// - - var type, i = 0; - - if ( jQuery.isFunction( data ) ) { - fn = data; - data = undefined; - } - - types = (types || "").split( /\s+/ ); - - while ( (type = types[ i++ ]) != null ) { - type = type === "focus" ? "focusin" : // focus --> focusin - type === "blur" ? "focusout" : // blur --> focusout - type === "hover" ? types.push("mouseleave") && "mouseenter" : // hover support - type; - - if ( "live" === "live" ) { - // bind live handler - jQuery( this.context ).bind( liveConvert( type, this.selector ), { - data: data, selector: this.selector, live: type - }, fn ); - - } else { - // unbind live handler - jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null ); - } - } - - return this; -} - -jQuery.fn[ "die" ] = function( types, data, fn ) { - /// - /// Remove all event handlers previously attached using .live() from the elements. - /// - /// - /// A string containing a JavaScript event type, such as click or keydown. - /// - /// - /// The function that is to be no longer executed. - /// - /// - - var type, i = 0; - - if ( jQuery.isFunction( data ) ) { - fn = data; - data = undefined; - } - - types = (types || "").split( /\s+/ ); - - while ( (type = types[ i++ ]) != null ) { - type = type === "focus" ? "focusin" : // focus --> focusin - type === "blur" ? "focusout" : // blur --> focusout - type === "hover" ? types.push("mouseleave") && "mouseenter" : // hover support - type; - - if ( "die" === "live" ) { - // bind live handler - jQuery( this.context ).bind( liveConvert( type, this.selector ), { - data: data, selector: this.selector, live: type - }, fn ); - - } else { - // unbind live handler - jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null ); - } - } - - return this; -} - -function liveHandler( event ) { - var stop, elems = [], selectors = [], args = arguments, - related, match, fn, elem, j, i, l, data, - live = jQuery.extend({}, jQuery.data( this, "events" ).live); - - // Make sure we avoid non-left-click bubbling in Firefox (#3861) - if ( event.button && event.type === "click" ) { - return; - } - - for ( j in live ) { - fn = live[j]; - if ( fn.live === event.type || - fn.altLive && jQuery.inArray(event.type, fn.altLive) > -1 ) { - - data = fn.data; - if ( !(data.beforeFilter && data.beforeFilter[event.type] && - !data.beforeFilter[event.type](event)) ) { - selectors.push( fn.selector ); - } - } else { - delete live[j]; - } - } - - match = jQuery( event.target ).closest( selectors, event.currentTarget ); - - for ( i = 0, l = match.length; i < l; i++ ) { - for ( j in live ) { - fn = live[j]; - elem = match[i].elem; - related = null; - - if ( match[i].selector === fn.selector ) { - // Those two events require additional checking - if ( fn.live === "mouseenter" || fn.live === "mouseleave" ) { - related = jQuery( event.relatedTarget ).closest( fn.selector )[0]; - } - - if ( !related || related !== elem ) { - elems.push({ elem: elem, fn: fn }); - } - } - } - } - - for ( i = 0, l = elems.length; i < l; i++ ) { - match = elems[i]; - event.currentTarget = match.elem; - event.data = match.fn.data; - if ( match.fn.apply( match.elem, args ) === false ) { - stop = false; - break; - } - } - - return stop; -} - -function liveConvert( type, selector ) { - return "live." + (type ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&"); -} - -// jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + -// "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + -// "change select submit keydown keypress keyup error").split(" "), function( i, name ) { -// -// // Handle event binding -// jQuery.fn[ name ] = function( fn ) { -// return fn ? this.bind( name, fn ) : this.trigger( name ); -// }; -// -// if ( jQuery.attrFn ) { -// jQuery.attrFn[ name ] = true; -// } -// }); - -jQuery.fn[ "blur" ] = function( fn ) { - /// - /// 1: blur() - Triggers the blur event of each matched element. - /// 2: blur(fn) - Binds a function to the blur event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "blur", fn ) : this.trigger( "blur" ); -}; - -jQuery.fn[ "focus" ] = function( fn ) { - /// - /// 1: focus() - Triggers the focus event of each matched element. - /// 2: focus(fn) - Binds a function to the focus event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "focus", fn ) : this.trigger( "focus" ); -}; - -jQuery.fn[ "focusin" ] = function( fn ) { - /// - /// Bind an event handler to the "focusin" JavaScript event. - /// - /// - /// A function to execute each time the event is triggered. - /// - /// - - return fn ? this.bind( "focusin", fn ) : this.trigger( "focusin" ); -}; - -jQuery.fn[ "focusout" ] = function( fn ) { - /// - /// Bind an event handler to the "focusout" JavaScript event. - /// - /// - /// A function to execute each time the event is triggered. - /// - /// - - return fn ? this.bind( "focusout", fn ) : this.trigger( "focusout" ); -}; - -jQuery.fn[ "load" ] = function( fn ) { - /// - /// 1: load() - Triggers the load event of each matched element. - /// 2: load(fn) - Binds a function to the load event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "load", fn ) : this.trigger( "load" ); -}; - -jQuery.fn[ "resize" ] = function( fn ) { - /// - /// 1: resize() - Triggers the resize event of each matched element. - /// 2: resize(fn) - Binds a function to the resize event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "resize", fn ) : this.trigger( "resize" ); -}; - -jQuery.fn[ "scroll" ] = function( fn ) { - /// - /// 1: scroll() - Triggers the scroll event of each matched element. - /// 2: scroll(fn) - Binds a function to the scroll event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "scroll", fn ) : this.trigger( "scroll" ); -}; - -jQuery.fn[ "unload" ] = function( fn ) { - /// - /// 1: unload() - Triggers the unload event of each matched element. - /// 2: unload(fn) - Binds a function to the unload event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "unload", fn ) : this.trigger( "unload" ); -}; - -jQuery.fn[ "click" ] = function( fn ) { - /// - /// 1: click() - Triggers the click event of each matched element. - /// 2: click(fn) - Binds a function to the click event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "click", fn ) : this.trigger( "click" ); -}; - -jQuery.fn[ "dblclick" ] = function( fn ) { - /// - /// 1: dblclick() - Triggers the dblclick event of each matched element. - /// 2: dblclick(fn) - Binds a function to the dblclick event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "dblclick", fn ) : this.trigger( "dblclick" ); -}; - -jQuery.fn[ "mousedown" ] = function( fn ) { - /// - /// Binds a function to the mousedown event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "mousedown", fn ) : this.trigger( "mousedown" ); -}; - -jQuery.fn[ "mouseup" ] = function( fn ) { - /// - /// Bind a function to the mouseup event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "mouseup", fn ) : this.trigger( "mouseup" ); -}; - -jQuery.fn[ "mousemove" ] = function( fn ) { - /// - /// Bind a function to the mousemove event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "mousemove", fn ) : this.trigger( "mousemove" ); -}; - -jQuery.fn[ "mouseover" ] = function( fn ) { - /// - /// Bind a function to the mouseover event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "mouseover", fn ) : this.trigger( "mouseover" ); -}; - -jQuery.fn[ "mouseout" ] = function( fn ) { - /// - /// Bind a function to the mouseout event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "mouseout", fn ) : this.trigger( "mouseout" ); -}; - -jQuery.fn[ "mouseenter" ] = function( fn ) { - /// - /// Bind a function to the mouseenter event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "mouseenter", fn ) : this.trigger( "mouseenter" ); -}; - -jQuery.fn[ "mouseleave" ] = function( fn ) { - /// - /// Bind a function to the mouseleave event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "mouseleave", fn ) : this.trigger( "mouseleave" ); -}; - -jQuery.fn[ "change" ] = function( fn ) { - /// - /// 1: change() - Triggers the change event of each matched element. - /// 2: change(fn) - Binds a function to the change event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "change", fn ) : this.trigger( "change" ); -}; - -jQuery.fn[ "select" ] = function( fn ) { - /// - /// 1: select() - Triggers the select event of each matched element. - /// 2: select(fn) - Binds a function to the select event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "select", fn ) : this.trigger( "select" ); -}; - -jQuery.fn[ "submit" ] = function( fn ) { - /// - /// 1: submit() - Triggers the submit event of each matched element. - /// 2: submit(fn) - Binds a function to the submit event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "submit", fn ) : this.trigger( "submit" ); -}; - -jQuery.fn[ "keydown" ] = function( fn ) { - /// - /// 1: keydown() - Triggers the keydown event of each matched element. - /// 2: keydown(fn) - Binds a function to the keydown event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "keydown", fn ) : this.trigger( "keydown" ); -}; - -jQuery.fn[ "keypress" ] = function( fn ) { - /// - /// 1: keypress() - Triggers the keypress event of each matched element. - /// 2: keypress(fn) - Binds a function to the keypress event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "keypress", fn ) : this.trigger( "keypress" ); -}; - -jQuery.fn[ "keyup" ] = function( fn ) { - /// - /// 1: keyup() - Triggers the keyup event of each matched element. - /// 2: keyup(fn) - Binds a function to the keyup event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "keyup", fn ) : this.trigger( "keyup" ); -}; - -jQuery.fn[ "error" ] = function( fn ) { - /// - /// 1: error() - Triggers the error event of each matched element. - /// 2: error(fn) - Binds a function to the error event of each matched element. - /// - /// The function to execute. - /// - - return fn ? this.bind( "error", fn ) : this.trigger( "error" ); -}; - -// Prevent memory leaks in IE -// Window isn't included so as not to unbind existing unload events -// More info: -// - http://isaacschlueter.com/2006/10/msie-memory-leaks/ -if ( window.attachEvent && !window.addEventListener ) { - window.attachEvent("onunload", function() { - for ( var id in jQuery.cache ) { - if ( jQuery.cache[ id ].handle ) { - // Try/Catch is to handle iframes being unloaded, see #4280 - try { - jQuery.event.remove( jQuery.cache[ id ].handle.elem ); - } catch(e) {} - } - } - }); -} -/*! - * Sizzle CSS Selector Engine - v1.0 - * Copyright 2009, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * More information: http://sizzlejs.com/ - */ -(function(){ - -var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, - done = 0, - toString = Object.prototype.toString, - hasDuplicate = false, - baseHasDuplicate = true; - -// Here we check if the JavaScript engine is using some sort of -// optimization where it does not always call our comparision -// function. If that is the case, discard the hasDuplicate value. -// Thus far that includes Google Chrome. -[0, 0].sort(function(){ - baseHasDuplicate = false; - return 0; -}); - -var Sizzle = function(selector, context, results, seed) { - results = results || []; - var origContext = context = context || document; - - if ( context.nodeType !== 1 && context.nodeType !== 9 ) { - return []; - } - - if ( !selector || typeof selector !== "string" ) { - return results; - } - - var parts = [], m, set, checkSet, extra, prune = true, contextXML = isXML(context), - soFar = selector; - - // Reset the position of the chunker regexp (start from head) - while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { - soFar = m[3]; - - parts.push( m[1] ); - - if ( m[2] ) { - extra = m[3]; - break; - } - } - - if ( parts.length > 1 && origPOS.exec( selector ) ) { - if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { - set = posProcess( parts[0] + parts[1], context ); - } else { - set = Expr.relative[ parts[0] ] ? - [ context ] : - Sizzle( parts.shift(), context ); - - while ( parts.length ) { - selector = parts.shift(); - - if ( Expr.relative[ selector ] ) { - selector += parts.shift(); - } - - set = posProcess( selector, set ); - } - } - } else { - // Take a shortcut and set the context if the root selector is an ID - // (but not if it'll be faster if the inner selector is an ID) - if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && - Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { - var ret = Sizzle.find( parts.shift(), context, contextXML ); - context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; - } - - if ( context ) { - var ret = seed ? - { expr: parts.pop(), set: makeArray(seed) } : - Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); - set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; - - if ( parts.length > 0 ) { - checkSet = makeArray(set); - } else { - prune = false; - } - - while ( parts.length ) { - var cur = parts.pop(), pop = cur; - - if ( !Expr.relative[ cur ] ) { - cur = ""; - } else { - pop = parts.pop(); - } - - if ( pop == null ) { - pop = context; - } - - Expr.relative[ cur ]( checkSet, pop, contextXML ); - } - } else { - checkSet = parts = []; - } - } - - if ( !checkSet ) { - checkSet = set; - } - - if ( !checkSet ) { - Sizzle.error( cur || selector ); - } - - if ( toString.call(checkSet) === "[object Array]" ) { - if ( !prune ) { - results.push.apply( results, checkSet ); - } else if ( context && context.nodeType === 1 ) { - for ( var i = 0; checkSet[i] != null; i++ ) { - if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { - results.push( set[i] ); - } - } - } else { - for ( var i = 0; checkSet[i] != null; i++ ) { - if ( checkSet[i] && checkSet[i].nodeType === 1 ) { - results.push( set[i] ); - } - } - } - } else { - makeArray( checkSet, results ); - } - - if ( extra ) { - Sizzle( extra, origContext, results, seed ); - Sizzle.uniqueSort( results ); - } - - return results; -}; - -Sizzle.uniqueSort = function(results){ - /// - /// Removes all duplicate elements from an array of elements. - /// - /// The array to translate - /// The array after translation. - - if ( sortOrder ) { - hasDuplicate = baseHasDuplicate; - results.sort(sortOrder); - - if ( hasDuplicate ) { - for ( var i = 1; i < results.length; i++ ) { - if ( results[i] === results[i-1] ) { - results.splice(i--, 1); - } - } - } - } - - return results; -}; - -Sizzle.matches = function(expr, set){ - return Sizzle(expr, null, null, set); -}; - -Sizzle.find = function(expr, context, isXML){ - var set, match; - - if ( !expr ) { - return []; - } - - for ( var i = 0, l = Expr.order.length; i < l; i++ ) { - var type = Expr.order[i], match; - - if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { - var left = match[1]; - match.splice(1,1); - - if ( left.substr( left.length - 1 ) !== "\\" ) { - match[1] = (match[1] || "").replace(/\\/g, ""); - set = Expr.find[ type ]( match, context, isXML ); - if ( set != null ) { - expr = expr.replace( Expr.match[ type ], "" ); - break; - } - } - } - } - - if ( !set ) { - set = context.getElementsByTagName("*"); - } - - return {set: set, expr: expr}; -}; - -Sizzle.filter = function(expr, set, inplace, not){ - var old = expr, result = [], curLoop = set, match, anyFound, - isXMLFilter = set && set[0] && isXML(set[0]); - - while ( expr && set.length ) { - for ( var type in Expr.filter ) { - if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { - var filter = Expr.filter[ type ], found, item, left = match[1]; - anyFound = false; - - match.splice(1,1); - - if ( left.substr( left.length - 1 ) === "\\" ) { - continue; - } - - if ( curLoop === result ) { - result = []; - } - - if ( Expr.preFilter[ type ] ) { - match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); - - if ( !match ) { - anyFound = found = true; - } else if ( match === true ) { - continue; - } - } - - if ( match ) { - for ( var i = 0; (item = curLoop[i]) != null; i++ ) { - if ( item ) { - found = filter( item, match, i, curLoop ); - var pass = not ^ !!found; - - if ( inplace && found != null ) { - if ( pass ) { - anyFound = true; - } else { - curLoop[i] = false; - } - } else if ( pass ) { - result.push( item ); - anyFound = true; - } - } - } - } - - if ( found !== undefined ) { - if ( !inplace ) { - curLoop = result; - } - - expr = expr.replace( Expr.match[ type ], "" ); - - if ( !anyFound ) { - return []; - } - - break; - } - } - } - - // Improper expression - if ( expr === old ) { - if ( anyFound == null ) { - Sizzle.error( expr ); - } else { - break; - } - } - - old = expr; - } - - return curLoop; -}; - -Sizzle.error = function( msg ) { - throw "Syntax error, unrecognized expression: " + msg; -}; - -var Expr = Sizzle.selectors = { - order: [ "ID", "NAME", "TAG" ], - match: { - ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, - CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, - NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, - ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, - TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, - CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, - POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, - PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ - }, - leftMatch: {}, - attrMap: { - "class": "className", - "for": "htmlFor" - }, - attrHandle: { - href: function(elem){ - return elem.getAttribute("href"); - } - }, - relative: { - "+": function(checkSet, part){ - var isPartStr = typeof part === "string", - isTag = isPartStr && !/\W/.test(part), - isPartStrNotTag = isPartStr && !isTag; - - if ( isTag ) { - part = part.toLowerCase(); - } - - for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { - if ( (elem = checkSet[i]) ) { - while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} - - checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? - elem || false : - elem === part; - } - } - - if ( isPartStrNotTag ) { - Sizzle.filter( part, checkSet, true ); - } - }, - ">": function(checkSet, part){ - var isPartStr = typeof part === "string"; - - if ( isPartStr && !/\W/.test(part) ) { - part = part.toLowerCase(); - - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - if ( elem ) { - var parent = elem.parentNode; - checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; - } - } - } else { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - if ( elem ) { - checkSet[i] = isPartStr ? - elem.parentNode : - elem.parentNode === part; - } - } - - if ( isPartStr ) { - Sizzle.filter( part, checkSet, true ); - } - } - }, - "": function(checkSet, part, isXML){ - var doneName = done++, checkFn = dirCheck; - - if ( typeof part === "string" && !/\W/.test(part) ) { - var nodeCheck = part = part.toLowerCase(); - checkFn = dirNodeCheck; - } - - checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); - }, - "~": function(checkSet, part, isXML){ - var doneName = done++, checkFn = dirCheck; - - if ( typeof part === "string" && !/\W/.test(part) ) { - var nodeCheck = part = part.toLowerCase(); - checkFn = dirNodeCheck; - } - - checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); - } - }, - find: { - ID: function(match, context, isXML){ - if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); - return m ? [m] : []; - } - }, - NAME: function(match, context){ - if ( typeof context.getElementsByName !== "undefined" ) { - var ret = [], results = context.getElementsByName(match[1]); - - for ( var i = 0, l = results.length; i < l; i++ ) { - if ( results[i].getAttribute("name") === match[1] ) { - ret.push( results[i] ); - } - } - - return ret.length === 0 ? null : ret; - } - }, - TAG: function(match, context){ - return context.getElementsByTagName(match[1]); - } - }, - preFilter: { - CLASS: function(match, curLoop, inplace, result, not, isXML){ - match = " " + match[1].replace(/\\/g, "") + " "; - - if ( isXML ) { - return match; - } - - for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { - if ( elem ) { - if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) { - if ( !inplace ) { - result.push( elem ); - } - } else if ( inplace ) { - curLoop[i] = false; - } - } - } - - return false; - }, - ID: function(match){ - return match[1].replace(/\\/g, ""); - }, - TAG: function(match, curLoop){ - return match[1].toLowerCase(); - }, - CHILD: function(match){ - if ( match[1] === "nth" ) { - // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' - var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( - match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || - !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); - - // calculate the numbers (first)n+(last) including if they are negative - match[2] = (test[1] + (test[2] || 1)) - 0; - match[3] = test[3] - 0; - } - - // TODO: Move to normal caching system - match[0] = done++; - - return match; - }, - ATTR: function(match, curLoop, inplace, result, not, isXML){ - var name = match[1].replace(/\\/g, ""); - - if ( !isXML && Expr.attrMap[name] ) { - match[1] = Expr.attrMap[name]; - } - - if ( match[2] === "~=" ) { - match[4] = " " + match[4] + " "; - } - - return match; - }, - PSEUDO: function(match, curLoop, inplace, result, not){ - if ( match[1] === "not" ) { - // If we're dealing with a complex expression, or a simple one - if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { - match[3] = Sizzle(match[3], null, null, curLoop); - } else { - var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); - if ( !inplace ) { - result.push.apply( result, ret ); - } - return false; - } - } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { - return true; - } - - return match; - }, - POS: function(match){ - match.unshift( true ); - return match; - } - }, - filters: { - enabled: function(elem){ - return elem.disabled === false && elem.type !== "hidden"; - }, - disabled: function(elem){ - return elem.disabled === true; - }, - checked: function(elem){ - return elem.checked === true; - }, - selected: function(elem){ - // Accessing this property makes selected-by-default - // options in Safari work properly - elem.parentNode.selectedIndex; - return elem.selected === true; - }, - parent: function(elem){ - return !!elem.firstChild; - }, - empty: function(elem){ - return !elem.firstChild; - }, - has: function(elem, i, match){ - /// - /// Internal use only; use hasClass('class') - /// - /// - - return !!Sizzle( match[3], elem ).length; - }, - header: function(elem){ - return /h\d/i.test( elem.nodeName ); - }, - text: function(elem){ - return "text" === elem.type; - }, - radio: function(elem){ - return "radio" === elem.type; - }, - checkbox: function(elem){ - return "checkbox" === elem.type; - }, - file: function(elem){ - return "file" === elem.type; - }, - password: function(elem){ - return "password" === elem.type; - }, - submit: function(elem){ - return "submit" === elem.type; - }, - image: function(elem){ - return "image" === elem.type; - }, - reset: function(elem){ - return "reset" === elem.type; - }, - button: function(elem){ - return "button" === elem.type || elem.nodeName.toLowerCase() === "button"; - }, - input: function(elem){ - return /input|select|textarea|button/i.test(elem.nodeName); - } - }, - setFilters: { - first: function(elem, i){ - return i === 0; - }, - last: function(elem, i, match, array){ - return i === array.length - 1; - }, - even: function(elem, i){ - return i % 2 === 0; - }, - odd: function(elem, i){ - return i % 2 === 1; - }, - lt: function(elem, i, match){ - return i < match[3] - 0; - }, - gt: function(elem, i, match){ - return i > match[3] - 0; - }, - nth: function(elem, i, match){ - return match[3] - 0 === i; - }, - eq: function(elem, i, match){ - return match[3] - 0 === i; - } - }, - filter: { - PSEUDO: function(elem, match, i, array){ - var name = match[1], filter = Expr.filters[ name ]; - - if ( filter ) { - return filter( elem, i, match, array ); - } else if ( name === "contains" ) { - return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; - } else if ( name === "not" ) { - var not = match[3]; - - for ( var i = 0, l = not.length; i < l; i++ ) { - if ( not[i] === elem ) { - return false; - } - } - - return true; - } else { - Sizzle.error( "Syntax error, unrecognized expression: " + name ); - } - }, - CHILD: function(elem, match){ - var type = match[1], node = elem; - switch (type) { - case 'only': - case 'first': - while ( (node = node.previousSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - if ( type === "first" ) { - return true; - } - node = elem; - case 'last': - while ( (node = node.nextSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - return true; - case 'nth': - var first = match[2], last = match[3]; - - if ( first === 1 && last === 0 ) { - return true; - } - - var doneName = match[0], - parent = elem.parentNode; - - if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { - var count = 0; - for ( node = parent.firstChild; node; node = node.nextSibling ) { - if ( node.nodeType === 1 ) { - node.nodeIndex = ++count; - } - } - parent.sizcache = doneName; - } - - var diff = elem.nodeIndex - last; - if ( first === 0 ) { - return diff === 0; - } else { - return ( diff % first === 0 && diff / first >= 0 ); - } - } - }, - ID: function(elem, match){ - return elem.nodeType === 1 && elem.getAttribute("id") === match; - }, - TAG: function(elem, match){ - return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; - }, - CLASS: function(elem, match){ - return (" " + (elem.className || elem.getAttribute("class")) + " ") - .indexOf( match ) > -1; - }, - ATTR: function(elem, match){ - var name = match[1], - result = Expr.attrHandle[ name ] ? - Expr.attrHandle[ name ]( elem ) : - elem[ name ] != null ? - elem[ name ] : - elem.getAttribute( name ), - value = result + "", - type = match[2], - check = match[4]; - - return result == null ? - type === "!=" : - type === "=" ? - value === check : - type === "*=" ? - value.indexOf(check) >= 0 : - type === "~=" ? - (" " + value + " ").indexOf(check) >= 0 : - !check ? - value && result !== false : - type === "!=" ? - value !== check : - type === "^=" ? - value.indexOf(check) === 0 : - type === "$=" ? - value.substr(value.length - check.length) === check : - type === "|=" ? - value === check || value.substr(0, check.length + 1) === check + "-" : - false; - }, - POS: function(elem, match, i, array){ - var name = match[2], filter = Expr.setFilters[ name ]; - - if ( filter ) { - return filter( elem, i, match, array ); - } - } - } -}; - -var origPOS = Expr.match.POS; - -for ( var type in Expr.match ) { - Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); - Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, function(all, num){ - return "\\" + (num - 0 + 1); - })); -} - -var makeArray = function(array, results) { - array = Array.prototype.slice.call( array, 0 ); - - if ( results ) { - results.push.apply( results, array ); - return results; - } - - return array; -}; - -// Perform a simple check to determine if the browser is capable of -// converting a NodeList to an array using builtin methods. -try { - Array.prototype.slice.call( document.documentElement.childNodes, 0 ); - -// Provide a fallback method if it does not work -} catch(e){ - makeArray = function(array, results) { - var ret = results || []; - - if ( toString.call(array) === "[object Array]" ) { - Array.prototype.push.apply( ret, array ); - } else { - if ( typeof array.length === "number" ) { - for ( var i = 0, l = array.length; i < l; i++ ) { - ret.push( array[i] ); - } - } else { - for ( var i = 0; array[i]; i++ ) { - ret.push( array[i] ); - } - } - } - - return ret; - }; -} - -var sortOrder; - -if ( document.documentElement.compareDocumentPosition ) { - sortOrder = function( a, b ) { - if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { - if ( a == b ) { - hasDuplicate = true; - } - return a.compareDocumentPosition ? -1 : 1; - } - - var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; - if ( ret === 0 ) { - hasDuplicate = true; - } - return ret; - }; -} else if ( "sourceIndex" in document.documentElement ) { - sortOrder = function( a, b ) { - if ( !a.sourceIndex || !b.sourceIndex ) { - if ( a == b ) { - hasDuplicate = true; - } - return a.sourceIndex ? -1 : 1; - } - - var ret = a.sourceIndex - b.sourceIndex; - if ( ret === 0 ) { - hasDuplicate = true; - } - return ret; - }; -} else if ( document.createRange ) { - sortOrder = function( a, b ) { - if ( !a.ownerDocument || !b.ownerDocument ) { - if ( a == b ) { - hasDuplicate = true; - } - return a.ownerDocument ? -1 : 1; - } - - var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); - aRange.setStart(a, 0); - aRange.setEnd(a, 0); - bRange.setStart(b, 0); - bRange.setEnd(b, 0); - var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); - if ( ret === 0 ) { - hasDuplicate = true; - } - return ret; - }; -} - -// Utility function for retreiving the text value of an array of DOM nodes -function getText( elems ) { - var ret = "", elem; - - for ( var i = 0; elems[i]; i++ ) { - elem = elems[i]; - - // Get the text from text nodes and CDATA nodes - if ( elem.nodeType === 3 || elem.nodeType === 4 ) { - ret += elem.nodeValue; - - // Traverse everything else, except comment nodes - } else if ( elem.nodeType !== 8 ) { - ret += getText( elem.childNodes ); - } - } - - return ret; -} - -// [vsdoc] The following function has been modified for IntelliSense. -// Check to see if the browser returns elements by name when -// querying by getElementById (and provide a workaround) -(function(){ - // We're going to inject a fake input element with a specified name - // var form = document.createElement("div"), - // id = "script" + (new Date).getTime(); - // form.innerHTML = ""; - - // // Inject it into the root element, check its status, and remove it quickly - // var root = document.documentElement; - // root.insertBefore( form, root.firstChild ); - - // The workaround has to do additional checks after a getElementById - // Which slows things down for other browsers (hence the branching) - // if ( document.getElementById( id ) ) { - Expr.find.ID = function(match, context, isXML){ - if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); - return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; - } - }; - - Expr.filter.ID = function(elem, match){ - var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); - return elem.nodeType === 1 && node && node.nodeValue === match; - }; - // } - - // root.removeChild( form ); - root = form = null; // release memory in IE -})(); - -// [vsdoc] The following function has been modified for IntelliSense. -(function(){ - // Check to see if the browser returns only elements - // when doing getElementsByTagName("*") - - // Create a fake element - // var div = document.createElement("div"); - // div.appendChild( document.createComment("") ); - - // Make sure no comments are found - // if ( div.getElementsByTagName("*").length > 0 ) { - Expr.find.TAG = function(match, context){ - var results = context.getElementsByTagName(match[1]); - - // Filter out possible comments - if ( match[1] === "*" ) { - var tmp = []; - - for ( var i = 0; results[i]; i++ ) { - if ( results[i].nodeType === 1 ) { - tmp.push( results[i] ); - } - } - - results = tmp; - } - - return results; - }; - // } - - // Check to see if an attribute returns normalized href attributes - // div.innerHTML = ""; - // if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && - // div.firstChild.getAttribute("href") !== "#" ) { - Expr.attrHandle.href = function(elem){ - return elem.getAttribute("href", 2); - }; - // } - - div = null; // release memory in IE -})(); - -if ( document.querySelectorAll ) { - (function(){ - var oldSizzle = Sizzle, div = document.createElement("div"); - div.innerHTML = "

"; - - // Safari can't handle uppercase or unicode characters when - // in quirks mode. - if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { - return; - } - - Sizzle = function(query, context, extra, seed){ - context = context || document; - - // Only use querySelectorAll on non-XML documents - // (ID selectors don't work in non-HTML documents) - if ( !seed && context.nodeType === 9 && !isXML(context) ) { - try { - return makeArray( context.querySelectorAll(query), extra ); - } catch(e){} - } - - return oldSizzle(query, context, extra, seed); - }; - - for ( var prop in oldSizzle ) { - Sizzle[ prop ] = oldSizzle[ prop ]; - } - - div = null; // release memory in IE - })(); -} - -(function(){ - var div = document.createElement("div"); - - div.innerHTML = "
"; - - // Opera can't find a second classname (in 9.6) - // Also, make sure that getElementsByClassName actually exists - if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { - return; - } - - // Safari caches class attributes, doesn't catch changes (in 3.2) - div.lastChild.className = "e"; - - if ( div.getElementsByClassName("e").length === 1 ) { - return; - } - - Expr.order.splice(1, 0, "CLASS"); - Expr.find.CLASS = function(match, context, isXML) { - if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { - return context.getElementsByClassName(match[1]); - } - }; - - div = null; // release memory in IE -})(); - -function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - if ( elem ) { - elem = elem[dir]; - var match = false; - - while ( elem ) { - if ( elem.sizcache === doneName ) { - match = checkSet[elem.sizset]; - break; - } - - if ( elem.nodeType === 1 && !isXML ){ - elem.sizcache = doneName; - elem.sizset = i; - } - - if ( elem.nodeName.toLowerCase() === cur ) { - match = elem; - break; - } - - elem = elem[dir]; - } - - checkSet[i] = match; - } - } -} - -function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - if ( elem ) { - elem = elem[dir]; - var match = false; - - while ( elem ) { - if ( elem.sizcache === doneName ) { - match = checkSet[elem.sizset]; - break; - } - - if ( elem.nodeType === 1 ) { - if ( !isXML ) { - elem.sizcache = doneName; - elem.sizset = i; - } - if ( typeof cur !== "string" ) { - if ( elem === cur ) { - match = true; - break; - } - - } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { - match = elem; - break; - } - } - - elem = elem[dir]; - } - - checkSet[i] = match; - } - } -} - -var contains = document.compareDocumentPosition ? function(a, b){ - /// - /// Check to see if a DOM node is within another DOM node. - /// - /// - /// The DOM element that may contain the other element. - /// - /// - /// The DOM node that may be contained by the other element. - /// - /// - - return a.compareDocumentPosition(b) & 16; -} : function(a, b){ - /// - /// Check to see if a DOM node is within another DOM node. - /// - /// - /// The DOM element that may contain the other element. - /// - /// - /// The DOM node that may be contained by the other element. - /// - /// - - return a !== b && (a.contains ? a.contains(b) : true); -}; - -var isXML = function(elem){ - /// - /// Determines if the parameter passed is an XML document. - /// - /// The object to test - /// True if the parameter is an XML document; otherwise false. - - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -var posProcess = function(selector, context){ - var tmpSet = [], later = "", match, - root = context.nodeType ? [context] : context; - - // Position selectors must be done after the filter - // And so must :not(positional) so we move all PSEUDOs to the end - while ( (match = Expr.match.PSEUDO.exec( selector )) ) { - later += match[0]; - selector = selector.replace( Expr.match.PSEUDO, "" ); - } - - selector = Expr.relative[selector] ? selector + "*" : selector; - - for ( var i = 0, l = root.length; i < l; i++ ) { - Sizzle( selector, root[i], tmpSet ); - } - - return Sizzle.filter( later, tmpSet ); -}; - -// EXPOSE -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.filters; -jQuery.unique = Sizzle.uniqueSort; -jQuery.getText = getText; -jQuery.isXMLDoc = isXML; -jQuery.contains = contains; - -return; - -window.Sizzle = Sizzle; - -})(); -var runtil = /Until$/, - rparentsprev = /^(?:parents|prevUntil|prevAll)/, - // Note: This RegExp should be improved, or likely pulled from Sizzle - rmultiselector = /,/, - slice = Array.prototype.slice; - -// Implement the identical functionality for filter and not -var winnow = function( elements, qualifier, keep ) { - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep(elements, function( elem, i ) { - return !!qualifier.call( elem, i, elem ) === keep; - }); - - } else if ( qualifier.nodeType ) { - return jQuery.grep(elements, function( elem, i ) { - return (elem === qualifier) === keep; - }); - - } else if ( typeof qualifier === "string" ) { - var filtered = jQuery.grep(elements, function( elem ) { - return elem.nodeType === 1; - }); - - if ( isSimple.test( qualifier ) ) { - return jQuery.filter(qualifier, filtered, !keep); - } else { - qualifier = jQuery.filter( qualifier, filtered ); - } - } - - return jQuery.grep(elements, function( elem, i ) { - return (jQuery.inArray( elem, qualifier ) >= 0) === keep; - }); -}; - -jQuery.fn.extend({ - find: function( selector ) { - /// - /// Searches for all elements that match the specified expression. - /// This method is a good way to find additional descendant - /// elements with which to process. - /// All searching is done using a jQuery expression. The expression can be - /// written using CSS 1-3 Selector syntax, or basic XPath. - /// Part of DOM/Traversing - /// - /// - /// - /// An expression to search with. - /// - /// - - var ret = this.pushStack( "", "find", selector ), length = 0; - - for ( var i = 0, l = this.length; i < l; i++ ) { - length = ret.length; - jQuery.find( selector, this[i], ret ); - - if ( i > 0 ) { - // Make sure that the results are unique - for ( var n = length; n < ret.length; n++ ) { - for ( var r = 0; r < length; r++ ) { - if ( ret[r] === ret[n] ) { - ret.splice(n--, 1); - break; - } - } - } - } - } - - return ret; - }, - - has: function( target ) { - /// - /// Reduce the set of matched elements to those that have a descendant that matches the - /// selector or DOM element. - /// - /// - /// A string containing a selector expression to match elements against. - /// - /// - - var targets = jQuery( target ); - return this.filter(function() { - for ( var i = 0, l = targets.length; i < l; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; - } - } - }); - }, - - not: function( selector ) { - /// - /// Removes any elements inside the array of elements from the set - /// of matched elements. This method is used to remove one or more - /// elements from a jQuery object. - /// Part of DOM/Traversing - /// - /// - /// A set of elements to remove from the jQuery set of matched elements. - /// - /// - - return this.pushStack( winnow(this, selector, false), "not", selector); - }, - - filter: function( selector ) { - /// - /// Removes all elements from the set of matched elements that do not - /// pass the specified filter. This method is used to narrow down - /// the results of a search. - /// }) - /// Part of DOM/Traversing - /// - /// - /// - /// A function to use for filtering - /// - /// - - return this.pushStack( winnow(this, selector, true), "filter", selector ); - }, - - is: function( selector ) { - /// - /// Checks the current selection against an expression and returns true, - /// if at least one element of the selection fits the given expression. - /// Does return false, if no element fits or the expression is not valid. - /// filter(String) is used internally, therefore all rules that apply there - /// apply here, too. - /// Part of DOM/Traversing - /// - /// - /// - /// The expression with which to filter - /// - - return !!selector && jQuery.filter( selector, this ).length > 0; - }, - - closest: function( selectors, context ) { - /// - /// Get a set of elements containing the closest parent element that matches the specified selector, the starting element included. - /// - /// - /// A string containing a selector expression to match elements against. - /// - /// - /// A DOM element within which a matching element may be found. If no context is passed - /// in then the context of the jQuery set will be used instead. - /// - /// - - if ( jQuery.isArray( selectors ) ) { - var ret = [], cur = this[0], match, matches = {}, selector; - - if ( cur && selectors.length ) { - for ( var i = 0, l = selectors.length; i < l; i++ ) { - selector = selectors[i]; - - if ( !matches[selector] ) { - matches[selector] = jQuery.expr.match.POS.test( selector ) ? - jQuery( selector, context || this.context ) : - selector; - } - } - - while ( cur && cur.ownerDocument && cur !== context ) { - for ( selector in matches ) { - match = matches[selector]; - - if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) { - ret.push({ selector: selector, elem: cur }); - delete matches[selector]; - } - } - cur = cur.parentNode; - } - } - - return ret; - } - - var pos = jQuery.expr.match.POS.test( selectors ) ? - jQuery( selectors, context || this.context ) : null; - - return this.map(function( i, cur ) { - while ( cur && cur.ownerDocument && cur !== context ) { - if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selectors) ) { - return cur; - } - cur = cur.parentNode; - } - return null; - }); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - /// - /// Searches every matched element for the object and returns - /// the index of the element, if found, starting with zero. - /// Returns -1 if the object wasn't found. - /// Part of Core - /// - /// - /// - /// Object to search for - /// - - if ( !elem || typeof elem === "string" ) { - return jQuery.inArray( this[0], - // If it receives a string, the selector is used - // If it receives nothing, the siblings are used - elem ? jQuery( elem ) : this.parent().children() ); - } - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[0] : elem, this ); - }, - - add: function( selector, context ) { - /// - /// Adds one or more Elements to the set of matched elements. - /// Part of DOM/Traversing - /// - /// - /// A string containing a selector expression to match additional elements against. - /// - /// - /// Add some elements rooted against the specified context. - /// - /// - - var set = typeof selector === "string" ? - jQuery( selector, context || this.context ) : - jQuery.makeArray( selector ), - all = jQuery.merge( this.get(), set ); - - return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? - all : - jQuery.unique( all ) ); - }, - - andSelf: function() { - /// - /// Adds the previous selection to the current selection. - /// - /// - - return this.add( this.prevObject ); - } -}); - -// A painfully simple check to see if an element is disconnected -// from a document (should be improved, where feasible). -function isDisconnected( node ) { - return !node || !node.parentNode || node.parentNode.nodeType === 11; -} - -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - next: function( elem ) { - return jQuery.nth( elem, 2, "nextSibling" ); - }, - prev: function( elem ) { - return jQuery.nth( elem, 2, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - siblings: function( elem ) { - return jQuery.sibling( elem.parentNode.firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.makeArray( elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ); - - if ( !runtil.test( name ) ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - ret = this.length > 1 ? jQuery.unique( ret ) : ret; - - if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { - ret = ret.reverse(); - } - - return this.pushStack( ret, name, slice.call(arguments).join(",") ); - }; -}); - -jQuery.fn[ "parentsUntil" ] = function( until, selector ) { - /// - /// Get the ancestors of each element in the current set of matched elements, up to but not - /// including the element matched by the selector. - /// - /// - /// A string containing a selector expression to indicate where to stop matching ancestor - /// elements. - /// - /// - - var fn = function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - } - - var ret = jQuery.map( this, fn, until ); - - if ( !runtil.test( "parentsUntil" ) ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - ret = this.length > 1 ? jQuery.unique( ret ) : ret; - - if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( "parentsUntil" ) ) { - ret = ret.reverse(); - } - - return this.pushStack( ret, "parentsUntil", slice.call(arguments).join(",") ); -}; - -jQuery.fn[ "nextUntil" ] = function( until, selector ) { - /// - /// Get all following siblings of each element up to but not including the element matched - /// by the selector. - /// - /// - /// A string containing a selector expression to indicate where to stop matching following - /// sibling elements. - /// - /// - - var fn = function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - } - - var ret = jQuery.map( this, fn, until ); - - if ( !runtil.test( "nextUntil" ) ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - ret = this.length > 1 ? jQuery.unique( ret ) : ret; - - if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( "nextUntil" ) ) { - ret = ret.reverse(); - } - - return this.pushStack( ret, "nextUntil", slice.call(arguments).join(",") ); -}; - -jQuery.fn[ "prevUntil" ] = function( until, selector ) { - /// - /// Get all preceding siblings of each element up to but not including the element matched - /// by the selector. - /// - /// - /// A string containing a selector expression to indicate where to stop matching preceding - /// sibling elements. - /// - /// - - var fn = function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - } - - var ret = jQuery.map( this, fn, until ); - - if ( !runtil.test( "prevUntil" ) ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - ret = this.length > 1 ? jQuery.unique( ret ) : ret; - - if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( "prevUntil" ) ) { - ret = ret.reverse(); - } - - return this.pushStack( ret, "prevUntil", slice.call(arguments).join(",") ); -}; - -jQuery.extend({ - filter: function( expr, elems, not ) { - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return jQuery.find.matches(expr, elems); - }, - - dir: function( elem, dir, until ) { - /// - /// This member is internal only. - /// - /// - - var matched = [], cur = elem[dir]; - while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { - if ( cur.nodeType === 1 ) { - matched.push( cur ); - } - cur = cur[dir]; - } - return matched; - }, - - nth: function( cur, result, dir, elem ) { - /// - /// This member is internal only. - /// - /// - - result = result || 1; - var num = 0; - - for ( ; cur; cur = cur[dir] ) { - if ( cur.nodeType === 1 && ++num === result ) { - break; - } - } - - return cur; - }, - - sibling: function( n, elem ) { - /// - /// This member is internal only. - /// - /// - - var r = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - r.push( n ); - } - } - - return r; - } -}); -var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, - rleadingWhitespace = /^\s+/, - rxhtmlTag = /(<([\w:]+)[^>]*?)\/>/g, - rselfClosing = /^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i, - rtagName = /<([\w:]+)/, - rtbody = /"; - }, - wrapMap = { - option: [ 1, "" ], - legend: [ 1, "
", "
" ], - thead: [ 1, "", "
" ], - tr: [ 2, "", "
" ], - td: [ 3, "", "
" ], - col: [ 2, "", "
" ], - area: [ 1, "", "" ], - _default: [ 0, "", "" ] - }; - -wrapMap.optgroup = wrapMap.option; -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -// IE can't serialize and