idea ide updates
idea ide updates

--- /dev/null
+++ b/.idea/compiler.xml
@@ -1,1 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <option name="DEFAULT_COMPILER" value="Javac" />
+    <resourceExtensions />
+    <wildcardResourcePatterns>
+      <entry name="!?*.java" />
+      <entry name="!?*.form" />
+      <entry name="!?*.class" />
+      <entry name="!?*.groovy" />
+      <entry name="!?*.scala" />
+      <entry name="!?*.flex" />
+      <entry name="!?*.kt" />
+      <entry name="!?*.clj" />
+    </wildcardResourcePatterns>
+    <annotationProcessing>
+      <profile default="true" name="Default" enabled="false">
+        <processorPath useClasspath="true" />
+      </profile>
+    </annotationProcessing>
+  </component>
+</project>
 
+

--- /dev/null
+++ b/.idea/copyright/profiles_settings.xml
@@ -1,1 +1,5 @@
-
+<component name="CopyrightManager">
+  <settings default="">
+    <module2copyright />
+  </settings>
+</component>

--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,7 +3,7 @@
   <component name="ProjectResources">
     <default-html-doctype>jar:file:\C:\Program Files (x86)\JetBrains\PhpStorm 5.0.2\lib\webide.jar!\resources\html5-schema\html5.rnc</default-html-doctype>
   </component>
-  <component name="ProjectRootManager" version="2" />
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_3" assert-keyword="false" jdk-15="false" />
 </project>
 
 

--- a/.idea/scannr.iml
+++ b/.idea/scannr.iml
@@ -1,6 +1,11 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <module type="WEB_MODULE" version="4">
-  <component name="NewModuleRootManager">
+  <component name="FacetManager">
+    <facet type="Python" name="Python">
+      <configuration sdkName="" />
+    </facet>
+  </component>
+  <component name="NewModuleRootManager" inherit-compiler-output="false">
     <content url="file://$MODULE_DIR$" />
     <orderEntry type="inheritedJdk" />
     <orderEntry type="sourceFolder" forTests="false" />

--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -1,1 +1,126 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Palette2">
+    <group name="Swing">
+      <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
+      </item>
+      <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
+        <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
+        <initial-values>
+          <property name="text" value="Button" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="RadioButton" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="CheckBox" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="Label" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
+          <preferred-size width="-1" height="20" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
+      </item>
+    </group>
+  </component>
+</project>
 
+

--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -2,11 +2,66 @@
 <project version="4">
   <component name="ChangeListManager">
     <list default="true" id="f90ee5b5-97e4-47ec-9b14-d4f4e896f100" name="Default" comment="">
-      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/output.txt" afterPath="$PROJECT_DIR$/output.txt" />
+      <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/.idea/compiler.xml" />
+      <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/.idea/copyright/profiles_settings.xml" />
+      <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/.idea/uiDesigner.xml" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/404.html" afterPath="$PROJECT_DIR$/404.html" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/spec/Chart.js" afterPath="$PROJECT_DIR$/js/flotr2/spec/Chart.js" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/spec/Color.js" afterPath="$PROJECT_DIR$/js/flotr2/spec/Color.js" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/spec/Flotr.js" afterPath="$PROJECT_DIR$/js/flotr2/spec/Flotr.js" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/spec/Graph.js" afterPath="$PROJECT_DIR$/js/flotr2/spec/Graph.js" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/lib/base64.js" afterPath="$PROJECT_DIR$/js/flotr2/lib/base64.js" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/make/basic.json" afterPath="$PROJECT_DIR$/js/flotr2/make/basic.json" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/make/build.json" afterPath="$PROJECT_DIR$/js/flotr2/make/build.json" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/calllog.php" afterPath="$PROJECT_DIR$/calllog.php" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/calls.json.php" afterPath="$PROJECT_DIR$/calls.json.php" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/common.inc.php" afterPath="$PROJECT_DIR$/common.inc.php" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/examples/old_examples/examples.js" afterPath="$PROJECT_DIR$/js/flotr2/examples/old_examples/examples.js" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/make/examples.json" afterPath="$PROJECT_DIR$/js/flotr2/make/examples.json" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/examples/old_examples/extending-flotr.html" afterPath="$PROJECT_DIR$/js/flotr2/examples/old_examples/extending-flotr.html" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/make/flotr2.json" afterPath="$PROJECT_DIR$/js/flotr2/make/flotr2.json" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/spec/js/flotr2.stable.js" afterPath="$PROJECT_DIR$/js/flotr2/spec/js/flotr2.stable.js" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/examples/lib/codemirror/lib/util/formatting.js" afterPath="$PROJECT_DIR$/js/flotr2/examples/lib/codemirror/lib/util/formatting.js" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/generateConvos.php" afterPath="$PROJECT_DIR$/generateConvos.php" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/getfile.php" afterPath="$PROJECT_DIR$/getfile.php" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/make/ie.json" afterPath="$PROJECT_DIR$/js/flotr2/make/ie.json" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/examples/old_examples/index.html" afterPath="$PROJECT_DIR$/js/flotr2/examples/old_examples/index.html" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/spec/index.html" afterPath="$PROJECT_DIR$/js/flotr2/spec/index.html" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/lib/jasmine/jasmine-html.js" afterPath="$PROJECT_DIR$/js/flotr2/lib/jasmine/jasmine-html.js" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/lib/jasmine/jasmine.css" afterPath="$PROJECT_DIR$/js/flotr2/lib/jasmine/jasmine.css" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/lib/jasmine/jasmine.js" afterPath="$PROJECT_DIR$/js/flotr2/lib/jasmine/jasmine.js" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/vendor/jquery-1.8.0.min.js" afterPath="$PROJECT_DIR$/js/vendor/jquery-1.8.0.min.js" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/examples/old_examples/json-data.html" afterPath="$PROJECT_DIR$/js/flotr2/examples/old_examples/json-data.html" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/examples/old_examples/json-real-data.html" afterPath="$PROJECT_DIR$/js/flotr2/examples/old_examples/json-real-data.html" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/examples/old_examples/json.txt" afterPath="$PROJECT_DIR$/js/flotr2/examples/old_examples/json.txt" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/make/lib.json" afterPath="$PROJECT_DIR$/js/flotr2/make/lib.json" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/examples/old_examples/logarithmic-scale.html" afterPath="$PROJECT_DIR$/js/flotr2/examples/old_examples/logarithmic-scale.html" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/.idea/misc.xml" afterPath="$PROJECT_DIR$/.idea/misc.xml" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/vendor/modernizr-2.6.1.min.js" afterPath="$PROJECT_DIR$/js/vendor/modernizr-2.6.1.min.js" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/examples/old_examples/mouse-zoom-preview.html" afterPath="$PROJECT_DIR$/js/flotr2/examples/old_examples/mouse-zoom-preview.html" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/nbproject/project.xml" afterPath="$PROJECT_DIR$/nbproject/project.xml" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/lib/prototype.js" afterPath="$PROJECT_DIR$/js/flotr2/lib/prototype.js" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/.idea/scannr.iml" afterPath="$PROJECT_DIR$/.idea/scannr.iml" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/scannr.py" afterPath="$PROJECT_DIR$/scannr.py" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/snd.py" afterPath="$PROJECT_DIR$/snd.py" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/examples/old_examples/style.css" afterPath="$PROJECT_DIR$/js/flotr2/examples/old_examples/style.css" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/spec/js/test-background.js" afterPath="$PROJECT_DIR$/js/flotr2/spec/js/test-background.js" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/spec/js/test-boundaries.js" afterPath="$PROJECT_DIR$/js/flotr2/spec/js/test-boundaries.js" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/js/flotr2/spec/js/test-mountain-nulls.js" afterPath="$PROJECT_DIR$/js/flotr2/spec/js/test-mountain-nulls.js" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/test.py" afterPath="$PROJECT_DIR$/test.py" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/test2.py" afterPath="$PROJECT_DIR$/test2.py" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/trunklog.php" afterPath="$PROJECT_DIR$/trunklog.php" />
       <change type="MODIFICATION" beforePath="$PROJECT_DIR$/viewcalls.php" afterPath="$PROJECT_DIR$/viewcalls.php" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/.idea/workspace.xml" afterPath="$PROJECT_DIR$/.idea/workspace.xml" />
     </list>
     <ignored path="scannr.iws" />
     <ignored path=".idea/workspace.xml" />
+    <file path="/Dummy.txt" changelist="f90ee5b5-97e4-47ec-9b14-d4f4e896f100" time="1356154429152" ignored="false" />
+    <file path="/calllog.php" changelist="f90ee5b5-97e4-47ec-9b14-d4f4e896f100" time="1356153807482" ignored="false" />
+    <file path="/scannr.py" changelist="f90ee5b5-97e4-47ec-9b14-d4f4e896f100" time="1356154551131" ignored="false" />
+    <file path="/start_script.py" changelist="f90ee5b5-97e4-47ec-9b14-d4f4e896f100" time="1356155203132" ignored="false" />
+    <file path="/a.java" changelist="f90ee5b5-97e4-47ec-9b14-d4f4e896f100" time="1356155211924" ignored="false" />
+    <file path="/a.php" changelist="f90ee5b5-97e4-47ec-9b14-d4f4e896f100" time="1356155216083" ignored="false" />
     <option name="TRACKING_ENABLED" value="true" />
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -20,33 +75,64 @@
   <component name="DaemonCodeAnalyzer">
     <disable_hints />
   </component>
+  <component name="DebuggerManager">
+    <ui_properties default_suspend_policy="SuspendAll" default_condition_enabled="true" />
+    <breakpoint_any default_suspend_policy="SuspendAll" default_condition_enabled="true">
+      <breakpoint>
+        <option name="NOTIFY_CAUGHT" value="true" />
+        <option name="NOTIFY_UNCAUGHT" value="true" />
+        <option name="ENABLED" value="false" />
+        <option name="LOG_ENABLED" value="false" />
+        <option name="LOG_EXPRESSION_ENABLED" value="false" />
+        <option name="SUSPEND_POLICY" value="SuspendAll" />
+        <option name="SUSPEND" value="true" />
+        <option name="COUNT_FILTER_ENABLED" value="false" />
+        <option name="COUNT_FILTER" value="0" />
+        <option name="CONDITION_ENABLED" value="true" />
+        <option name="CLASS_FILTERS_ENABLED" value="false" />
+        <option name="INSTANCE_FILTERS_ENABLED" value="false" />
+        <option name="CONDITION" value="" />
+        <option name="LOG_MESSAGE" value="" />
+      </breakpoint>
+      <breakpoint>
+        <option name="NOTIFY_CAUGHT" value="true" />
+        <option name="NOTIFY_UNCAUGHT" value="true" />
+        <option name="ENABLED" value="false" />
+        <option name="LOG_ENABLED" value="false" />
+        <option name="LOG_EXPRESSION_ENABLED" value="false" />
+        <option name="SUSPEND_POLICY" value="SuspendAll" />
+        <option name="SUSPEND" value="true" />
+        <option name="COUNT_FILTER_ENABLED" value="false" />
+        <option name="COUNT_FILTER" value="0" />
+        <option name="CONDITION_ENABLED" value="true" />
+        <option name="CLASS_FILTERS_ENABLED" value="false" />
+        <option name="INSTANCE_FILTERS_ENABLED" value="false" />
+        <option name="CONDITION" value="" />
+        <option name="LOG_MESSAGE" value="" />
+      </breakpoint>
+    </breakpoint_any>
+    <breakpoint_rules />
+    <ui_properties />
+  </component>
   <component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
+  <component name="FavoritesManager">
+    <favorites_list name="scannr" />
+  </component>
   <component name="FileEditorManager">
     <leaf>
-      <file leaf-file-name="viewcalls.php" pinned="false" current="true" current-in-tab="true">
-        <entry file="file://$PROJECT_DIR$/viewcalls.php">
+      <file leaf-file-name="calllog.php" pinned="false" current="false" current-in-tab="false">
+        <entry file="file://$PROJECT_DIR$/calllog.php">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="41" column="69" selection-start="1388" selection-end="1388" vertical-scroll-proportion="1.2659575">
-              <folding>
-                <element signature="e#255#287#0" expanded="true" />
-              </folding>
-            </state>
-          </provider>
-        </entry>
-      </file>
-      <file leaf-file-name="common.inc.php" pinned="false" current="false" current-in-tab="false">
-        <entry file="file://$PROJECT_DIR$/common.inc.php">
-          <provider selected="true" editor-type-id="text-editor">
-            <state line="60" column="117" selection-start="2262" selection-end="2262" vertical-scroll-proportion="-39.23077">
+            <state line="9" column="0" selection-start="189" selection-end="189" vertical-scroll-proportion="0.0">
               <folding />
             </state>
           </provider>
         </entry>
       </file>
-      <file leaf-file-name="calls.json.php" pinned="false" current="false" current-in-tab="false">
-        <entry file="file://$PROJECT_DIR$/calls.json.php">
+      <file leaf-file-name="scannr.py" pinned="false" current="true" current-in-tab="true">
+        <entry file="file://$PROJECT_DIR$/scannr.py">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="72" column="41" selection-start="2843" selection-end="2843" vertical-scroll-proportion="-43.153847">
+            <state line="80" column="64" selection-start="2271" selection-end="2271" vertical-scroll-proportion="-0.31178707">
               <folding />
             </state>
           </provider>
@@ -60,23 +146,30 @@
     </FindUsagesManager>
   </component>
   <component name="Git.Settings">
+    <option name="SYNC_SETTING" value="DONT" />
     <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
+  </component>
+  <component name="GitLogSettings">
+    <option name="myDateState">
+      <MyDateState />
+    </option>
   </component>
   <component name="IdeDocumentHistory">
     <option name="changedFiles">
       <list>
-        <option value="$PROJECT_DIR$/scannr.py" />
         <option value="$PROJECT_DIR$/common.inc.php" />
         <option value="$PROJECT_DIR$/calls.json.php" />
         <option value="$PROJECT_DIR$/viewcalls.php" />
+        <option value="$PROJECT_DIR$/calllog.php" />
+        <option value="$PROJECT_DIR$/scannr.py" />
       </list>
     </option>
   </component>
-  <component name="PhpWorkspaceProjectConfiguration" backward_compatibility_performed="true" />
+  <component name="PhpWorkspaceProjectConfiguration" backward_compatibility_performed="true" interpreter_name="PHP" />
   <component name="ProjectFrameBounds">
-    <option name="x" value="619" />
-    <option name="width" value="825" />
-    <option name="height" value="600" />
+    <option name="y" value="22" />
+    <option name="width" value="1680" />
+    <option name="height" value="937" />
   </component>
   <component name="ProjectLevelVcsManager" settingsEditedManually="true">
     <OptionsSetting value="true" id="Add" />
@@ -104,6 +197,7 @@
       <sortByType />
     </navigator>
     <panes>
+      <pane id="PackagesPane" />
       <pane id="ProjectPane">
         <subPane>
           <PATH>
@@ -112,6 +206,16 @@
               <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
             </PATH_ELEMENT>
           </PATH>
+          <PATH>
+            <PATH_ELEMENT>
+              <option name="myItemId" value="scannr" />
+              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
+            </PATH_ELEMENT>
+            <PATH_ELEMENT>
+              <option name="myItemId" value="scannr" />
+              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
+            </PATH_ELEMENT>
+          </PATH>
         </subPane>
       </pane>
       <pane id="Scope" />
@@ -120,20 +224,26 @@
   <component name="PropertiesComponent">
     <property name="options.splitter.main.proportions" value="0.3" />
     <property name="WebServerToolWindowFactoryState" value="false" />
-    <property name="options.lastSelected" value="project.propVCSSupport.Mappings" />
+    <property name="options.lastSelected" value="tasks" />
     <property name="last_opened_file_path" value="$PROJECT_DIR$/../busui/myway/myway_timeliness.php" />
+    <property name="FullScreen" value="false" />
     <property name="options.splitter.details.proportions" value="0.2" />
     <property name="options.searchVisible" value="true" />
+  </component>
+  <component name="PyConsoleOptionsProvider">
+    <option name="myPythonConsoleState">
+      <PyConsoleSettings />
+    </option>
+    <option name="myDjangoConsoleState">
+      <PyConsoleSettings />
+    </option>
   </component>
   <component name="RunManager">
     <configuration default="true" type="PHPUnitRunConfigurationType" factoryName="PHPUnit">
       <TestRunner />
       <method />
     </configuration>
-    <configuration default="true" type="PhpLocalRunConfigurationType" factoryName="PHP Console">
-      <method />
-    </configuration>
-    <configuration default="true" type="JavascriptDebugSession" factoryName="Local">
+    <configuration default="true" type="JavascriptDebugSession" factoryName="Local" singleton="true">
       <JSDebuggerConfigurationSettings>
         <option name="engineId" value="embedded" />
         <option name="fileUrl" />
@@ -170,24 +280,26 @@
     <servers />
   </component>
   <component name="ToolWindowManager">
-    <frame x="619" y="0" width="825" height="600" extended-state="0" />
-    <editor active="false" />
+    <frame x="0" y="22" width="1680" height="937" extended-state="6" />
+    <editor active="true" />
     <layout>
       <window_info id="Changes" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
+      <window_info id="Palette" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
+      <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
+      <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
+      <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32925338" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
+      <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
+      <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
       <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
-      <window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
       <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="1" side_tool="true" content_ui="tabs" />
-      <window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.44036698" sideWeight="0.6706349" order="0" side_tool="false" content_ui="combo" />
-      <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
-      <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
-      <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32936507" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
+      <window_info id="Maven Projects" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
+      <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
+      <window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.19645043" sideWeight="0.6707466" order="0" side_tool="false" content_ui="combo" />
       <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
-      <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
       <window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
       <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
-      <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
+      <window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
       <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
-      <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
       <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
       <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
     </layout>
@@ -225,6 +337,9 @@
     <option name="INCLUDE_TEXT_INTO_SHELF" value="false" />
     <option name="SHOW_FILE_HISTORY_DETAILS" value="true" />
     <option name="SHOW_VCS_ERROR_NOTIFICATIONS" value="true" />
+    <option name="SHOW_DIRTY_RECURSIVELY" value="false" />
+    <option name="LIMIT_HISTORY" value="true" />
+    <option name="MAXIMUM_HISTORY_ROWS" value="1000" />
     <option name="FORCE_NON_EMPTY_COMMENT" value="false" />
     <option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="false" />
     <option name="LAST_COMMIT_MESSAGE" />
@@ -244,85 +359,98 @@
   <component name="XDebuggerManager">
     <breakpoint-manager />
   </component>
+  <component name="antWorkspaceConfiguration">
+    <option name="IS_AUTOSCROLL_TO_SOURCE" value="false" />
+    <option name="FILTER_TARGETS" value="false" />
+  </component>
   <component name="editorHistoryManager">
-    <entry file="file://$PROJECT_DIR$/viewcalls.php">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="2" column="13" selection-start="46" selection-end="46" vertical-scroll-proportion="0.0">
-          <folding>
-            <element signature="e#255#287#0" expanded="true" />
-          </folding>
-        </state>
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/common.inc.php">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="34" column="0" selection-start="1179" selection-end="1179" vertical-scroll-proportion="0.0">
+    <entry file="file://$PROJECT_DIR$/calllog.php">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="9" column="0" selection-start="189" selection-end="189" vertical-scroll-proportion="0.0">
           <folding />
         </state>
       </provider>
     </entry>
-    <entry file="file://$PROJECT_DIR$/calls.json.php">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="2" column="9" selection-start="42" selection-end="42" vertical-scroll-proportion="0.0">
+    <entry file="file://$PROJECT_DIR$/scannr.py">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="12" column="21" selection-start="328" selection-end="328" vertical-scroll-proportion="0.0">
           <folding />
         </state>
       </provider>
     </entry>
-    <entry file="file://$PROJECT_DIR$/trunklog.php">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="0" column="0" selection-start="0" selection-end="0" vertical-scroll-proportion="0.0" />
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/../disclosr/include/template.inc.php">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="72" column="93" selection-start="2545" selection-end="2635" vertical-scroll-proportion="0.43404254" />
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/../disclosr/include/common.inc.php">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="0" column="0" selection-start="0" selection-end="0" vertical-scroll-proportion="0.0" />
-      </provider>
-    </entry>
-    <entry file="file://C:/tmp/h5bp-html5-boilerplate-2279296/index.html">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="38" column="11" selection-start="1245" selection-end="1982" vertical-scroll-proportion="0.93352604" />
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/../busui/myway/myway_timeliness.php">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="27" column="5" selection-start="1003" selection-end="1018" vertical-scroll-proportion="26.346153" />
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/scannr.py">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="66" column="23" selection-start="2084" selection-end="2084" vertical-scroll-proportion="0.0" />
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/snd.py">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="0" column="0" selection-start="0" selection-end="0" vertical-scroll-proportion="0.0" />
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/common.inc.php">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="60" column="117" selection-start="2262" selection-end="2262" vertical-scroll-proportion="-39.23077">
+    <entry file="file://$PROJECT_DIR$/calllog.php">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="0" column="0" selection-start="0" selection-end="0" vertical-scroll-proportion="0.0">
           <folding />
         </state>
       </provider>
     </entry>
+    <entry file="file://$PROJECT_DIR$/viewcalls.php">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="2" column="13" selection-start="46" selection-end="46" vertical-scroll-proportion="0.0" />
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/common.inc.php">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="34" column="0" selection-start="1179" selection-end="1179" vertical-scroll-proportion="0.0" />
+      </provider>
+    </entry>
     <entry file="file://$PROJECT_DIR$/calls.json.php">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="72" column="41" selection-start="2843" selection-end="2843" vertical-scroll-proportion="-43.153847">
+        <state line="2" column="9" selection-start="42" selection-end="42" vertical-scroll-proportion="0.0" />
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/trunklog.php">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="0" column="0" selection-start="0" selection-end="0" vertical-scroll-proportion="0.0" />
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/../disclosr/include/template.inc.php">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="72" column="93" selection-start="2545" selection-end="2635" vertical-scroll-proportion="0.43404254" />
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/../disclosr/include/common.inc.php">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="0" column="0" selection-start="0" selection-end="0" vertical-scroll-proportion="0.0" />
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/../busui/myway/myway_timeliness.php">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="27" column="5" selection-start="1003" selection-end="1018" vertical-scroll-proportion="26.346153" />
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/snd.py">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="0" column="0" selection-start="0" selection-end="0" vertical-scroll-proportion="0.0" />
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/common.inc.php">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="60" column="117" selection-start="2262" selection-end="2262" vertical-scroll-proportion="-39.23077" />
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/calls.json.php">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="72" column="41" selection-start="2843" selection-end="2843" vertical-scroll-proportion="-43.153847" />
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/viewcalls.php">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="41" column="69" selection-start="1388" selection-end="1388" vertical-scroll-proportion="1.2659575" />
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/calllog.php">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="9" column="0" selection-start="189" selection-end="189" vertical-scroll-proportion="0.0">
           <folding />
         </state>
       </provider>
     </entry>
-    <entry file="file://$PROJECT_DIR$/viewcalls.php">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="41" column="69" selection-start="1388" selection-end="1388" vertical-scroll-proportion="1.2659575">
-          <folding>
-            <element signature="e#255#287#0" expanded="true" />
-          </folding>
+    <entry file="file://$PROJECT_DIR$/scannr.py">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="80" column="64" selection-start="2271" selection-end="2271" vertical-scroll-proportion="-0.31178707">
+          <folding />
         </state>
       </provider>
     </entry>

file:a/404.html -> file:b/404.html
--- a/404.html
+++ b/404.html
@@ -1,158 +1,160 @@
 <!DOCTYPE html>
 <html lang="en">
-    <head>
-        <meta charset="utf-8">
-        <title>Page Not Found :(</title>
-        <style>
-            ::-moz-selection {
-                background: #b3d4fc;
-                text-shadow: none;
-            }
+<head>
+    <meta charset="utf-8">
+    <title>Page Not Found :(</title>
+    <style>
+        ::-moz-selection {
+            background: #b3d4fc;
+            text-shadow: none;
+        }
 
-            ::selection {
-                background: #b3d4fc;
-                text-shadow: none;
-            }
+        ::selection {
+            background: #b3d4fc;
+            text-shadow: none;
+        }
 
-            html {
-                padding: 30px 10px;
-                font-size: 20px;
-                line-height: 1.4;
-                color: #737373;
-                background: #f0f0f0;
-                -webkit-text-size-adjust: 100%;
-                -ms-text-size-adjust: 100%;
-            }
+        html {
+            padding: 30px 10px;
+            font-size: 20px;
+            line-height: 1.4;
+            color: #737373;
+            background: #f0f0f0;
+            -webkit-text-size-adjust: 100%;
+            -ms-text-size-adjust: 100%;
+        }
 
-            html,
-            input {
-                font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
-            }
+        html,
+        input {
+            font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+        }
 
-            body {
-                max-width: 500px;
-                _width: 500px;
-                padding: 30px 20px 50px;
-                border: 1px solid #b3b3b3;
-                border-radius: 4px;
-                margin: 0 auto;
-                box-shadow: 0 1px 10px #a7a7a7, inset 0 1px 0 #fff;
-                background: #fcfcfc;
-            }
+        body {
+            max-width: 500px;
+            _width: 500px;
+            padding: 30px 20px 50px;
+            border: 1px solid #b3b3b3;
+            border-radius: 4px;
+            margin: 0 auto;
+            box-shadow: 0 1px 10px #a7a7a7, inset 0 1px 0 #fff;
+            background: #fcfcfc;
+        }
 
-            h1 {
-                margin: 0 10px;
-                font-size: 50px;
-                text-align: center;
-            }
+        h1 {
+            margin: 0 10px;
+            font-size: 50px;
+            text-align: center;
+        }
 
-            h1 span {
-                color: #bbb;
-            }
+        h1 span {
+            color: #bbb;
+        }
 
-            h3 {
-                margin: 1.5em 0 0.5em;
-            }
+        h3 {
+            margin: 1.5em 0 0.5em;
+        }
 
-            p {
-                margin: 1em 0;
-            }
+        p {
+            margin: 1em 0;
+        }
 
-            ul {
-                padding: 0 0 0 40px;
-                margin: 1em 0;
-            }
+        ul {
+            padding: 0 0 0 40px;
+            margin: 1em 0;
+        }
 
-            .container {
-                max-width: 380px;
-                _width: 380px;
-                margin: 0 auto;
-            }
+        .container {
+            max-width: 380px;
+            _width: 380px;
+            margin: 0 auto;
+        }
 
             /* google search */
 
-            #goog-fixurl ul {
-                list-style: none;
-                padding: 0;
-                margin: 0;
-            }
+        #goog-fixurl ul {
+            list-style: none;
+            padding: 0;
+            margin: 0;
+        }
 
-            #goog-fixurl form {
-                margin: 0;
-            }
+        #goog-fixurl form {
+            margin: 0;
+        }
 
-            #goog-wm-qt,
-            #goog-wm-sb {
-                border: 1px solid #bbb;
-                font-size: 16px;
-                line-height: normal;
-                vertical-align: top;
-                color: #444;
-                border-radius: 2px;
-            }
+        #goog-wm-qt,
+        #goog-wm-sb {
+            border: 1px solid #bbb;
+            font-size: 16px;
+            line-height: normal;
+            vertical-align: top;
+            color: #444;
+            border-radius: 2px;
+        }
 
-            #goog-wm-qt {
-                width: 220px;
-                height: 20px;
-                padding: 5px;
-                margin: 5px 10px 0 0;
-                box-shadow: inset 0 1px 1px #ccc;
-            }
+        #goog-wm-qt {
+            width: 220px;
+            height: 20px;
+            padding: 5px;
+            margin: 5px 10px 0 0;
+            box-shadow: inset 0 1px 1px #ccc;
+        }
 
-            #goog-wm-sb {
-                display: inline-block;
-                height: 32px;
-                padding: 0 10px;
-                margin: 5px 0 0;
-                white-space: nowrap;
-                cursor: pointer;
-                background-color: #f5f5f5;
-                background-image: -webkit-linear-gradient(rgba(255,255,255,0), #f1f1f1);
-                background-image: -moz-linear-gradient(rgba(255,255,255,0), #f1f1f1);
-                background-image: -ms-linear-gradient(rgba(255,255,255,0), #f1f1f1);
-                background-image: -o-linear-gradient(rgba(255,255,255,0), #f1f1f1);
-                -webkit-appearance: none;
-                -moz-appearance: none;
-                appearance: none;
-                *overflow: visible;
-                *display: inline;
-                *zoom: 1;
-            }
+        #goog-wm-sb {
+            display: inline-block;
+            height: 32px;
+            padding: 0 10px;
+            margin: 5px 0 0;
+            white-space: nowrap;
+            cursor: pointer;
+            background-color: #f5f5f5;
+            background-image: -webkit-linear-gradient(rgba(255, 255, 255, 0), #f1f1f1);
+            background-image: -moz-linear-gradient(rgba(255, 255, 255, 0), #f1f1f1);
+            background-image: -ms-linear-gradient(rgba(255, 255, 255, 0), #f1f1f1);
+            background-image: -o-linear-gradient(rgba(255, 255, 255, 0), #f1f1f1);
+            -webkit-appearance: none;
+            -moz-appearance: none;
+            appearance: none;
+            *overflow: visible;
+            *display: inline;
+            *zoom: 1;
+        }
 
-            #goog-wm-sb:hover,
-            #goog-wm-sb:focus {
-                border-color: #aaa;
-                box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
-                background-color: #f8f8f8;
-            }
+        #goog-wm-sb:hover,
+        #goog-wm-sb:focus {
+            border-color: #aaa;
+            box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+            background-color: #f8f8f8;
+        }
 
-            #goog-wm-qt:hover,
-            #goog-wm-qt:focus {
-                border-color: #105cb6;
-                outline: 0;
-                color: #222;
-            }
+        #goog-wm-qt:hover,
+        #goog-wm-qt:focus {
+            border-color: #105cb6;
+            outline: 0;
+            color: #222;
+        }
 
-            input::-moz-focus-inner {
-                padding: 0;
-                border: 0;
-            }
-        </style>
-    </head>
-    <body>
-        <div class="container">
-            <h1>Not found <span>:(</span></h1>
-            <p>Sorry, but the page you were trying to view does not exist.</p>
-            <p>It looks like this was the result of either:</p>
-            <ul>
-                <li>a mistyped address</li>
-                <li>an out-of-date link</li>
-            </ul>
-            <script>
-                var GOOG_FIXURL_LANG = (navigator.language || '').slice(0,2),GOOG_FIXURL_SITE = location.host;
-            </script>
-            <script src="http://linkhelp.clients.google.com/tbproxy/lh/wm/fixurl.js"></script>
-        </div>
-    </body>
+        input::-moz-focus-inner {
+            padding: 0;
+            border: 0;
+        }
+    </style>
+</head>
+<body>
+<div class="container">
+    <h1>Not found <span>:(</span></h1>
+
+    <p>Sorry, but the page you were trying to view does not exist.</p>
+
+    <p>It looks like this was the result of either:</p>
+    <ul>
+        <li>a mistyped address</li>
+        <li>an out-of-date link</li>
+    </ul>
+    <script>
+        var GOOG_FIXURL_LANG = (navigator.language || '').slice(0, 2), GOOG_FIXURL_SITE = location.host;
+    </script>
+    <script src="http://linkhelp.clients.google.com/tbproxy/lh/wm/fixurl.js"></script>
+</div>
+</body>
 </html>
 

--- a/calllog.php
+++ b/calllog.php
@@ -1,22 +1,21 @@
 <?php
 include ('common.inc.php');
-    $sth = $conn->prepare( 'select * from recordings
-            order by call_timestamp desc limit 10');
+$sth = $conn->prepare('select * from recordings
+            order by call_timestamp desc limit 1000');
 
-    $sth->execute(Array());
+$sth->execute(Array());
 
 $row = 0;
 echo "<table>";
 foreach ($sth->fetchAll() as $data) {
-        
-            
-        echo "<tr>";
-        for ($c=0; $c < count($data); $c++) {
-            echo '<td>'.$data[$c] . "</td>\n";
-        }
-        echo "</tr>";
-        }
-        $row++;
+
+
+    echo "<tr>";
+    for ($c = 0; $c < count($data); $c++) {
+        echo '<td>' . $data[$c] . "</td>\n";
+    }
+    echo "</tr>";
+}
+$row++;
 echo "</table>";
-?>
 

--- a/calls.json.php
+++ b/calls.json.php
@@ -1,48 +1,53 @@
 <?php
 include('common.inc.php');
-function getTGIDValuesByHour($TGID, $timeFrom, $timeTo) {
+function getTGIDValuesByHour($TGID, $timeFrom, $timeTo)
+{
     global $conn;
-    $sth = $conn->prepare( 'select tgid, min(call_timestamp) as time, count(*), min(length), max(length), avg(length), stddev(length) from recordings
+    $sth = $conn->prepare('select tgid, min(call_timestamp) as time, count(*), min(length), max(length), avg(length), stddev(length) from recordings
 where call_timestamp between to_timestamp(?) and to_timestamp(?)
             group by tgid, date_trunc(\'hour\', call_timestamp) order by time');
 
     $sth->execute(Array($timeFrom, $timeTo));
-        return  $sth->fetchAll();
+    return $sth->fetchAll();
 
 
 }
 
-function getTGIDValuesByDay($TGID, $dayFrom, $dayTo) {
+function getTGIDValuesByDay($TGID, $dayFrom, $dayTo)
+{
     global $conn;
     $sth = $conn->prepare('select min(time) as time, min(value), max(value), avg(value), stddev(value) from sensor_values where sensor_id = ?
             group by sensor_id, date_trunc(\'day\', time) order by time');
 
-    $sth->execute( Array($TGID));
-    return  $sth->fetchAll();
+    $sth->execute(Array($TGID));
+    return $sth->fetchAll();
 }
-function getTGIDDataYears($TGID, $timeFrom, $timeTo) {
+function getTGIDDataYears($TGID, $timeFrom, $timeTo)
+{
     global $conn;
     $sth = $conn->prepare("select distinct extract('year' from call_timestamp) as year from recordings where tgid = ? order by year");
 
     $sth->execute(Array($TGID));
-    return  $sth->fetchAll();
+    return $sth->fetchAll();
 }
 
-function getTGIDDataMonths($TGID, $timeFrom, $timeTo) {
+function getTGIDDataMonths($TGID, $timeFrom, $timeTo)
+{
     global $conn;
     $sth = $conn->prepare("select distinct extract('month' from call_timestamp) as month, extract('year' from call_timestamp) as year from recordings where tgid = ?  order by year, month");
 
     $sth->execute(Array($TGID));
-    return  $sth->fetchAll();
+    return $sth->fetchAll();
 }
 
-function getTGIDDataDays($TGID, $timeFrom, $timeTo) {
+function getTGIDDataDays($TGID, $timeFrom, $timeTo)
+{
     global $conn;
     $sth = $conn->prepare("select distinct extract('day' from call_timestamp) as day, extract('month' from call_timestamp) as month, extract('year' from call_timestamp) as year from recordings where tgid = ?  order by year,month,day");
 
 
     $sth->execute(Array($TGID));
-    return  $sth->fetchAll();
+    return $sth->fetchAll();
 }
 $action = (isset($_REQUEST['action']) ? $_REQUEST['action'] : '');
 $TGID = (isset($_REQUEST['tgid']) ? $_REQUEST['tgid'] : '');
@@ -58,23 +63,23 @@
     $days = getTGIDDataDays($TGID, $timefrom, $timeto);
 
     echo json_encode(Array("years" => $years, "months" => $months, "days" => $days
-                    ));
+    ));
 }
 
 
-if (strpos($action,"graph") !== false) {
+if (strpos($action, "graph") !== false) {
     $values = getTGIDValuesByHour($TGID, $timefrom, $timeto);
     $label = $TGID;
     $data = Array();
     $tzoffset = get_timezone_offset("UTC");
     foreach ($values as $value) {
         if ($action == "graphlength") {
-        $data[$value['tgid']][] = Array((strtotime($value['time']) + $tzoffset) * 1000, intval($value['avg']));
+            $data[$value['tgid']][] = Array((strtotime($value['time']) + $tzoffset) * 1000, intval($value['avg']));
         } else if ($action == "graphcount") {
             $data[$value['tgid']][] = Array((strtotime($value['time']) + $tzoffset) * 1000, intval($value['count']));
         }
     }
-   echo json_encode(Array("label" => $label, "data" => $data,
+    echo json_encode(Array("label" => $label, "data" => $data,
             "previous" => Array(
                 "from" => $timefrom - (24 * 60 * 60),
                 "to" => $timefrom)

--- a/common.inc.php
+++ b/common.inc.php
@@ -3,11 +3,10 @@
 try {
     $conn = new PDO("pgsql:dbname=scannr;user=postgres;password=snmc;host=localhost");
     $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
-}
-catch(PDOException $e) {
+} catch (PDOException $e) {
     die('Unable to connect to database server.');
 }
-catch(Exception $e) {
+catch (Exception $e) {
     die('Unknown error in ' . __FILE__ . '.');
 }
 $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
@@ -15,11 +14,12 @@
 $DATA_DIR = "./data";
 
 /**    Returns the offset from the origin timezone to the remote timezone, in seconds.
- *    @param $remote_tz;
- *    @param $origin_tz; If null the servers current timezone is used as the origin.
- *    @return int;
+ * @param $remote_tz;
+ * @param $origin_tz; If null the servers current timezone is used as the origin.
+ * @return int;
  */
-function get_timezone_offset($remote_tz, $origin_tz = null) {
+function get_timezone_offset($remote_tz, $origin_tz = null)
+{
     if ($origin_tz === null) {
         if (!is_string($origin_tz = date_default_timezone_get())) {
             return false; // A UTC timestamp was returned -- bail out!
@@ -34,60 +34,69 @@
 }
 
 
+function include_header($title)
+{
+    global $basePath;
+    ?>
+    <!DOCTYPE html>
+    <!--[if lt IE 7]>
+    <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
+    <!--[if IE 7]>
+    <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
+    <!--[if IE 8]>
+    <html class="no-js lt-ie9"> <![endif]-->
+    <!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
+    <head>
+        <meta charset="utf-8">
+        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+        <title></title>
+        <meta name="description" content="">
+        <meta name="viewport" content="width=device-width">
+
+        <!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
+
+        <link rel="stylesheet" href="css/normalize.css">
+        <link rel="stylesheet" href="css/main.css">
+        <script src="js/vendor/modernizr-2.6.1.min.js"></script>
+        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
+        <!--<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.8.0.min.js"><\/script>')</script>-->
+        <script type="text/javascript" src="<?php echo $basePath ?>js/flotr2/flotr2.js"></script>
+        <script src="js/plugins.js"></script>
+        <script src="js/main.js"></script>
+    </head>
+    <body>
+    <!--[if lt IE 7]>
+    <p class="chromeframe">You are using an outdated browser. <a href="http://browsehappy.com/">Upgrade your browser
+        today</a> or <a href="http://www.google.com/chromeframe/?redirect=true">install Google Chrome Frame</a> to
+        better experience this site.</p>
+    <![endif]-->
+
+    <!-- Add your site or application content here -->
+<?php
+}
+
+function include_footer()
+{
+    global $basePath;
+    ?>
 
 
+    <!-- Google Analytics: change UA-XXXXX-X to be your site's ID. -->
+    <script>
+        var _gaq = [
+            ['_setAccount', 'UA-XXXXX-X'],
+            ['_trackPageview']
+        ];
+        (function (d, t) {
+            var g = d.createElement(t), s = d.getElementsByTagName(t)[0];
+            g.src = ('https:' == location.protocol ? '//ssl' : '//www') + '.google-analytics.com/ga.js';
+            s.parentNode.insertBefore(g, s)
+        }(document, 'script'));
+    </script>
+    </body>
+    </html>
 
-function include_header($title) {
-    global $basePath;
-    ?>
-<!DOCTYPE html>
-<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
-<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
-<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
-<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
-<head>
-    <meta charset="utf-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-    <title></title>
-    <meta name="description" content="">
-    <meta name="viewport" content="width=device-width">
-
-    <!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
-
-    <link rel="stylesheet" href="css/normalize.css">
-    <link rel="stylesheet" href="css/main.css">
-    <script src="js/vendor/modernizr-2.6.1.min.js"></script>
-    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
-    <!--<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.8.0.min.js"><\/script>')</script>-->
-    <script type="text/javascript" src="<?php echo $basePath ?>js/flotr2/flotr2.js"></script>
-    <script src="js/plugins.js"></script>
-    <script src="js/main.js"></script>
-</head>
-    <body>
-        <!--[if lt IE 7]>
-<p class="chromeframe">You are using an outdated browser. <a href="http://browsehappy.com/">Upgrade your browser today</a> or <a href="http://www.google.com/chromeframe/?redirect=true">install Google Chrome Frame</a> to better experience this site.</p>
-<![endif]-->
-
-<!-- Add your site or application content here -->
-            <?php
-            }
-
-            function include_footer() {
-                global $basePath;
-                ?>
-
-
-            <!-- Google Analytics: change UA-XXXXX-X to be your site's ID. -->
-            <script>
-                var _gaq=[['_setAccount','UA-XXXXX-X'],['_trackPageview']];
-                (function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
-                    g.src=('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js';
-                    s.parentNode.insertBefore(g,s)}(document,'script'));
-            </script>
-    </body>
-</html>
-
-    <?php
+<?php
 
 }
 

--- a/generateConvos.php
+++ b/generateConvos.php
@@ -1,33 +1,34 @@
 <?php
 include('common.inc.php');
-  $sth = $conn->prepare( 'select * from recordings limit 100;');
+$sth = $conn->prepare('select * from recordings limit 100;');
 
-    $sth->execute( );
+$sth->execute();
 $recordings = $sth->fetchAll();
 $convos = Array();
 $convo = Array();
 foreach ($recordings as $i => $recording) {
 
-	if (count($convo) > 0) {
-		echo "<br> ".strcasecmp($convos[count($convos)-1][0]['call_timestamp'],$recording['call_timestamp']);
-		if (abs(strcasecmp($convos[count($convos)-1][0]['call_timestamp'],$recording['call_timestamp'])) > 2) {
-			echo " ".$convos[count($convos)-1][0]['call_timestamp']." ".$recording['call_timestamp'];
-		}
-		if (strcasecmp($convos[count($convos)-1][0]['tgid'], $recording['tgid']) != 0 ) {
-		$convos[] = $convo;
-		$convo = Array();
-		}
-	} ;
-	//print_r($recording);
-	$convo[] = $recording;
-	//print_r($convo);
-	//echo "<br>\n";
+    if (count($convo) > 0) {
+        echo "<br> " . strcasecmp($convos[count($convos) - 1][0]['call_timestamp'], $recording['call_timestamp']);
+        if (abs(strcasecmp($convos[count($convos) - 1][0]['call_timestamp'], $recording['call_timestamp'])) > 2) {
+            echo " " . $convos[count($convos) - 1][0]['call_timestamp'] . " " . $recording['call_timestamp'];
+        }
+        if (strcasecmp($convos[count($convos) - 1][0]['tgid'], $recording['tgid']) != 0) {
+            $convos[] = $convo;
+            $convo = Array();
+        }
+    }
+    ;
+    //print_r($recording);
+    $convo[] = $recording;
+    //print_r($convo);
+    //echo "<br>\n";
 }
 foreach ($convos as $i => $convo) {
-	foreach($convo as $recording) {
-		echo $recording['filename']." , ";
-	}
-	echo "<br><hr>\n";
+    foreach ($convo as $recording) {
+        echo $recording['filename'] . " , ";
+    }
+    echo "<br><hr>\n";
 }
 ?>
 

--- a/getfile.php
+++ b/getfile.php
@@ -1,19 +1,19 @@
 <?php
 $reqfile = "path/to/file.3gp";
-$contenttype="audio/3gpp";
- 
-if($fn=fopen($reqfile, "rba")){
-  header("Content-Type: ".$contenttype); 
-  header("Content-Length: ".filesize($reqfile)); 
-  header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
-  header("Pragma: no-cache");
-  header("Expires: Mon, 26 Jul 1997 06:00:00 GMT");
-  header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0");
-passthru("ffmpeg -i 2012-09-29-1348911268.34-demo.wav -ar 8000 -ab 4.75k -");
-  fpassthru($fn);
-  fclose($fn);
-}else{
-  exit("error....");
+$contenttype = "audio/3gpp";
+
+if ($fn = fopen($reqfile, "rba")) {
+    header("Content-Type: " . $contenttype);
+    header("Content-Length: " . filesize($reqfile));
+    header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
+    header("Pragma: no-cache");
+    header("Expires: Mon, 26 Jul 1997 06:00:00 GMT");
+    header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0");
+    passthru("ffmpeg -i 2012-09-29-1348911268.34-demo.wav -ar 8000 -ab 4.75k -");
+    fpassthru($fn);
+    fclose($fn);
+} else {
+    exit("error....");
 }
 exit();
 ?>

--- a/js/flotr2/lib/jasmine/jasmine-html.js
+++ b/js/flotr2/lib/jasmine/jasmine-html.js
@@ -1,617 +1,621 @@
 jasmine.HtmlReporterHelpers = {};
 
-jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
-  var el = document.createElement(type);
-
-  for (var i = 2; i < arguments.length; i++) {
-    var child = arguments[i];
-
-    if (typeof child === 'string') {
-      el.appendChild(document.createTextNode(child));
-    } else {
-      if (child) {
-        el.appendChild(child);
-      }
-    }
-  }
-
-  for (var attr in attrs) {
-    if (attr == "className") {
-      el[attr] = attrs[attr];
-    } else {
-      el.setAttribute(attr, attrs[attr]);
-    }
-  }
-
-  return el;
-};
-
-jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
-  var results = child.results();
-  var status = results.passed() ? 'passed' : 'failed';
-  if (results.skipped) {
-    status = 'skipped';
-  }
-
-  return status;
-};
-
-jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
-  var parentDiv = this.dom.summary;
-  var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
-  var parent = child[parentSuite];
-
-  if (parent) {
-    if (typeof this.views.suites[parent.id] == 'undefined') {
-      this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
-    }
-    parentDiv = this.views.suites[parent.id].element;
-  }
-
-  parentDiv.appendChild(childElement);
-};
-
-
-jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
-  for(var fn in jasmine.HtmlReporterHelpers) {
-    ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
-  }
-};
-
-jasmine.HtmlReporter = function(_doc) {
-  var self = this;
-  var doc = _doc || window.document;
-
-  var reporterView;
-
-  var dom = {};
-
-  // Jasmine Reporter Public Interface
-  self.logRunningSpecs = false;
-
-  self.reportRunnerStarting = function(runner) {
-    var specs = runner.specs() || [];
-
-    if (specs.length == 0) {
-      return;
-    }
-
-    createReporterDom(runner.env.versionString());
-    doc.body.appendChild(dom.reporter);
-
-    reporterView = new jasmine.HtmlReporter.ReporterView(dom);
-    reporterView.addSpecs(specs, self.specFilter);
-  };
-
-  self.reportRunnerResults = function(runner) {
-    reporterView && reporterView.complete();
-  };
-
-  self.reportSuiteResults = function(suite) {
-    reporterView.suiteComplete(suite);
-  };
-
-  self.reportSpecStarting = function(spec) {
-    if (self.logRunningSpecs) {
-      self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
-    }
-  };
-
-  self.reportSpecResults = function(spec) {
-    reporterView.specComplete(spec);
-  };
-
-  self.log = function() {
+jasmine.HtmlReporterHelpers.createDom = function (type, attrs, childrenVarArgs) {
+    var el = document.createElement(type);
+
+    for (var i = 2; i < arguments.length; i++) {
+        var child = arguments[i];
+
+        if (typeof child === 'string') {
+            el.appendChild(document.createTextNode(child));
+        } else {
+            if (child) {
+                el.appendChild(child);
+            }
+        }
+    }
+
+    for (var attr in attrs) {
+        if (attr == "className") {
+            el[attr] = attrs[attr];
+        } else {
+            el.setAttribute(attr, attrs[attr]);
+        }
+    }
+
+    return el;
+};
+
+jasmine.HtmlReporterHelpers.getSpecStatus = function (child) {
+    var results = child.results();
+    var status = results.passed() ? 'passed' : 'failed';
+    if (results.skipped) {
+        status = 'skipped';
+    }
+
+    return status;
+};
+
+jasmine.HtmlReporterHelpers.appendToSummary = function (child, childElement) {
+    var parentDiv = this.dom.summary;
+    var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
+    var parent = child[parentSuite];
+
+    if (parent) {
+        if (typeof this.views.suites[parent.id] == 'undefined') {
+            this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
+        }
+        parentDiv = this.views.suites[parent.id].element;
+    }
+
+    parentDiv.appendChild(childElement);
+};
+
+
+jasmine.HtmlReporterHelpers.addHelpers = function (ctor) {
+    for (var fn in jasmine.HtmlReporterHelpers) {
+        ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
+    }
+};
+
+jasmine.HtmlReporter = function (_doc) {
+    var self = this;
+    var doc = _doc || window.document;
+
+    var reporterView;
+
+    var dom = {};
+
+    // Jasmine Reporter Public Interface
+    self.logRunningSpecs = false;
+
+    self.reportRunnerStarting = function (runner) {
+        var specs = runner.specs() || [];
+
+        if (specs.length == 0) {
+            return;
+        }
+
+        createReporterDom(runner.env.versionString());
+        doc.body.appendChild(dom.reporter);
+
+        reporterView = new jasmine.HtmlReporter.ReporterView(dom);
+        reporterView.addSpecs(specs, self.specFilter);
+    };
+
+    self.reportRunnerResults = function (runner) {
+        reporterView && reporterView.complete();
+    };
+
+    self.reportSuiteResults = function (suite) {
+        reporterView.suiteComplete(suite);
+    };
+
+    self.reportSpecStarting = function (spec) {
+        if (self.logRunningSpecs) {
+            self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
+        }
+    };
+
+    self.reportSpecResults = function (spec) {
+        reporterView.specComplete(spec);
+    };
+
+    self.log = function () {
+        var console = jasmine.getGlobal().console;
+        if (console && console.log) {
+            if (console.log.apply) {
+                console.log.apply(console, arguments);
+            } else {
+                console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
+            }
+        }
+    };
+
+    self.specFilter = function (spec) {
+        if (!focusedSpecName()) {
+            return true;
+        }
+
+        return spec.getFullName().indexOf(focusedSpecName()) === 0;
+    };
+
+    return self;
+
+    function focusedSpecName() {
+        var specName;
+
+        (function memoizeFocusedSpec() {
+            if (specName) {
+                return;
+            }
+
+            var paramMap = [];
+            var params = doc.location.search.substring(1).split('&');
+
+            for (var i = 0; i < params.length; i++) {
+                var p = params[i].split('=');
+                paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+            }
+
+            specName = paramMap.spec;
+        })();
+
+        return specName;
+    }
+
+    function createReporterDom(version) {
+        dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
+            dom.banner = self.createDom('div', { className: 'banner' },
+                self.createDom('span', { className: 'title' }, "Jasmine "),
+                self.createDom('span', { className: 'version' }, version)),
+
+            dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
+            dom.alert = self.createDom('div', {className: 'alert'}),
+            dom.results = self.createDom('div', {className: 'results'},
+                dom.summary = self.createDom('div', { className: 'summary' }),
+                dom.details = self.createDom('div', { id: 'details' }))
+        );
+    }
+};
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);
+jasmine.HtmlReporter.ReporterView = function (dom) {
+    this.startedAt = new Date();
+    this.runningSpecCount = 0;
+    this.completeSpecCount = 0;
+    this.passedCount = 0;
+    this.failedCount = 0;
+    this.skippedCount = 0;
+
+    this.createResultsMenu = function () {
+        this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
+            this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
+            ' | ',
+            this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
+
+        this.summaryMenuItem.onclick = function () {
+            dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
+        };
+
+        this.detailsMenuItem.onclick = function () {
+            showDetails();
+        };
+    };
+
+    this.addSpecs = function (specs, specFilter) {
+        this.totalSpecCount = specs.length;
+
+        this.views = {
+            specs: {},
+            suites: {}
+        };
+
+        for (var i = 0; i < specs.length; i++) {
+            var spec = specs[i];
+            this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
+            if (specFilter(spec)) {
+                this.runningSpecCount++;
+            }
+        }
+    };
+
+    this.specComplete = function (spec) {
+        this.completeSpecCount++;
+
+        if (isUndefined(this.views.specs[spec.id])) {
+            this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
+        }
+
+        var specView = this.views.specs[spec.id];
+
+        switch (specView.status()) {
+            case 'passed':
+                this.passedCount++;
+                break;
+
+            case 'failed':
+                this.failedCount++;
+                break;
+
+            case 'skipped':
+                this.skippedCount++;
+                break;
+        }
+
+        specView.refresh();
+        this.refresh();
+    };
+
+    this.suiteComplete = function (suite) {
+        var suiteView = this.views.suites[suite.id];
+        if (isUndefined(suiteView)) {
+            return;
+        }
+        suiteView.refresh();
+    };
+
+    this.refresh = function () {
+
+        if (isUndefined(this.resultsMenu)) {
+            this.createResultsMenu();
+        }
+
+        // currently running UI
+        if (isUndefined(this.runningAlert)) {
+            this.runningAlert = this.createDom('a', {href: "?", className: "runningAlert bar"});
+            dom.alert.appendChild(this.runningAlert);
+        }
+        this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
+
+        // skipped specs UI
+        if (isUndefined(this.skippedAlert)) {
+            this.skippedAlert = this.createDom('a', {href: "?", className: "skippedAlert bar"});
+        }
+
+        this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
+
+        if (this.skippedCount === 1 && isDefined(dom.alert)) {
+            dom.alert.appendChild(this.skippedAlert);
+        }
+
+        // passing specs UI
+        if (isUndefined(this.passedAlert)) {
+            this.passedAlert = this.createDom('span', {href: "?", className: "passingAlert bar"});
+        }
+        this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
+
+        // failing specs UI
+        if (isUndefined(this.failedAlert)) {
+            this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
+        }
+        this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
+
+        if (this.failedCount === 1 && isDefined(dom.alert)) {
+            dom.alert.appendChild(this.failedAlert);
+            dom.alert.appendChild(this.resultsMenu);
+        }
+
+        // summary info
+        this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
+        this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
+    };
+
+    this.complete = function () {
+        dom.alert.removeChild(this.runningAlert);
+
+        this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
+
+        if (this.failedCount === 0) {
+            dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
+        } else {
+            showDetails();
+        }
+
+        dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
+    };
+
+    return this;
+
+    function showDetails() {
+        if (dom.reporter.className.search(/showDetails/) === -1) {
+            dom.reporter.className += " showDetails";
+        }
+    }
+
+    function isUndefined(obj) {
+        return typeof obj === 'undefined';
+    }
+
+    function isDefined(obj) {
+        return !isUndefined(obj);
+    }
+
+    function specPluralizedFor(count) {
+        var str = count + " spec";
+        if (count > 1) {
+            str += "s"
+        }
+        return str;
+    }
+
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
+
+
+jasmine.HtmlReporter.SpecView = function (spec, dom, views) {
+    this.spec = spec;
+    this.dom = dom;
+    this.views = views;
+
+    this.symbol = this.createDom('li', { className: 'pending' });
+    this.dom.symbolSummary.appendChild(this.symbol);
+
+    this.summary = this.createDom('div', { className: 'specSummary' },
+        this.createDom('a', {
+            className: 'description',
+            href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
+            title: this.spec.getFullName()
+        }, this.spec.description)
+    );
+
+    this.detail = this.createDom('div', { className: 'specDetail' },
+        this.createDom('a', {
+            className: 'description',
+            href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
+            title: this.spec.getFullName()
+        }, this.spec.getFullName())
+    );
+};
+
+jasmine.HtmlReporter.SpecView.prototype.status = function () {
+    return this.getSpecStatus(this.spec);
+};
+
+jasmine.HtmlReporter.SpecView.prototype.refresh = function () {
+    this.symbol.className = this.status();
+
+    switch (this.status()) {
+        case 'skipped':
+            break;
+
+        case 'passed':
+            this.appendSummaryToSuiteDiv();
+            break;
+
+        case 'failed':
+            this.appendSummaryToSuiteDiv();
+            this.appendFailureDetail();
+            break;
+    }
+};
+
+jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function () {
+    this.summary.className += ' ' + this.status();
+    this.appendToSummary(this.spec, this.summary);
+};
+
+jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function () {
+    this.detail.className += ' ' + this.status();
+
+    var resultItems = this.spec.results().getItems();
+    var messagesDiv = this.createDom('div', { className: 'messages' });
+
+    for (var i = 0; i < resultItems.length; i++) {
+        var result = resultItems[i];
+
+        if (result.type == 'log') {
+            messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
+        } else if (result.type == 'expect' && result.passed && !result.passed()) {
+            messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
+
+            if (result.trace.stack) {
+                messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
+            }
+        }
+    }
+
+    if (messagesDiv.childNodes.length > 0) {
+        this.detail.appendChild(messagesDiv);
+        this.dom.details.appendChild(this.detail);
+    }
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);
+jasmine.HtmlReporter.SuiteView = function (suite, dom, views) {
+    this.suite = suite;
+    this.dom = dom;
+    this.views = views;
+
+    this.element = this.createDom('div', { className: 'suite' },
+        this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(this.suite.getFullName()) }, this.suite.description)
+    );
+
+    this.appendToSummary(this.suite, this.element);
+};
+
+jasmine.HtmlReporter.SuiteView.prototype.status = function () {
+    return this.getSpecStatus(this.suite);
+};
+
+jasmine.HtmlReporter.SuiteView.prototype.refresh = function () {
+    this.element.className += " " + this.status();
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
+
+/* @deprecated Use jasmine.HtmlReporter instead
+ */
+jasmine.TrivialReporter = function (doc) {
+    this.document = doc || document;
+    this.suiteDivs = {};
+    this.logRunningSpecs = false;
+};
+
+jasmine.TrivialReporter.prototype.createDom = function (type, attrs, childrenVarArgs) {
+    var el = document.createElement(type);
+
+    for (var i = 2; i < arguments.length; i++) {
+        var child = arguments[i];
+
+        if (typeof child === 'string') {
+            el.appendChild(document.createTextNode(child));
+        } else {
+            if (child) {
+                el.appendChild(child);
+            }
+        }
+    }
+
+    for (var attr in attrs) {
+        if (attr == "className") {
+            el[attr] = attrs[attr];
+        } else {
+            el.setAttribute(attr, attrs[attr]);
+        }
+    }
+
+    return el;
+};
+
+jasmine.TrivialReporter.prototype.reportRunnerStarting = function (runner) {
+    var showPassed, showSkipped;
+
+    this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
+        this.createDom('div', { className: 'banner' },
+            this.createDom('div', { className: 'logo' },
+                this.createDom('span', { className: 'title' }, "Jasmine"),
+                this.createDom('span', { className: 'version' }, runner.env.versionString())),
+            this.createDom('div', { className: 'options' },
+                "Show ",
+                showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
+                this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
+                showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
+                this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
+            )
+        ),
+
+        this.runnerDiv = this.createDom('div', { className: 'runner running' },
+            this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
+            this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
+            this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
+    );
+
+    this.document.body.appendChild(this.outerDiv);
+
+    var suites = runner.suites();
+    for (var i = 0; i < suites.length; i++) {
+        var suite = suites[i];
+        var suiteDiv = this.createDom('div', { className: 'suite' },
+            this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
+            this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
+        this.suiteDivs[suite.id] = suiteDiv;
+        var parentDiv = this.outerDiv;
+        if (suite.parentSuite) {
+            parentDiv = this.suiteDivs[suite.parentSuite.id];
+        }
+        parentDiv.appendChild(suiteDiv);
+    }
+
+    this.startedAt = new Date();
+
+    var self = this;
+    showPassed.onclick = function (evt) {
+        if (showPassed.checked) {
+            self.outerDiv.className += ' show-passed';
+        } else {
+            self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
+        }
+    };
+
+    showSkipped.onclick = function (evt) {
+        if (showSkipped.checked) {
+            self.outerDiv.className += ' show-skipped';
+        } else {
+            self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
+        }
+    };
+};
+
+jasmine.TrivialReporter.prototype.reportRunnerResults = function (runner) {
+    var results = runner.results();
+    var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
+    this.runnerDiv.setAttribute("class", className);
+    //do it twice for IE
+    this.runnerDiv.setAttribute("className", className);
+    var specs = runner.specs();
+    var specCount = 0;
+    for (var i = 0; i < specs.length; i++) {
+        if (this.specFilter(specs[i])) {
+            specCount++;
+        }
+    }
+    var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
+    message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
+    this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
+
+    this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
+};
+
+jasmine.TrivialReporter.prototype.reportSuiteResults = function (suite) {
+    var results = suite.results();
+    var status = results.passed() ? 'passed' : 'failed';
+    if (results.totalCount === 0) { // todo: change this to check results.skipped
+        status = 'skipped';
+    }
+    this.suiteDivs[suite.id].className += " " + status;
+};
+
+jasmine.TrivialReporter.prototype.reportSpecStarting = function (spec) {
+    if (this.logRunningSpecs) {
+        this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
+    }
+};
+
+jasmine.TrivialReporter.prototype.reportSpecResults = function (spec) {
+    var results = spec.results();
+    var status = results.passed() ? 'passed' : 'failed';
+    if (results.skipped) {
+        status = 'skipped';
+    }
+    var specDiv = this.createDom('div', { className: 'spec ' + status },
+        this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
+        this.createDom('a', {
+            className: 'description',
+            href: '?spec=' + encodeURIComponent(spec.getFullName()),
+            title: spec.getFullName()
+        }, spec.description));
+
+
+    var resultItems = results.getItems();
+    var messagesDiv = this.createDom('div', { className: 'messages' });
+    for (var i = 0; i < resultItems.length; i++) {
+        var result = resultItems[i];
+
+        if (result.type == 'log') {
+            messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
+        } else if (result.type == 'expect' && result.passed && !result.passed()) {
+            messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
+
+            if (result.trace.stack) {
+                messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
+            }
+        }
+    }
+
+    if (messagesDiv.childNodes.length > 0) {
+        specDiv.appendChild(messagesDiv);
+    }
+
+    this.suiteDivs[spec.suite.id].appendChild(specDiv);
+};
+
+jasmine.TrivialReporter.prototype.log = function () {
     var console = jasmine.getGlobal().console;
     if (console && console.log) {
-      if (console.log.apply) {
-        console.log.apply(console, arguments);
-      } else {
-        console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
-      }
-    }
-  };
-
-  self.specFilter = function(spec) {
-    if (!focusedSpecName()) {
-      return true;
-    }
-
-    return spec.getFullName().indexOf(focusedSpecName()) === 0;
-  };
-
-  return self;
-
-  function focusedSpecName() {
-    var specName;
-
-    (function memoizeFocusedSpec() {
-      if (specName) {
-        return;
-      }
-
-      var paramMap = [];
-      var params = doc.location.search.substring(1).split('&');
-
-      for (var i = 0; i < params.length; i++) {
+        if (console.log.apply) {
+            console.log.apply(console, arguments);
+        } else {
+            console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
+        }
+    }
+};
+
+jasmine.TrivialReporter.prototype.getLocation = function () {
+    return this.document.location;
+};
+
+jasmine.TrivialReporter.prototype.specFilter = function (spec) {
+    var paramMap = {};
+    var params = this.getLocation().search.substring(1).split('&');
+    for (var i = 0; i < params.length; i++) {
         var p = params[i].split('=');
         paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
-      }
-
-      specName = paramMap.spec;
-    })();
-
-    return specName;
-  }
-
-  function createReporterDom(version) {
-    dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
-      dom.banner = self.createDom('div', { className: 'banner' },
-        self.createDom('span', { className: 'title' }, "Jasmine "),
-        self.createDom('span', { className: 'version' }, version)),
-
-      dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
-      dom.alert = self.createDom('div', {className: 'alert'}),
-      dom.results = self.createDom('div', {className: 'results'},
-        dom.summary = self.createDom('div', { className: 'summary' }),
-        dom.details = self.createDom('div', { id: 'details' }))
-    );
-  }
-};
-jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);jasmine.HtmlReporter.ReporterView = function(dom) {
-  this.startedAt = new Date();
-  this.runningSpecCount = 0;
-  this.completeSpecCount = 0;
-  this.passedCount = 0;
-  this.failedCount = 0;
-  this.skippedCount = 0;
-
-  this.createResultsMenu = function() {
-    this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
-      this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
-      ' | ',
-      this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
-
-    this.summaryMenuItem.onclick = function() {
-      dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
-    };
-
-    this.detailsMenuItem.onclick = function() {
-      showDetails();
-    };
-  };
-
-  this.addSpecs = function(specs, specFilter) {
-    this.totalSpecCount = specs.length;
-
-    this.views = {
-      specs: {},
-      suites: {}
-    };
-
-    for (var i = 0; i < specs.length; i++) {
-      var spec = specs[i];
-      this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
-      if (specFilter(spec)) {
-        this.runningSpecCount++;
-      }
-    }
-  };
-
-  this.specComplete = function(spec) {
-    this.completeSpecCount++;
-
-    if (isUndefined(this.views.specs[spec.id])) {
-      this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
-    }
-
-    var specView = this.views.specs[spec.id];
-
-    switch (specView.status()) {
-      case 'passed':
-        this.passedCount++;
-        break;
-
-      case 'failed':
-        this.failedCount++;
-        break;
-
-      case 'skipped':
-        this.skippedCount++;
-        break;
-    }
-
-    specView.refresh();
-    this.refresh();
-  };
-
-  this.suiteComplete = function(suite) {
-    var suiteView = this.views.suites[suite.id];
-    if (isUndefined(suiteView)) {
-      return;
-    }
-    suiteView.refresh();
-  };
-
-  this.refresh = function() {
-
-    if (isUndefined(this.resultsMenu)) {
-      this.createResultsMenu();
-    }
-
-    // currently running UI
-    if (isUndefined(this.runningAlert)) {
-      this.runningAlert = this.createDom('a', {href: "?", className: "runningAlert bar"});
-      dom.alert.appendChild(this.runningAlert);
-    }
-    this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
-
-    // skipped specs UI
-    if (isUndefined(this.skippedAlert)) {
-      this.skippedAlert = this.createDom('a', {href: "?", className: "skippedAlert bar"});
-    }
-
-    this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
-
-    if (this.skippedCount === 1 && isDefined(dom.alert)) {
-      dom.alert.appendChild(this.skippedAlert);
-    }
-
-    // passing specs UI
-    if (isUndefined(this.passedAlert)) {
-      this.passedAlert = this.createDom('span', {href: "?", className: "passingAlert bar"});
-    }
-    this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
-
-    // failing specs UI
-    if (isUndefined(this.failedAlert)) {
-      this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
-    }
-    this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
-
-    if (this.failedCount === 1 && isDefined(dom.alert)) {
-      dom.alert.appendChild(this.failedAlert);
-      dom.alert.appendChild(this.resultsMenu);
-    }
-
-    // summary info
-    this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
-    this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
-  };
-
-  this.complete = function() {
-    dom.alert.removeChild(this.runningAlert);
-
-    this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
-
-    if (this.failedCount === 0) {
-      dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
-    } else {
-      showDetails();
-    }
-
-    dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
-  };
-
-  return this;
-
-  function showDetails() {
-    if (dom.reporter.className.search(/showDetails/) === -1) {
-      dom.reporter.className += " showDetails";
-    }
-  }
-
-  function isUndefined(obj) {
-    return typeof obj === 'undefined';
-  }
-
-  function isDefined(obj) {
-    return !isUndefined(obj);
-  }
-
-  function specPluralizedFor(count) {
-    var str = count + " spec";
-    if (count > 1) {
-      str += "s"
-    }
-    return str;
-  }
-
-};
-
-jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
-
-
-jasmine.HtmlReporter.SpecView = function(spec, dom, views) {
-  this.spec = spec;
-  this.dom = dom;
-  this.views = views;
-
-  this.symbol = this.createDom('li', { className: 'pending' });
-  this.dom.symbolSummary.appendChild(this.symbol);
-
-  this.summary = this.createDom('div', { className: 'specSummary' },
-      this.createDom('a', {
-        className: 'description',
-        href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
-        title: this.spec.getFullName()
-      }, this.spec.description)
-  );
-
-  this.detail = this.createDom('div', { className: 'specDetail' },
-      this.createDom('a', {
-        className: 'description',
-        href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
-        title: this.spec.getFullName()
-      }, this.spec.getFullName())
-  );
-};
-
-jasmine.HtmlReporter.SpecView.prototype.status = function() {
-  return this.getSpecStatus(this.spec);
-};
-
-jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
-  this.symbol.className = this.status();
-
-  switch (this.status()) {
-    case 'skipped':
-      break;
-
-    case 'passed':
-      this.appendSummaryToSuiteDiv();
-      break;
-
-    case 'failed':
-      this.appendSummaryToSuiteDiv();
-      this.appendFailureDetail();
-      break;
-  }
-};
-
-jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
-  this.summary.className += ' ' + this.status();
-  this.appendToSummary(this.spec, this.summary);
-};
-
-jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
-  this.detail.className += ' ' + this.status();
-
-  var resultItems = this.spec.results().getItems();
-  var messagesDiv = this.createDom('div', { className: 'messages' });
-
-  for (var i = 0; i < resultItems.length; i++) {
-    var result = resultItems[i];
-
-    if (result.type == 'log') {
-      messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
-    } else if (result.type == 'expect' && result.passed && !result.passed()) {
-      messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
-
-      if (result.trace.stack) {
-        messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
-      }
-    }
-  }
-
-  if (messagesDiv.childNodes.length > 0) {
-    this.detail.appendChild(messagesDiv);
-    this.dom.details.appendChild(this.detail);
-  }
-};
-
-jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
-  this.suite = suite;
-  this.dom = dom;
-  this.views = views;
-
-  this.element = this.createDom('div', { className: 'suite' },
-      this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(this.suite.getFullName()) }, this.suite.description)
-  );
-
-  this.appendToSummary(this.suite, this.element);
-};
-
-jasmine.HtmlReporter.SuiteView.prototype.status = function() {
-  return this.getSpecStatus(this.suite);
-};
-
-jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
-  this.element.className += " " + this.status();
-};
-
-jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
-
-/* @deprecated Use jasmine.HtmlReporter instead
- */
-jasmine.TrivialReporter = function(doc) {
-  this.document = doc || document;
-  this.suiteDivs = {};
-  this.logRunningSpecs = false;
-};
-
-jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
-  var el = document.createElement(type);
-
-  for (var i = 2; i < arguments.length; i++) {
-    var child = arguments[i];
-
-    if (typeof child === 'string') {
-      el.appendChild(document.createTextNode(child));
-    } else {
-      if (child) { el.appendChild(child); }
-    }
-  }
-
-  for (var attr in attrs) {
-    if (attr == "className") {
-      el[attr] = attrs[attr];
-    } else {
-      el.setAttribute(attr, attrs[attr]);
-    }
-  }
-
-  return el;
-};
-
-jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
-  var showPassed, showSkipped;
-
-  this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
-      this.createDom('div', { className: 'banner' },
-        this.createDom('div', { className: 'logo' },
-            this.createDom('span', { className: 'title' }, "Jasmine"),
-            this.createDom('span', { className: 'version' }, runner.env.versionString())),
-        this.createDom('div', { className: 'options' },
-            "Show ",
-            showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
-            this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
-            showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
-            this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
-            )
-          ),
-
-      this.runnerDiv = this.createDom('div', { className: 'runner running' },
-          this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
-          this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
-          this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
-      );
-
-  this.document.body.appendChild(this.outerDiv);
-
-  var suites = runner.suites();
-  for (var i = 0; i < suites.length; i++) {
-    var suite = suites[i];
-    var suiteDiv = this.createDom('div', { className: 'suite' },
-        this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
-        this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
-    this.suiteDivs[suite.id] = suiteDiv;
-    var parentDiv = this.outerDiv;
-    if (suite.parentSuite) {
-      parentDiv = this.suiteDivs[suite.parentSuite.id];
-    }
-    parentDiv.appendChild(suiteDiv);
-  }
-
-  this.startedAt = new Date();
-
-  var self = this;
-  showPassed.onclick = function(evt) {
-    if (showPassed.checked) {
-      self.outerDiv.className += ' show-passed';
-    } else {
-      self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
-    }
-  };
-
-  showSkipped.onclick = function(evt) {
-    if (showSkipped.checked) {
-      self.outerDiv.className += ' show-skipped';
-    } else {
-      self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
-    }
-  };
-};
-
-jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
-  var results = runner.results();
-  var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
-  this.runnerDiv.setAttribute("class", className);
-  //do it twice for IE
-  this.runnerDiv.setAttribute("className", className);
-  var specs = runner.specs();
-  var specCount = 0;
-  for (var i = 0; i < specs.length; i++) {
-    if (this.specFilter(specs[i])) {
-      specCount++;
-    }
-  }
-  var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
-  message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
-  this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
-
-  this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
-};
-
-jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
-  var results = suite.results();
-  var status = results.passed() ? 'passed' : 'failed';
-  if (results.totalCount === 0) { // todo: change this to check results.skipped
-    status = 'skipped';
-  }
-  this.suiteDivs[suite.id].className += " " + status;
-};
-
-jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
-  if (this.logRunningSpecs) {
-    this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
-  }
-};
-
-jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
-  var results = spec.results();
-  var status = results.passed() ? 'passed' : 'failed';
-  if (results.skipped) {
-    status = 'skipped';
-  }
-  var specDiv = this.createDom('div', { className: 'spec '  + status },
-      this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
-      this.createDom('a', {
-        className: 'description',
-        href: '?spec=' + encodeURIComponent(spec.getFullName()),
-        title: spec.getFullName()
-      }, spec.description));
-
-
-  var resultItems = results.getItems();
-  var messagesDiv = this.createDom('div', { className: 'messages' });
-  for (var i = 0; i < resultItems.length; i++) {
-    var result = resultItems[i];
-
-    if (result.type == 'log') {
-      messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
-    } else if (result.type == 'expect' && result.passed && !result.passed()) {
-      messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
-
-      if (result.trace.stack) {
-        messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
-      }
-    }
-  }
-
-  if (messagesDiv.childNodes.length > 0) {
-    specDiv.appendChild(messagesDiv);
-  }
-
-  this.suiteDivs[spec.suite.id].appendChild(specDiv);
-};
-
-jasmine.TrivialReporter.prototype.log = function() {
-  var console = jasmine.getGlobal().console;
-  if (console && console.log) {
-    if (console.log.apply) {
-      console.log.apply(console, arguments);
-    } else {
-      console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
-    }
-  }
-};
-
-jasmine.TrivialReporter.prototype.getLocation = function() {
-  return this.document.location;
-};
-
-jasmine.TrivialReporter.prototype.specFilter = function(spec) {
-  var paramMap = {};
-  var params = this.getLocation().search.substring(1).split('&');
-  for (var i = 0; i < params.length; i++) {
-    var p = params[i].split('=');
-    paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
-  }
-
-  if (!paramMap.spec) {
-    return true;
-  }
-  return spec.getFullName().indexOf(paramMap.spec) === 0;
-};
-
+    }
+
+    if (!paramMap.spec) {
+        return true;
+    }
+    return spec.getFullName().indexOf(paramMap.spec) === 0;
+};
+

--- a/js/flotr2/lib/jasmine/jasmine.css
+++ b/js/flotr2/lib/jasmine/jasmine.css
@@ -1,82 +1,403 @@
-body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
-
-#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
-#HTMLReporter a { text-decoration: none; }
-#HTMLReporter a:hover { text-decoration: underline; }
-#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
-#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
-#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
-#HTMLReporter .version { color: #aaaaaa; }
-#HTMLReporter .banner { margin-top: 14px; }
-#HTMLReporter .duration { color: #aaaaaa; float: right; }
-#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
-#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
-#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
-#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
-#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
-#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
-#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
-#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
-#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
-#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
-#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
-#HTMLReporter .runningAlert { background-color: #666666; }
-#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
-#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
-#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
-#HTMLReporter .passingAlert { background-color: #a6b779; }
-#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
-#HTMLReporter .failingAlert { background-color: #cf867e; }
-#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
-#HTMLReporter .results { margin-top: 14px; }
-#HTMLReporter #details { display: none; }
-#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
-#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
-#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
-#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
-#HTMLReporter.showDetails .summary { display: none; }
-#HTMLReporter.showDetails #details { display: block; }
-#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
-#HTMLReporter .summary { margin-top: 14px; }
-#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
-#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
-#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
-#HTMLReporter .description + .suite { margin-top: 0; }
-#HTMLReporter .suite { margin-top: 14px; }
-#HTMLReporter .suite a { color: #333333; }
-#HTMLReporter #details .specDetail { margin-bottom: 28px; }
-#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
-#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
-#HTMLReporter .resultMessage span.result { display: block; }
-#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
-
-#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
-#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
-#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
-#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
-#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
-#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
-#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
-#TrivialReporter .runner.running { background-color: yellow; }
-#TrivialReporter .options { text-align: right; font-size: .8em; }
-#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
-#TrivialReporter .suite .suite { margin: 5px; }
-#TrivialReporter .suite.passed { background-color: #dfd; }
-#TrivialReporter .suite.failed { background-color: #fdd; }
-#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
-#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
-#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
-#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
-#TrivialReporter .spec.skipped { background-color: #bbb; }
-#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
-#TrivialReporter .passed { background-color: #cfc; display: none; }
-#TrivialReporter .failed { background-color: #fbb; }
-#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
-#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
-#TrivialReporter .resultMessage .mismatch { color: black; }
-#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
-#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
-#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
-#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
-#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }
-
+body {
+    background-color: #eeeeee;
+    padding: 0;
+    margin: 5px;
+    overflow-y: scroll;
+}
+
+#HTMLReporter {
+    font-size: 11px;
+    font-family: Monaco, "Lucida Console", monospace;
+    line-height: 14px;
+    color: #333333;
+}
+
+#HTMLReporter a {
+    text-decoration: none;
+}
+
+#HTMLReporter a:hover {
+    text-decoration: underline;
+}
+
+#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 {
+    margin: 0;
+    line-height: 14px;
+}
+
+#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace {
+    padding-left: 9px;
+    padding-right: 9px;
+}
+
+#HTMLReporter #jasmine_content {
+    position: fixed;
+    right: 100%;
+}
+
+#HTMLReporter .version {
+    color: #aaaaaa;
+}
+
+#HTMLReporter .banner {
+    margin-top: 14px;
+}
+
+#HTMLReporter .duration {
+    color: #aaaaaa;
+    float: right;
+}
+
+#HTMLReporter .symbolSummary {
+    overflow: hidden;
+    *zoom: 1;
+    margin: 14px 0;
+}
+
+#HTMLReporter .symbolSummary li {
+    display: block;
+    float: left;
+    height: 7px;
+    width: 14px;
+    margin-bottom: 7px;
+    font-size: 16px;
+}
+
+#HTMLReporter .symbolSummary li.passed {
+    font-size: 14px;
+}
+
+#HTMLReporter .symbolSummary li.passed:before {
+    color: #5e7d00;
+    content: "\02022";
+}
+
+#HTMLReporter .symbolSummary li.failed {
+    line-height: 9px;
+}
+
+#HTMLReporter .symbolSummary li.failed:before {
+    color: #b03911;
+    content: "x";
+    font-weight: bold;
+    margin-left: -1px;
+}
+
+#HTMLReporter .symbolSummary li.skipped {
+    font-size: 14px;
+}
+
+#HTMLReporter .symbolSummary li.skipped:before {
+    color: #bababa;
+    content: "\02022";
+}
+
+#HTMLReporter .symbolSummary li.pending {
+    line-height: 11px;
+}
+
+#HTMLReporter .symbolSummary li.pending:before {
+    color: #aaaaaa;
+    content: "-";
+}
+
+#HTMLReporter .bar {
+    line-height: 28px;
+    font-size: 14px;
+    display: block;
+    color: #eee;
+}
+
+#HTMLReporter .runningAlert {
+    background-color: #666666;
+}
+
+#HTMLReporter .skippedAlert {
+    background-color: #aaaaaa;
+}
+
+#HTMLReporter .skippedAlert:first-child {
+    background-color: #333333;
+}
+
+#HTMLReporter .skippedAlert:hover {
+    text-decoration: none;
+    color: white;
+    text-decoration: underline;
+}
+
+#HTMLReporter .passingAlert {
+    background-color: #a6b779;
+}
+
+#HTMLReporter .passingAlert:first-child {
+    background-color: #5e7d00;
+}
+
+#HTMLReporter .failingAlert {
+    background-color: #cf867e;
+}
+
+#HTMLReporter .failingAlert:first-child {
+    background-color: #b03911;
+}
+
+#HTMLReporter .results {
+    margin-top: 14px;
+}
+
+#HTMLReporter #details {
+    display: none;
+}
+
+#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a {
+    background-color: #fff;
+    color: #333333;
+}
+
+#HTMLReporter.showDetails .summaryMenuItem {
+    font-weight: normal;
+    text-decoration: inherit;
+}
+
+#HTMLReporter.showDetails .summaryMenuItem:hover {
+    text-decoration: underline;
+}
+
+#HTMLReporter.showDetails .detailsMenuItem {
+    font-weight: bold;
+    text-decoration: underline;
+}
+
+#HTMLReporter.showDetails .summary {
+    display: none;
+}
+
+#HTMLReporter.showDetails #details {
+    display: block;
+}
+
+#HTMLReporter .summaryMenuItem {
+    font-weight: bold;
+    text-decoration: underline;
+}
+
+#HTMLReporter .summary {
+    margin-top: 14px;
+}
+
+#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary {
+    margin-left: 14px;
+}
+
+#HTMLReporter .summary .specSummary.passed a {
+    color: #5e7d00;
+}
+
+#HTMLReporter .summary .specSummary.failed a {
+    color: #b03911;
+}
+
+#HTMLReporter .description + .suite {
+    margin-top: 0;
+}
+
+#HTMLReporter .suite {
+    margin-top: 14px;
+}
+
+#HTMLReporter .suite a {
+    color: #333333;
+}
+
+#HTMLReporter #details .specDetail {
+    margin-bottom: 28px;
+}
+
+#HTMLReporter #details .specDetail .description {
+    display: block;
+    color: white;
+    background-color: #b03911;
+}
+
+#HTMLReporter .resultMessage {
+    padding-top: 14px;
+    color: #333333;
+}
+
+#HTMLReporter .resultMessage span.result {
+    display: block;
+}
+
+#HTMLReporter .stackTrace {
+    margin: 5px 0 0 0;
+    max-height: 224px;
+    overflow: auto;
+    line-height: 18px;
+    color: #666666;
+    border: 1px solid #ddd;
+    background: white;
+    white-space: pre;
+}
+
+#TrivialReporter {
+    padding: 8px 13px;
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    overflow-y: scroll;
+    background-color: white;
+    font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/
+    /*white-space: pre;*/
+    /*}*/
+}
+
+#TrivialReporter a:visited, #TrivialReporter a {
+    color: #303;
+}
+
+#TrivialReporter a:hover, #TrivialReporter a:active {
+    color: blue;
+}
+
+#TrivialReporter .run_spec {
+    float: right;
+    padding-right: 5px;
+    font-size: .8em;
+    text-decoration: none;
+}
+
+#TrivialReporter .banner {
+    color: #303;
+    background-color: #fef;
+    padding: 5px;
+}
+
+#TrivialReporter .logo {
+    float: left;
+    font-size: 1.1em;
+    padding-left: 5px;
+}
+
+#TrivialReporter .logo .version {
+    font-size: .6em;
+    padding-left: 1em;
+}
+
+#TrivialReporter .runner.running {
+    background-color: yellow;
+}
+
+#TrivialReporter .options {
+    text-align: right;
+    font-size: .8em;
+}
+
+#TrivialReporter .suite {
+    border: 1px outset gray;
+    margin: 5px 0;
+    padding-left: 1em;
+}
+
+#TrivialReporter .suite .suite {
+    margin: 5px;
+}
+
+#TrivialReporter .suite.passed {
+    background-color: #dfd;
+}
+
+#TrivialReporter .suite.failed {
+    background-color: #fdd;
+}
+
+#TrivialReporter .spec {
+    margin: 5px;
+    padding-left: 1em;
+    clear: both;
+}
+
+#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped {
+    padding-bottom: 5px;
+    border: 1px solid gray;
+}
+
+#TrivialReporter .spec.failed {
+    background-color: #fbb;
+    border-color: red;
+}
+
+#TrivialReporter .spec.passed {
+    background-color: #bfb;
+    border-color: green;
+}
+
+#TrivialReporter .spec.skipped {
+    background-color: #bbb;
+}
+
+#TrivialReporter .messages {
+    border-left: 1px dashed gray;
+    padding-left: 1em;
+    padding-right: 1em;
+}
+
+#TrivialReporter .passed {
+    background-color: #cfc;
+    display: none;
+}
+
+#TrivialReporter .failed {
+    background-color: #fbb;
+}
+
+#TrivialReporter .skipped {
+    color: #777;
+    background-color: #eee;
+    display: none;
+}
+
+#TrivialReporter .resultMessage span.result {
+    display: block;
+    line-height: 2em;
+    color: black;
+}
+
+#TrivialReporter .resultMessage .mismatch {
+    color: black;
+}
+
+#TrivialReporter .stackTrace {
+    white-space: pre;
+    font-size: .8em;
+    margin-left: 10px;
+    max-height: 5em;
+    overflow: auto;
+    border: 1px inset red;
+    padding: 1em;
+    background: #eef;
+}
+
+#TrivialReporter .finished-at {
+    padding-left: 1em;
+    font-size: .6em;
+}
+
+#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped {
+    display: block;
+}
+
+#TrivialReporter #jasmine_content {
+    position: fixed;
+    right: 100%;
+}
+
+#TrivialReporter .runner {
+    border: 1px solid gray;
+    display: block;
+    margin: 5px 0;
+    padding: 2px 0 2px 10px;
+}
+

--- a/js/flotr2/lib/jasmine/jasmine.js
+++ b/js/flotr2/lib/jasmine/jasmine.js
@@ -10,8 +10,8 @@
 /**
  * @private
  */
-jasmine.unimplementedMethod_ = function() {
-  throw new Error("unimplemented method");
+jasmine.unimplementedMethod_ = function () {
+    throw new Error("unimplemented method");
 };
 
 /**
@@ -39,12 +39,12 @@
  */
 jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
 
-jasmine.getGlobal = function() {
-  function getGlobal() {
-    return this;
-  }
-
-  return getGlobal();
+jasmine.getGlobal = function () {
+    function getGlobal() {
+        return this;
+    }
+
+    return getGlobal();
 };
 
 /**
@@ -55,16 +55,16 @@
  * @param base {Object} bound 'this' for the function
  * @param name {Function} function to find
  */
-jasmine.bindOriginal_ = function(base, name) {
-  var original = base[name];
-  if (original.apply) {
-    return function() {
-      return original.apply(base, arguments);
-    };
-  } else {
-    // IE support
-    return jasmine.getGlobal()[name];
-  }
+jasmine.bindOriginal_ = function (base, name) {
+    var original = base[name];
+    if (original.apply) {
+        return function () {
+            return original.apply(base, arguments);
+        };
+    } else {
+        // IE support
+        return jasmine.getGlobal()[name];
+    }
 };
 
 jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');
@@ -72,51 +72,51 @@
 jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');
 jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');
 
-jasmine.MessageResult = function(values) {
-  this.type = 'log';
-  this.values = values;
-  this.trace = new Error(); // todo: test better
-};
-
-jasmine.MessageResult.prototype.toString = function() {
-  var text = "";
-  for (var i = 0; i < this.values.length; i++) {
-    if (i > 0) text += " ";
-    if (jasmine.isString_(this.values[i])) {
-      text += this.values[i];
-    } else {
-      text += jasmine.pp(this.values[i]);
-    }
-  }
-  return text;
-};
-
-jasmine.ExpectationResult = function(params) {
-  this.type = 'expect';
-  this.matcherName = params.matcherName;
-  this.passed_ = params.passed;
-  this.expected = params.expected;
-  this.actual = params.actual;
-  this.message = this.passed_ ? 'Passed.' : params.message;
-
-  var trace = (params.trace || new Error(this.message));
-  this.trace = this.passed_ ? '' : trace;
+jasmine.MessageResult = function (values) {
+    this.type = 'log';
+    this.values = values;
+    this.trace = new Error(); // todo: test better
+};
+
+jasmine.MessageResult.prototype.toString = function () {
+    var text = "";
+    for (var i = 0; i < this.values.length; i++) {
+        if (i > 0) text += " ";
+        if (jasmine.isString_(this.values[i])) {
+            text += this.values[i];
+        } else {
+            text += jasmine.pp(this.values[i]);
+        }
+    }
+    return text;
+};
+
+jasmine.ExpectationResult = function (params) {
+    this.type = 'expect';
+    this.matcherName = params.matcherName;
+    this.passed_ = params.passed;
+    this.expected = params.expected;
+    this.actual = params.actual;
+    this.message = this.passed_ ? 'Passed.' : params.message;
+
+    var trace = (params.trace || new Error(this.message));
+    this.trace = this.passed_ ? '' : trace;
 };
 
 jasmine.ExpectationResult.prototype.toString = function () {
-  return this.message;
+    return this.message;
 };
 
 jasmine.ExpectationResult.prototype.passed = function () {
-  return this.passed_;
+    return this.passed_;
 };
 
 /**
  * Getter for the Jasmine environment. Ensures one gets created
  */
-jasmine.getEnv = function() {
-  var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
-  return env;
+jasmine.getEnv = function () {
+    var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
+    return env;
 };
 
 /**
@@ -125,8 +125,8 @@
  * @param value
  * @returns {Boolean}
  */
-jasmine.isArray_ = function(value) {
-  return jasmine.isA_("Array", value);
+jasmine.isArray_ = function (value) {
+    return jasmine.isA_("Array", value);
 };
 
 /**
@@ -135,8 +135,8 @@
  * @param value
  * @returns {Boolean}
  */
-jasmine.isString_ = function(value) {
-  return jasmine.isA_("String", value);
+jasmine.isString_ = function (value) {
+    return jasmine.isA_("String", value);
 };
 
 /**
@@ -145,8 +145,8 @@
  * @param value
  * @returns {Boolean}
  */
-jasmine.isNumber_ = function(value) {
-  return jasmine.isA_("Number", value);
+jasmine.isNumber_ = function (value) {
+    return jasmine.isA_("Number", value);
 };
 
 /**
@@ -156,8 +156,8 @@
  * @param value
  * @returns {Boolean}
  */
-jasmine.isA_ = function(typeName, value) {
-  return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
+jasmine.isA_ = function (typeName, value) {
+    return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
 };
 
 /**
@@ -166,10 +166,10 @@
  * @param value {Object} an object to be outputted
  * @returns {String}
  */
-jasmine.pp = function(value) {
-  var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
-  stringPrettyPrinter.format(value);
-  return stringPrettyPrinter.string;
+jasmine.pp = function (value) {
+    var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
+    stringPrettyPrinter.format(value);
+    return stringPrettyPrinter.string;
 };
 
 /**
@@ -178,8 +178,8 @@
  * @param {Object} obj object to check
  * @returns {Boolean}
  */
-jasmine.isDomNode = function(obj) {
-  return obj.nodeType > 0;
+jasmine.isDomNode = function (obj) {
+    return obj.nodeType > 0;
 };
 
 /**
@@ -192,8 +192,8 @@
  * @param {Class} clazz
  * @returns matchable object of the type clazz
  */
-jasmine.any = function(clazz) {
-  return new jasmine.Matchers.Any(clazz);
+jasmine.any = function (clazz) {
+    return new jasmine.Matchers.Any(clazz);
 };
 
 /**
@@ -255,41 +255,41 @@
  * @see spyOn, jasmine.createSpy, jasmine.createSpyObj
  * @param {String} name
  */
-jasmine.Spy = function(name) {
-  /**
-   * The name of the spy, if provided.
-   */
-  this.identity = name || 'unknown';
-  /**
-   *  Is this Object a spy?
-   */
-  this.isSpy = true;
-  /**
-   * The actual function this spy stubs.
-   */
-  this.plan = function() {
-  };
-  /**
-   * Tracking of the most recent call to the spy.
-   * @example
-   * var mySpy = jasmine.createSpy('foo');
-   * mySpy(1, 2);
-   * mySpy.mostRecentCall.args = [1, 2];
-   */
-  this.mostRecentCall = {};
-
-  /**
-   * Holds arguments for each call to the spy, indexed by call count
-   * @example
-   * var mySpy = jasmine.createSpy('foo');
-   * mySpy(1, 2);
-   * mySpy(7, 8);
-   * mySpy.mostRecentCall.args = [7, 8];
-   * mySpy.argsForCall[0] = [1, 2];
-   * mySpy.argsForCall[1] = [7, 8];
-   */
-  this.argsForCall = [];
-  this.calls = [];
+jasmine.Spy = function (name) {
+    /**
+     * The name of the spy, if provided.
+     */
+    this.identity = name || 'unknown';
+    /**
+     *  Is this Object a spy?
+     */
+    this.isSpy = true;
+    /**
+     * The actual function this spy stubs.
+     */
+    this.plan = function () {
+    };
+    /**
+     * Tracking of the most recent call to the spy.
+     * @example
+     * var mySpy = jasmine.createSpy('foo');
+     * mySpy(1, 2);
+     * mySpy.mostRecentCall.args = [1, 2];
+     */
+    this.mostRecentCall = {};
+
+    /**
+     * Holds arguments for each call to the spy, indexed by call count
+     * @example
+     * var mySpy = jasmine.createSpy('foo');
+     * mySpy(1, 2);
+     * mySpy(7, 8);
+     * mySpy.mostRecentCall.args = [7, 8];
+     * mySpy.argsForCall[0] = [1, 2];
+     * mySpy.argsForCall[1] = [7, 8];
+     */
+    this.argsForCall = [];
+    this.calls = [];
 };
 
 /**
@@ -303,9 +303,9 @@
  * // defining a spy on an existing property: foo.bar
  * spyOn(foo, 'bar').andCallThrough();
  */
-jasmine.Spy.prototype.andCallThrough = function() {
-  this.plan = this.originalValue;
-  return this;
+jasmine.Spy.prototype.andCallThrough = function () {
+    this.plan = this.originalValue;
+    return this;
 };
 
 /**
@@ -320,11 +320,11 @@
  *
  * @param {Object} value
  */
-jasmine.Spy.prototype.andReturn = function(value) {
-  this.plan = function() {
-    return value;
-  };
-  return this;
+jasmine.Spy.prototype.andReturn = function (value) {
+    this.plan = function () {
+        return value;
+    };
+    return this;
 };
 
 /**
@@ -339,11 +339,11 @@
  *
  * @param {String} exceptionMsg
  */
-jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
-  this.plan = function() {
-    throw exceptionMsg;
-  };
-  return this;
+jasmine.Spy.prototype.andThrow = function (exceptionMsg) {
+    this.plan = function () {
+        throw exceptionMsg;
+    };
+    return this;
 };
 
 /**
@@ -361,9 +361,9 @@
  *
  * @param {Function} fakeFunc
  */
-jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
-  this.plan = fakeFunc;
-  return this;
+jasmine.Spy.prototype.andCallFake = function (fakeFunc) {
+    this.plan = fakeFunc;
+    return this;
 };
 
 /**
@@ -380,36 +380,36 @@
  *
  * expect(foo.bar.callCount).toEqual(0);
  */
-jasmine.Spy.prototype.reset = function() {
-  this.wasCalled = false;
-  this.callCount = 0;
-  this.argsForCall = [];
-  this.calls = [];
-  this.mostRecentCall = {};
-};
-
-jasmine.createSpy = function(name) {
-
-  var spyObj = function() {
-    spyObj.wasCalled = true;
-    spyObj.callCount++;
-    var args = jasmine.util.argsToArray(arguments);
-    spyObj.mostRecentCall.object = this;
-    spyObj.mostRecentCall.args = args;
-    spyObj.argsForCall.push(args);
-    spyObj.calls.push({object: this, args: args});
-    return spyObj.plan.apply(this, arguments);
-  };
-
-  var spy = new jasmine.Spy(name);
-
-  for (var prop in spy) {
-    spyObj[prop] = spy[prop];
-  }
-
-  spyObj.reset();
-
-  return spyObj;
+jasmine.Spy.prototype.reset = function () {
+    this.wasCalled = false;
+    this.callCount = 0;
+    this.argsForCall = [];
+    this.calls = [];
+    this.mostRecentCall = {};
+};
+
+jasmine.createSpy = function (name) {
+
+    var spyObj = function () {
+        spyObj.wasCalled = true;
+        spyObj.callCount++;
+        var args = jasmine.util.argsToArray(arguments);
+        spyObj.mostRecentCall.object = this;
+        spyObj.mostRecentCall.args = args;
+        spyObj.argsForCall.push(args);
+        spyObj.calls.push({object: this, args: args});
+        return spyObj.plan.apply(this, arguments);
+    };
+
+    var spy = new jasmine.Spy(name);
+
+    for (var prop in spy) {
+        spyObj[prop] = spy[prop];
+    }
+
+    spyObj.reset();
+
+    return spyObj;
 };
 
 /**
@@ -418,8 +418,8 @@
  * @param {jasmine.Spy|Object} putativeSpy
  * @returns {Boolean}
  */
-jasmine.isSpy = function(putativeSpy) {
-  return putativeSpy && putativeSpy.isSpy;
+jasmine.isSpy = function (putativeSpy) {
+    return putativeSpy && putativeSpy.isSpy;
 };
 
 /**
@@ -429,15 +429,15 @@
  * @param {String} baseName name of spy class
  * @param {Array} methodNames array of names of methods to make spies
  */
-jasmine.createSpyObj = function(baseName, methodNames) {
-  if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
-    throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
-  }
-  var obj = {};
-  for (var i = 0; i < methodNames.length; i++) {
-    obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
-  }
-  return obj;
+jasmine.createSpyObj = function (baseName, methodNames) {
+    if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
+        throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
+    }
+    var obj = {};
+    for (var i = 0; i < methodNames.length; i++) {
+        obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
+    }
+    return obj;
 };
 
 /**
@@ -445,9 +445,9 @@
  *
  * Be careful not to leave calls to <code>jasmine.log</code> in production code.
  */
-jasmine.log = function() {
-  var spec = jasmine.getEnv().currentSpec;
-  spec.log.apply(spec, arguments);
+jasmine.log = function () {
+    var spec = jasmine.getEnv().currentSpec;
+    spec.log.apply(spec, arguments);
 };
 
 /**
@@ -465,8 +465,8 @@
  * @param methodName
  * @returns a Jasmine spy that can be chained with all spy methods
  */
-var spyOn = function(obj, methodName) {
-  return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
+var spyOn = function (obj, methodName) {
+    return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
 };
 if (isCommonJS) exports.spyOn = spyOn;
 
@@ -483,8 +483,8 @@
  * @param {String} desc description of this specification
  * @param {Function} func defines the preconditions and expectations of the spec
  */
-var it = function(desc, func) {
-  return jasmine.getEnv().it(desc, func);
+var it = function (desc, func) {
+    return jasmine.getEnv().it(desc, func);
 };
 if (isCommonJS) exports.it = it;
 
@@ -496,8 +496,8 @@
  * @param {String} desc description of this specification
  * @param {Function} func defines the preconditions and expectations of the spec
  */
-var xit = function(desc, func) {
-  return jasmine.getEnv().xit(desc, func);
+var xit = function (desc, func) {
+    return jasmine.getEnv().xit(desc, func);
 };
 if (isCommonJS) exports.xit = xit;
 
@@ -509,8 +509,8 @@
  *
  * @param {Object} actual Actual value to test against and expected value
  */
-var expect = function(actual) {
-  return jasmine.getEnv().currentSpec.expect(actual);
+var expect = function (actual) {
+    return jasmine.getEnv().currentSpec.expect(actual);
 };
 if (isCommonJS) exports.expect = expect;
 
@@ -519,8 +519,8 @@
  *
  * @param {Function} func Function that defines part of a jasmine spec.
  */
-var runs = function(func) {
-  jasmine.getEnv().currentSpec.runs(func);
+var runs = function (func) {
+    jasmine.getEnv().currentSpec.runs(func);
 };
 if (isCommonJS) exports.runs = runs;
 
@@ -530,8 +530,8 @@
  * @deprecated Use waitsFor() instead
  * @param {Number} timeout milliseconds to wait
  */
-var waits = function(timeout) {
-  jasmine.getEnv().currentSpec.waits(timeout);
+var waits = function (timeout) {
+    jasmine.getEnv().currentSpec.waits(timeout);
 };
 if (isCommonJS) exports.waits = waits;
 
@@ -542,8 +542,8 @@
  * @param {String} optional_timeoutMessage
  * @param {Number} optional_timeout
  */
-var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
-  jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
+var waitsFor = function (latchFunction, optional_timeoutMessage, optional_timeout) {
+    jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
 };
 if (isCommonJS) exports.waitsFor = waitsFor;
 
@@ -554,8 +554,8 @@
  *
  * @param {Function} beforeEachFunction
  */
-var beforeEach = function(beforeEachFunction) {
-  jasmine.getEnv().beforeEach(beforeEachFunction);
+var beforeEach = function (beforeEachFunction) {
+    jasmine.getEnv().beforeEach(beforeEachFunction);
 };
 if (isCommonJS) exports.beforeEach = beforeEach;
 
@@ -566,8 +566,8 @@
  *
  * @param {Function} afterEachFunction
  */
-var afterEach = function(afterEachFunction) {
-  jasmine.getEnv().afterEach(afterEachFunction);
+var afterEach = function (afterEachFunction) {
+    jasmine.getEnv().afterEach(afterEachFunction);
 };
 if (isCommonJS) exports.afterEach = afterEach;
 
@@ -586,8 +586,8 @@
  * @param {String} description A string, usually the class under test.
  * @param {Function} specDefinitions function that defines several specs.
  */
-var describe = function(description, specDefinitions) {
-  return jasmine.getEnv().describe(description, specDefinitions);
+var describe = function (description, specDefinitions) {
+    return jasmine.getEnv().describe(description, specDefinitions);
 };
 if (isCommonJS) exports.describe = describe;
 
@@ -597,38 +597,38 @@
  * @param {String} description A string, usually the class under test.
  * @param {Function} specDefinitions function that defines several specs.
  */
-var xdescribe = function(description, specDefinitions) {
-  return jasmine.getEnv().xdescribe(description, specDefinitions);
+var xdescribe = function (description, specDefinitions) {
+    return jasmine.getEnv().xdescribe(description, specDefinitions);
 };
 if (isCommonJS) exports.xdescribe = xdescribe;
 
 
 // Provide the XMLHttpRequest class for IE 5.x-6.x:
-jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
-  function tryIt(f) {
-    try {
-      return f();
-    } catch(e) {
-    }
-    return null;
-  }
-
-  var xhr = tryIt(function() {
-    return new ActiveXObject("Msxml2.XMLHTTP.6.0");
-  }) ||
-    tryIt(function() {
-      return new ActiveXObject("Msxml2.XMLHTTP.3.0");
+jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function () {
+    function tryIt(f) {
+        try {
+            return f();
+        } catch (e) {
+        }
+        return null;
+    }
+
+    var xhr = tryIt(function () {
+        return new ActiveXObject("Msxml2.XMLHTTP.6.0");
     }) ||
-    tryIt(function() {
-      return new ActiveXObject("Msxml2.XMLHTTP");
-    }) ||
-    tryIt(function() {
-      return new ActiveXObject("Microsoft.XMLHTTP");
-    });
-
-  if (!xhr) throw new Error("This browser does not support XMLHttpRequest.");
-
-  return xhr;
+        tryIt(function () {
+            return new ActiveXObject("Msxml2.XMLHTTP.3.0");
+        }) ||
+        tryIt(function () {
+            return new ActiveXObject("Msxml2.XMLHTTP");
+        }) ||
+        tryIt(function () {
+            return new ActiveXObject("Microsoft.XMLHTTP");
+        });
+
+    if (!xhr) throw new Error("This browser does not support XMLHttpRequest.");
+
+    return xhr;
 } : XMLHttpRequest;
 /**
  * @namespace
@@ -642,59 +642,59 @@
  * @param {Function} childClass
  * @param {Function} parentClass
  */
-jasmine.util.inherit = function(childClass, parentClass) {
-  /**
-   * @private
-   */
-  var subclass = function() {
-  };
-  subclass.prototype = parentClass.prototype;
-  childClass.prototype = new subclass();
-};
-
-jasmine.util.formatException = function(e) {
-  var lineNumber;
-  if (e.line) {
-    lineNumber = e.line;
-  }
-  else if (e.lineNumber) {
-    lineNumber = e.lineNumber;
-  }
-
-  var file;
-
-  if (e.sourceURL) {
-    file = e.sourceURL;
-  }
-  else if (e.fileName) {
-    file = e.fileName;
-  }
-
-  var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
-
-  if (file && lineNumber) {
-    message += ' in ' + file + ' (line ' + lineNumber + ')';
-  }
-
-  return message;
-};
-
-jasmine.util.htmlEscape = function(str) {
-  if (!str) return str;
-  return str.replace(/&/g, '&amp;')
-    .replace(/</g, '&lt;')
-    .replace(/>/g, '&gt;');
-};
-
-jasmine.util.argsToArray = function(args) {
-  var arrayOfArgs = [];
-  for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
-  return arrayOfArgs;
-};
-
-jasmine.util.extend = function(destination, source) {
-  for (var property in source) destination[property] = source[property];
-  return destination;
+jasmine.util.inherit = function (childClass, parentClass) {
+    /**
+     * @private
+     */
+    var subclass = function () {
+    };
+    subclass.prototype = parentClass.prototype;
+    childClass.prototype = new subclass();
+};
+
+jasmine.util.formatException = function (e) {
+    var lineNumber;
+    if (e.line) {
+        lineNumber = e.line;
+    }
+    else if (e.lineNumber) {
+        lineNumber = e.lineNumber;
+    }
+
+    var file;
+
+    if (e.sourceURL) {
+        file = e.sourceURL;
+    }
+    else if (e.fileName) {
+        file = e.fileName;
+    }
+
+    var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
+
+    if (file && lineNumber) {
+        message += ' in ' + file + ' (line ' + lineNumber + ')';
+    }
+
+    return message;
+};
+
+jasmine.util.htmlEscape = function (str) {
+    if (!str) return str;
+    return str.replace(/&/g, '&amp;')
+        .replace(/</g, '&lt;')
+        .replace(/>/g, '&gt;');
+};
+
+jasmine.util.argsToArray = function (args) {
+    var arrayOfArgs = [];
+    for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
+    return arrayOfArgs;
+};
+
+jasmine.util.extend = function (destination, source) {
+    for (var property in source) destination[property] = source[property];
+    return destination;
 };
 
 /**
@@ -702,31 +702,31 @@
  *
  * @constructor
  */
-jasmine.Env = function() {
-  this.currentSpec = null;
-  this.currentSuite = null;
-  this.currentRunner_ = new jasmine.Runner(this);
-
-  this.reporter = new jasmine.MultiReporter();
-
-  this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
-  this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
-  this.lastUpdate = 0;
-  this.specFilter = function() {
-    return true;
-  };
-
-  this.nextSpecId_ = 0;
-  this.nextSuiteId_ = 0;
-  this.equalityTesters_ = [];
-
-  // wrap matchers
-  this.matchersClass = function() {
-    jasmine.Matchers.apply(this, arguments);
-  };
-  jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
-
-  jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
+jasmine.Env = function () {
+    this.currentSpec = null;
+    this.currentSuite = null;
+    this.currentRunner_ = new jasmine.Runner(this);
+
+    this.reporter = new jasmine.MultiReporter();
+
+    this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
+    this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
+    this.lastUpdate = 0;
+    this.specFilter = function () {
+        return true;
+    };
+
+    this.nextSpecId_ = 0;
+    this.nextSuiteId_ = 0;
+    this.equalityTesters_ = [];
+
+    // wrap matchers
+    this.matchersClass = function () {
+        jasmine.Matchers.apply(this, arguments);
+    };
+    jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
+
+    jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
 };
 
 
@@ -739,270 +739,270 @@
  * @returns an object containing jasmine version build info, if set.
  */
 jasmine.Env.prototype.version = function () {
-  if (jasmine.version_) {
-    return jasmine.version_;
-  } else {
-    throw new Error('Version not set');
-  }
+    if (jasmine.version_) {
+        return jasmine.version_;
+    } else {
+        throw new Error('Version not set');
+    }
 };
 
 /**
  * @returns string containing jasmine version build info, if set.
  */
-jasmine.Env.prototype.versionString = function() {
-  if (!jasmine.version_) {
-    return "version unknown";
-  }
-
-  var version = this.version();
-  var versionString = version.major + "." + version.minor + "." + version.build;
-  if (version.release_candidate) {
-    versionString += ".rc" + version.release_candidate;
-  }
-  versionString += " revision " + version.revision;
-  return versionString;
+jasmine.Env.prototype.versionString = function () {
+    if (!jasmine.version_) {
+        return "version unknown";
+    }
+
+    var version = this.version();
+    var versionString = version.major + "." + version.minor + "." + version.build;
+    if (version.release_candidate) {
+        versionString += ".rc" + version.release_candidate;
+    }
+    versionString += " revision " + version.revision;
+    return versionString;
 };
 
 /**
  * @returns a sequential integer starting at 0
  */
 jasmine.Env.prototype.nextSpecId = function () {
-  return this.nextSpecId_++;
+    return this.nextSpecId_++;
 };
 
 /**
  * @returns a sequential integer starting at 0
  */
 jasmine.Env.prototype.nextSuiteId = function () {
-  return this.nextSuiteId_++;
+    return this.nextSuiteId_++;
 };
 
 /**
  * Register a reporter to receive status updates from Jasmine.
  * @param {jasmine.Reporter} reporter An object which will receive status updates.
  */
-jasmine.Env.prototype.addReporter = function(reporter) {
-  this.reporter.addReporter(reporter);
-};
-
-jasmine.Env.prototype.execute = function() {
-  this.currentRunner_.execute();
-};
-
-jasmine.Env.prototype.describe = function(description, specDefinitions) {
-  var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
-
-  var parentSuite = this.currentSuite;
-  if (parentSuite) {
-    parentSuite.add(suite);
-  } else {
-    this.currentRunner_.add(suite);
-  }
-
-  this.currentSuite = suite;
-
-  var declarationError = null;
-  try {
-    specDefinitions.call(suite);
-  } catch(e) {
-    declarationError = e;
-  }
-
-  if (declarationError) {
-    this.it("encountered a declaration exception", function() {
-      throw declarationError;
-    });
-  }
-
-  this.currentSuite = parentSuite;
-
-  return suite;
-};
-
-jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
-  if (this.currentSuite) {
-    this.currentSuite.beforeEach(beforeEachFunction);
-  } else {
-    this.currentRunner_.beforeEach(beforeEachFunction);
-  }
+jasmine.Env.prototype.addReporter = function (reporter) {
+    this.reporter.addReporter(reporter);
+};
+
+jasmine.Env.prototype.execute = function () {
+    this.currentRunner_.execute();
+};
+
+jasmine.Env.prototype.describe = function (description, specDefinitions) {
+    var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
+
+    var parentSuite = this.currentSuite;
+    if (parentSuite) {
+        parentSuite.add(suite);
+    } else {
+        this.currentRunner_.add(suite);
+    }
+
+    this.currentSuite = suite;
+
+    var declarationError = null;
+    try {
+        specDefinitions.call(suite);
+    } catch (e) {
+        declarationError = e;
+    }
+
+    if (declarationError) {
+        this.it("encountered a declaration exception", function () {
+            throw declarationError;
+        });
+    }
+
+    this.currentSuite = parentSuite;
+
+    return suite;
+};
+
+jasmine.Env.prototype.beforeEach = function (beforeEachFunction) {
+    if (this.currentSuite) {
+        this.currentSuite.beforeEach(beforeEachFunction);
+    } else {
+        this.currentRunner_.beforeEach(beforeEachFunction);
+    }
 };
 
 jasmine.Env.prototype.currentRunner = function () {
-  return this.currentRunner_;
-};
-
-jasmine.Env.prototype.afterEach = function(afterEachFunction) {
-  if (this.currentSuite) {
-    this.currentSuite.afterEach(afterEachFunction);
-  } else {
-    this.currentRunner_.afterEach(afterEachFunction);
-  }
-
-};
-
-jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
-  return {
-    execute: function() {
-    }
-  };
-};
-
-jasmine.Env.prototype.it = function(description, func) {
-  var spec = new jasmine.Spec(this, this.currentSuite, description);
-  this.currentSuite.add(spec);
-  this.currentSpec = spec;
-
-  if (func) {
-    spec.runs(func);
-  }
-
-  return spec;
-};
-
-jasmine.Env.prototype.xit = function(desc, func) {
-  return {
-    id: this.nextSpecId(),
-    runs: function() {
-    }
-  };
-};
-
-jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
-  if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
-    return true;
-  }
-
-  a.__Jasmine_been_here_before__ = b;
-  b.__Jasmine_been_here_before__ = a;
-
-  var hasKey = function(obj, keyName) {
-    return obj !== null && obj[keyName] !== jasmine.undefined;
-  };
-
-  for (var property in b) {
-    if (!hasKey(a, property) && hasKey(b, property)) {
-      mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
-    }
-  }
-  for (property in a) {
-    if (!hasKey(b, property) && hasKey(a, property)) {
-      mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
-    }
-  }
-  for (property in b) {
-    if (property == '__Jasmine_been_here_before__') continue;
-    if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
-      mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
-    }
-  }
-
-  if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
-    mismatchValues.push("arrays were not the same length");
-  }
-
-  delete a.__Jasmine_been_here_before__;
-  delete b.__Jasmine_been_here_before__;
-  return (mismatchKeys.length === 0 && mismatchValues.length === 0);
-};
-
-jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
-  mismatchKeys = mismatchKeys || [];
-  mismatchValues = mismatchValues || [];
-
-  for (var i = 0; i < this.equalityTesters_.length; i++) {
-    var equalityTester = this.equalityTesters_[i];
-    var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
-    if (result !== jasmine.undefined) return result;
-  }
-
-  if (a === b) return true;
-
-  if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {
-    return (a == jasmine.undefined && b == jasmine.undefined);
-  }
-
-  if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
-    return a === b;
-  }
-
-  if (a instanceof Date && b instanceof Date) {
-    return a.getTime() == b.getTime();
-  }
-
-  if (a.jasmineMatches) {
-    return a.jasmineMatches(b);
-  }
-
-  if (b.jasmineMatches) {
-    return b.jasmineMatches(a);
-  }
-
-  if (a instanceof jasmine.Matchers.ObjectContaining) {
-    return a.matches(b);
-  }
-
-  if (b instanceof jasmine.Matchers.ObjectContaining) {
-    return b.matches(a);
-  }
-
-  if (jasmine.isString_(a) && jasmine.isString_(b)) {
-    return (a == b);
-  }
-
-  if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
-    return (a == b);
-  }
-
-  if (typeof a === "object" && typeof b === "object") {
-    return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
-  }
-
-  //Straight check
-  return (a === b);
-};
-
-jasmine.Env.prototype.contains_ = function(haystack, needle) {
-  if (jasmine.isArray_(haystack)) {
-    for (var i = 0; i < haystack.length; i++) {
-      if (this.equals_(haystack[i], needle)) return true;
-    }
-    return false;
-  }
-  return haystack.indexOf(needle) >= 0;
-};
-
-jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
-  this.equalityTesters_.push(equalityTester);
+    return this.currentRunner_;
+};
+
+jasmine.Env.prototype.afterEach = function (afterEachFunction) {
+    if (this.currentSuite) {
+        this.currentSuite.afterEach(afterEachFunction);
+    } else {
+        this.currentRunner_.afterEach(afterEachFunction);
+    }
+
+};
+
+jasmine.Env.prototype.xdescribe = function (desc, specDefinitions) {
+    return {
+        execute: function () {
+        }
+    };
+};
+
+jasmine.Env.prototype.it = function (description, func) {
+    var spec = new jasmine.Spec(this, this.currentSuite, description);
+    this.currentSuite.add(spec);
+    this.currentSpec = spec;
+
+    if (func) {
+        spec.runs(func);
+    }
+
+    return spec;
+};
+
+jasmine.Env.prototype.xit = function (desc, func) {
+    return {
+        id: this.nextSpecId(),
+        runs: function () {
+        }
+    };
+};
+
+jasmine.Env.prototype.compareObjects_ = function (a, b, mismatchKeys, mismatchValues) {
+    if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
+        return true;
+    }
+
+    a.__Jasmine_been_here_before__ = b;
+    b.__Jasmine_been_here_before__ = a;
+
+    var hasKey = function (obj, keyName) {
+        return obj !== null && obj[keyName] !== jasmine.undefined;
+    };
+
+    for (var property in b) {
+        if (!hasKey(a, property) && hasKey(b, property)) {
+            mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
+        }
+    }
+    for (property in a) {
+        if (!hasKey(b, property) && hasKey(a, property)) {
+            mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
+        }
+    }
+    for (property in b) {
+        if (property == '__Jasmine_been_here_before__') continue;
+        if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
+            mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
+        }
+    }
+
+    if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
+        mismatchValues.push("arrays were not the same length");
+    }
+
+    delete a.__Jasmine_been_here_before__;
+    delete b.__Jasmine_been_here_before__;
+    return (mismatchKeys.length === 0 && mismatchValues.length === 0);
+};
+
+jasmine.Env.prototype.equals_ = function (a, b, mismatchKeys, mismatchValues) {
+    mismatchKeys = mismatchKeys || [];
+    mismatchValues = mismatchValues || [];
+
+    for (var i = 0; i < this.equalityTesters_.length; i++) {
+        var equalityTester = this.equalityTesters_[i];
+        var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
+        if (result !== jasmine.undefined) return result;
+    }
+
+    if (a === b) return true;
+
+    if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {
+        return (a == jasmine.undefined && b == jasmine.undefined);
+    }
+
+    if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
+        return a === b;
+    }
+
+    if (a instanceof Date && b instanceof Date) {
+        return a.getTime() == b.getTime();
+    }
+
+    if (a.jasmineMatches) {
+        return a.jasmineMatches(b);
+    }
+
+    if (b.jasmineMatches) {
+        return b.jasmineMatches(a);
+    }
+
+    if (a instanceof jasmine.Matchers.ObjectContaining) {
+        return a.matches(b);
+    }
+
+    if (b instanceof jasmine.Matchers.ObjectContaining) {
+        return b.matches(a);
+    }
+
+    if (jasmine.isString_(a) && jasmine.isString_(b)) {
+        return (a == b);
+    }
+
+    if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
+        return (a == b);
+    }
+
+    if (typeof a === "object" && typeof b === "object") {
+        return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
+    }
+
+    //Straight check
+    return (a === b);
+};
+
+jasmine.Env.prototype.contains_ = function (haystack, needle) {
+    if (jasmine.isArray_(haystack)) {
+        for (var i = 0; i < haystack.length; i++) {
+            if (this.equals_(haystack[i], needle)) return true;
+        }
+        return false;
+    }
+    return haystack.indexOf(needle) >= 0;
+};
+
+jasmine.Env.prototype.addEqualityTester = function (equalityTester) {
+    this.equalityTesters_.push(equalityTester);
 };
 /** No-op base class for Jasmine reporters.
  *
  * @constructor
  */
-jasmine.Reporter = function() {
+jasmine.Reporter = function () {
 };
 
 //noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportRunnerStarting = function(runner) {
+jasmine.Reporter.prototype.reportRunnerStarting = function (runner) {
 };
 
 //noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportRunnerResults = function(runner) {
+jasmine.Reporter.prototype.reportRunnerResults = function (runner) {
 };
 
 //noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportSuiteResults = function(suite) {
+jasmine.Reporter.prototype.reportSuiteResults = function (suite) {
 };
 
 //noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportSpecStarting = function(spec) {
+jasmine.Reporter.prototype.reportSpecStarting = function (spec) {
 };
 
 //noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportSpecResults = function(spec) {
+jasmine.Reporter.prototype.reportSpecResults = function (spec) {
 };
 
 //noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.log = function(str) {
+jasmine.Reporter.prototype.log = function (str) {
 };
 
 /**
@@ -1013,120 +1013,120 @@
  * @param {Function} func
  * @param {jasmine.Spec} spec
  */
-jasmine.Block = function(env, func, spec) {
-  this.env = env;
-  this.func = func;
-  this.spec = spec;
-};
-
-jasmine.Block.prototype.execute = function(onComplete) {  
-  try {
-    this.func.apply(this.spec);
-  } catch (e) {
-    this.spec.fail(e);
-  }
-  onComplete();
+jasmine.Block = function (env, func, spec) {
+    this.env = env;
+    this.func = func;
+    this.spec = spec;
+};
+
+jasmine.Block.prototype.execute = function (onComplete) {
+    try {
+        this.func.apply(this.spec);
+    } catch (e) {
+        this.spec.fail(e);
+    }
+    onComplete();
 };
 /** JavaScript API reporter.
  *
  * @constructor
  */
-jasmine.JsApiReporter = function() {
-  this.started = false;
-  this.finished = false;
-  this.suites_ = [];
-  this.results_ = {};
-};
-
-jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) {
-  this.started = true;
-  var suites = runner.topLevelSuites();
-  for (var i = 0; i < suites.length; i++) {
-    var suite = suites[i];
-    this.suites_.push(this.summarize_(suite));
-  }
-};
-
-jasmine.JsApiReporter.prototype.suites = function() {
-  return this.suites_;
-};
-
-jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {
-  var isSuite = suiteOrSpec instanceof jasmine.Suite;
-  var summary = {
-    id: suiteOrSpec.id,
-    name: suiteOrSpec.description,
-    type: isSuite ? 'suite' : 'spec',
-    children: []
-  };
-  
-  if (isSuite) {
-    var children = suiteOrSpec.children();
-    for (var i = 0; i < children.length; i++) {
-      summary.children.push(this.summarize_(children[i]));
-    }
-  }
-  return summary;
-};
-
-jasmine.JsApiReporter.prototype.results = function() {
-  return this.results_;
-};
-
-jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) {
-  return this.results_[specId];
+jasmine.JsApiReporter = function () {
+    this.started = false;
+    this.finished = false;
+    this.suites_ = [];
+    this.results_ = {};
+};
+
+jasmine.JsApiReporter.prototype.reportRunnerStarting = function (runner) {
+    this.started = true;
+    var suites = runner.topLevelSuites();
+    for (var i = 0; i < suites.length; i++) {
+        var suite = suites[i];
+        this.suites_.push(this.summarize_(suite));
+    }
+};
+
+jasmine.JsApiReporter.prototype.suites = function () {
+    return this.suites_;
+};
+
+jasmine.JsApiReporter.prototype.summarize_ = function (suiteOrSpec) {
+    var isSuite = suiteOrSpec instanceof jasmine.Suite;
+    var summary = {
+        id: suiteOrSpec.id,
+        name: suiteOrSpec.description,
+        type: isSuite ? 'suite' : 'spec',
+        children: []
+    };
+
+    if (isSuite) {
+        var children = suiteOrSpec.children();
+        for (var i = 0; i < children.length; i++) {
+            summary.children.push(this.summarize_(children[i]));
+        }
+    }
+    return summary;
+};
+
+jasmine.JsApiReporter.prototype.results = function () {
+    return this.results_;
+};
+
+jasmine.JsApiReporter.prototype.resultsForSpec = function (specId) {
+    return this.results_[specId];
 };
 
 //noinspection JSUnusedLocalSymbols
-jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) {
-  this.finished = true;
+jasmine.JsApiReporter.prototype.reportRunnerResults = function (runner) {
+    this.finished = true;
 };
 
 //noinspection JSUnusedLocalSymbols
-jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) {
+jasmine.JsApiReporter.prototype.reportSuiteResults = function (suite) {
 };
 
 //noinspection JSUnusedLocalSymbols
-jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) {
-  this.results_[spec.id] = {
-    messages: spec.results().getItems(),
-    result: spec.results().failedCount > 0 ? "failed" : "passed"
-  };
+jasmine.JsApiReporter.prototype.reportSpecResults = function (spec) {
+    this.results_[spec.id] = {
+        messages: spec.results().getItems(),
+        result: spec.results().failedCount > 0 ? "failed" : "passed"
+    };
 };
 
 //noinspection JSUnusedLocalSymbols
-jasmine.JsApiReporter.prototype.log = function(str) {
-};
-
-jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){
-  var results = {};
-  for (var i = 0; i < specIds.length; i++) {
-    var specId = specIds[i];
-    results[specId] = this.summarizeResult_(this.results_[specId]);
-  }
-  return results;
-};
-
-jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){
-  var summaryMessages = [];
-  var messagesLength = result.messages.length;
-  for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {
-    var resultMessage = result.messages[messageIndex];
-    summaryMessages.push({
-      text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,
-      passed: resultMessage.passed ? resultMessage.passed() : true,
-      type: resultMessage.type,
-      message: resultMessage.message,
-      trace: {
-        stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined
-      }
-    });
-  }
-
-  return {
-    result : result.result,
-    messages : summaryMessages
-  };
+jasmine.JsApiReporter.prototype.log = function (str) {
+};
+
+jasmine.JsApiReporter.prototype.resultsForSpecs = function (specIds) {
+    var results = {};
+    for (var i = 0; i < specIds.length; i++) {
+        var specId = specIds[i];
+        results[specId] = this.summarizeResult_(this.results_[specId]);
+    }
+    return results;
+};
+
+jasmine.JsApiReporter.prototype.summarizeResult_ = function (result) {
+    var summaryMessages = [];
+    var messagesLength = result.messages.length;
+    for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {
+        var resultMessage = result.messages[messageIndex];
+        summaryMessages.push({
+            text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,
+            passed: resultMessage.passed ? resultMessage.passed() : true,
+            type: resultMessage.type,
+            message: resultMessage.message,
+            trace: {
+                stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined
+            }
+        });
+    }
+
+    return {
+        result: result.result,
+        messages: summaryMessages
+    };
 };
 
 /**
@@ -1135,83 +1135,83 @@
  * @param actual
  * @param {jasmine.Spec} spec
  */
-jasmine.Matchers = function(env, actual, spec, opt_isNot) {
-  this.env = env;
-  this.actual = actual;
-  this.spec = spec;
-  this.isNot = opt_isNot || false;
-  this.reportWasCalled_ = false;
+jasmine.Matchers = function (env, actual, spec, opt_isNot) {
+    this.env = env;
+    this.actual = actual;
+    this.spec = spec;
+    this.isNot = opt_isNot || false;
+    this.reportWasCalled_ = false;
 };
 
 // todo: @deprecated as of Jasmine 0.11, remove soon [xw]
-jasmine.Matchers.pp = function(str) {
-  throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
+jasmine.Matchers.pp = function (str) {
+    throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
 };
 
 // todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]
-jasmine.Matchers.prototype.report = function(result, failing_message, details) {
-  throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
-};
-
-jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {
-  for (var methodName in prototype) {
-    if (methodName == 'report') continue;
-    var orig = prototype[methodName];
-    matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
-  }
-};
-
-jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
-  return function() {
-    var matcherArgs = jasmine.util.argsToArray(arguments);
-    var result = matcherFunction.apply(this, arguments);
-
-    if (this.isNot) {
-      result = !result;
-    }
-
-    if (this.reportWasCalled_) return result;
-
-    var message;
-    if (!result) {
-      if (this.message) {
-        message = this.message.apply(this, arguments);
-        if (jasmine.isArray_(message)) {
-          message = message[this.isNot ? 1 : 0];
-        }
-      } else {
-        var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
-        message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
-        if (matcherArgs.length > 0) {
-          for (var i = 0; i < matcherArgs.length; i++) {
-            if (i > 0) message += ",";
-            message += " " + jasmine.pp(matcherArgs[i]);
-          }
-        }
-        message += ".";
-      }
-    }
-    var expectationResult = new jasmine.ExpectationResult({
-      matcherName: matcherName,
-      passed: result,
-      expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
-      actual: this.actual,
-      message: message
-    });
-    this.spec.addMatcherResult(expectationResult);
-    return jasmine.undefined;
-  };
-};
-
-
+jasmine.Matchers.prototype.report = function (result, failing_message, details) {
+    throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
+};
+
+jasmine.Matchers.wrapInto_ = function (prototype, matchersClass) {
+    for (var methodName in prototype) {
+        if (methodName == 'report') continue;
+        var orig = prototype[methodName];
+        matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
+    }
+};
+
+jasmine.Matchers.matcherFn_ = function (matcherName, matcherFunction) {
+    return function () {
+        var matcherArgs = jasmine.util.argsToArray(arguments);
+        var result = matcherFunction.apply(this, arguments);
+
+        if (this.isNot) {
+            result = !result;
+        }
+
+        if (this.reportWasCalled_) return result;
+
+        var message;
+        if (!result) {
+            if (this.message) {
+                message = this.message.apply(this, arguments);
+                if (jasmine.isArray_(message)) {
+                    message = message[this.isNot ? 1 : 0];
+                }
+            } else {
+                var englishyPredicate = matcherName.replace(/[A-Z]/g, function (s) {
+                    return ' ' + s.toLowerCase();
+                });
+                message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
+                if (matcherArgs.length > 0) {
+                    for (var i = 0; i < matcherArgs.length; i++) {
+                        if (i > 0) message += ",";
+                        message += " " + jasmine.pp(matcherArgs[i]);
+                    }
+                }
+                message += ".";
+            }
+        }
+        var expectationResult = new jasmine.ExpectationResult({
+            matcherName: matcherName,
+            passed: result,
+            expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
+            actual: this.actual,
+            message: message
+        });
+        this.spec.addMatcherResult(expectationResult);
+        return jasmine.undefined;
+    };
+};
 
 
 /**
  * toBe: compares the actual to the expected using ===
  * @param expected
  */
-jasmine.Matchers.prototype.toBe = function(expected) {
-  return this.actual === expected;
+jasmine.Matchers.prototype.toBe = function (expected) {
+    return this.actual === expected;
 };
 
 /**
@@ -1219,8 +1219,8 @@
  * @param expected
  * @deprecated as of 1.0. Use not.toBe() instead.
  */
-jasmine.Matchers.prototype.toNotBe = function(expected) {
-  return this.actual !== expected;
+jasmine.Matchers.prototype.toNotBe = function (expected) {
+    return this.actual !== expected;
 };
 
 /**
@@ -1228,8 +1228,8 @@
  *
  * @param expected
  */
-jasmine.Matchers.prototype.toEqual = function(expected) {
-  return this.env.equals_(this.actual, expected);
+jasmine.Matchers.prototype.toEqual = function (expected) {
+    return this.env.equals_(this.actual, expected);
 };
 
 /**
@@ -1237,8 +1237,8 @@
  * @param expected
  * @deprecated as of 1.0. Use not.toEqual() instead.
  */
-jasmine.Matchers.prototype.toNotEqual = function(expected) {
-  return !this.env.equals_(this.actual, expected);
+jasmine.Matchers.prototype.toNotEqual = function (expected) {
+    return !this.env.equals_(this.actual, expected);
 };
 
 /**
@@ -1247,8 +1247,8 @@
  *
  * @param expected
  */
-jasmine.Matchers.prototype.toMatch = function(expected) {
-  return new RegExp(expected).test(this.actual);
+jasmine.Matchers.prototype.toMatch = function (expected) {
+    return new RegExp(expected).test(this.actual);
 };
 
 /**
@@ -1256,67 +1256,67 @@
  * @param expected
  * @deprecated as of 1.0. Use not.toMatch() instead.
  */
-jasmine.Matchers.prototype.toNotMatch = function(expected) {
-  return !(new RegExp(expected).test(this.actual));
+jasmine.Matchers.prototype.toNotMatch = function (expected) {
+    return !(new RegExp(expected).test(this.actual));
 };
 
 /**
  * Matcher that compares the actual to jasmine.undefined.
  */
-jasmine.Matchers.prototype.toBeDefined = function() {
-  return (this.actual !== jasmine.undefined);
+jasmine.Matchers.prototype.toBeDefined = function () {
+    return (this.actual !== jasmine.undefined);
 };
 
 /**
  * Matcher that compares the actual to jasmine.undefined.
  */
-jasmine.Matchers.prototype.toBeUndefined = function() {
-  return (this.actual === jasmine.undefined);
+jasmine.Matchers.prototype.toBeUndefined = function () {
+    return (this.actual === jasmine.undefined);
 };
 
 /**
  * Matcher that compares the actual to null.
  */
-jasmine.Matchers.prototype.toBeNull = function() {
-  return (this.actual === null);
+jasmine.Matchers.prototype.toBeNull = function () {
+    return (this.actual === null);
 };
 
 /**
  * Matcher that boolean not-nots the actual.
  */
-jasmine.Matchers.prototype.toBeTruthy = function() {
-  return !!this.actual;
+jasmine.Matchers.prototype.toBeTruthy = function () {
+    return !!this.actual;
 };
 
 
 /**
  * Matcher that boolean nots the actual.
  */
-jasmine.Matchers.prototype.toBeFalsy = function() {
-  return !this.actual;
+jasmine.Matchers.prototype.toBeFalsy = function () {
+    return !this.actual;
 };
 
 
 /**
  * Matcher that checks to see if the actual, a Jasmine spy, was called.
  */
-jasmine.Matchers.prototype.toHaveBeenCalled = function() {
-  if (arguments.length > 0) {
-    throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
-  }
-
-  if (!jasmine.isSpy(this.actual)) {
-    throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
-  }
-
-  this.message = function() {
-    return [
-      "Expected spy " + this.actual.identity + " to have been called.",
-      "Expected spy " + this.actual.identity + " not to have been called."
-    ];
-  };
-
-  return this.actual.wasCalled;
+jasmine.Matchers.prototype.toHaveBeenCalled = function () {
+    if (arguments.length > 0) {
+        throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
+    }
+
+    if (!jasmine.isSpy(this.actual)) {
+        throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+    }
+
+    this.message = function () {
+        return [
+            "Expected spy " + this.actual.identity + " to have been called.",
+            "Expected spy " + this.actual.identity + " not to have been called."
+        ];
+    };
+
+    return this.actual.wasCalled;
 };
 
 /** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
@@ -1327,23 +1327,23 @@
  *
  * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
  */
-jasmine.Matchers.prototype.wasNotCalled = function() {
-  if (arguments.length > 0) {
-    throw new Error('wasNotCalled does not take arguments');
-  }
-
-  if (!jasmine.isSpy(this.actual)) {
-    throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
-  }
-
-  this.message = function() {
-    return [
-      "Expected spy " + this.actual.identity + " to not have been called.",
-      "Expected spy " + this.actual.identity + " to have been called."
-    ];
-  };
-
-  return !this.actual.wasCalled;
+jasmine.Matchers.prototype.wasNotCalled = function () {
+    if (arguments.length > 0) {
+        throw new Error('wasNotCalled does not take arguments');
+    }
+
+    if (!jasmine.isSpy(this.actual)) {
+        throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+    }
+
+    this.message = function () {
+        return [
+            "Expected spy " + this.actual.identity + " to not have been called.",
+            "Expected spy " + this.actual.identity + " to have been called."
+        ];
+    };
+
+    return !this.actual.wasCalled;
 };
 
 /**
@@ -1352,47 +1352,47 @@
  * @example
  *
  */
-jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
-  var expectedArgs = jasmine.util.argsToArray(arguments);
-  if (!jasmine.isSpy(this.actual)) {
-    throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
-  }
-  this.message = function() {
-    if (this.actual.callCount === 0) {
-      // todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw]
-      return [
-        "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.",
-        "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was."
-      ];
-    } else {
-      return [
-        "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall),
-        "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall)
-      ];
-    }
-  };
-
-  return this.env.contains_(this.actual.argsForCall, expectedArgs);
+jasmine.Matchers.prototype.toHaveBeenCalledWith = function () {
+    var expectedArgs = jasmine.util.argsToArray(arguments);
+    if (!jasmine.isSpy(this.actual)) {
+        throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+    }
+    this.message = function () {
+        if (this.actual.callCount === 0) {
+            // todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw]
+            return [
+                "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.",
+                "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was."
+            ];
+        } else {
+            return [
+                "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall),
+                "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall)
+            ];
+        }
+    };
+
+    return this.env.contains_(this.actual.argsForCall, expectedArgs);
 };
 
 /** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
 jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;
 
 /** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
-jasmine.Matchers.prototype.wasNotCalledWith = function() {
-  var expectedArgs = jasmine.util.argsToArray(arguments);
-  if (!jasmine.isSpy(this.actual)) {
-    throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
-  }
-
-  this.message = function() {
-    return [
-      "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
-      "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
-    ];
-  };
-
-  return !this.env.contains_(this.actual.argsForCall, expectedArgs);
+jasmine.Matchers.prototype.wasNotCalledWith = function () {
+    var expectedArgs = jasmine.util.argsToArray(arguments);
+    if (!jasmine.isSpy(this.actual)) {
+        throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+    }
+
+    this.message = function () {
+        return [
+            "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
+            "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
+        ];
+    };
+
+    return !this.env.contains_(this.actual.argsForCall, expectedArgs);
 };
 
 /**
@@ -1400,8 +1400,8 @@
  *
  * @param {Object} expected
  */
-jasmine.Matchers.prototype.toContain = function(expected) {
-  return this.env.contains_(this.actual, expected);
+jasmine.Matchers.prototype.toContain = function (expected) {
+    return this.env.contains_(this.actual, expected);
 };
 
 /**
@@ -1410,16 +1410,16 @@
  * @param {Object} expected
  * @deprecated as of 1.0. Use not.toContain() instead.
  */
-jasmine.Matchers.prototype.toNotContain = function(expected) {
-  return !this.env.contains_(this.actual, expected);
-};
-
-jasmine.Matchers.prototype.toBeLessThan = function(expected) {
-  return this.actual < expected;
-};
-
-jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
-  return this.actual > expected;
+jasmine.Matchers.prototype.toNotContain = function (expected) {
+    return !this.env.contains_(this.actual, expected);
+};
+
+jasmine.Matchers.prototype.toBeLessThan = function (expected) {
+    return this.actual < expected;
+};
+
+jasmine.Matchers.prototype.toBeGreaterThan = function (expected) {
+    return this.actual > expected;
 };
 
 /**
@@ -1429,14 +1429,14 @@
  * @param {Number} expected
  * @param {Number} precision
  */
-jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) {
-  if (!(precision === 0)) {
-    precision = precision || 2;
-  }
-  var multiplier = Math.pow(10, precision);
-  var actual = Math.round(this.actual * multiplier);
-  expected = Math.round(expected * multiplier);
-  return expected == actual;
+jasmine.Matchers.prototype.toBeCloseTo = function (expected, precision) {
+    if (!(precision === 0)) {
+        precision = precision || 2;
+    }
+    var multiplier = Math.pow(10, precision);
+    var actual = Math.round(this.actual * multiplier);
+    expected = Math.round(expected * multiplier);
+    return expected == actual;
 };
 
 /**
@@ -1444,335 +1444,335 @@
  *
  * @param {String} expected
  */
-jasmine.Matchers.prototype.toThrow = function(expected) {
-  var result = false;
-  var exception;
-  if (typeof this.actual != 'function') {
-    throw new Error('Actual is not a function');
-  }
-  try {
-    this.actual();
-  } catch (e) {
-    exception = e;
-  }
-  if (exception) {
-    result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
-  }
-
-  var not = this.isNot ? "not " : "";
-
-  this.message = function() {
-    if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
-      return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
-    } else {
-      return "Expected function to throw an exception.";
-    }
-  };
-
-  return result;
-};
-
-jasmine.Matchers.Any = function(expectedClass) {
-  this.expectedClass = expectedClass;
-};
-
-jasmine.Matchers.Any.prototype.jasmineMatches = function(other) {
-  if (this.expectedClass == String) {
-    return typeof other == 'string' || other instanceof String;
-  }
-
-  if (this.expectedClass == Number) {
-    return typeof other == 'number' || other instanceof Number;
-  }
-
-  if (this.expectedClass == Function) {
-    return typeof other == 'function' || other instanceof Function;
-  }
-
-  if (this.expectedClass == Object) {
-    return typeof other == 'object';
-  }
-
-  return other instanceof this.expectedClass;
-};
-
-jasmine.Matchers.Any.prototype.jasmineToString = function() {
-  return '<jasmine.any(' + this.expectedClass + ')>';
+jasmine.Matchers.prototype.toThrow = function (expected) {
+    var result = false;
+    var exception;
+    if (typeof this.actual != 'function') {
+        throw new Error('Actual is not a function');
+    }
+    try {
+        this.actual();
+    } catch (e) {
+        exception = e;
+    }
+    if (exception) {
+        result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
+    }
+
+    var not = this.isNot ? "not " : "";
+
+    this.message = function () {
+        if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
+            return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
+        } else {
+            return "Expected function to throw an exception.";
+        }
+    };
+
+    return result;
+};
+
+jasmine.Matchers.Any = function (expectedClass) {
+    this.expectedClass = expectedClass;
+};
+
+jasmine.Matchers.Any.prototype.jasmineMatches = function (other) {
+    if (this.expectedClass == String) {
+        return typeof other == 'string' || other instanceof String;
+    }
+
+    if (this.expectedClass == Number) {
+        return typeof other == 'number' || other instanceof Number;
+    }
+
+    if (this.expectedClass == Function) {
+        return typeof other == 'function' || other instanceof Function;
+    }
+
+    if (this.expectedClass == Object) {
+        return typeof other == 'object';
+    }
+
+    return other instanceof this.expectedClass;
+};
+
+jasmine.Matchers.Any.prototype.jasmineToString = function () {
+    return '<jasmine.any(' + this.expectedClass + ')>';
 };
 
 jasmine.Matchers.ObjectContaining = function (sample) {
-  this.sample = sample;
-};
-
-jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
-  mismatchKeys = mismatchKeys || [];
-  mismatchValues = mismatchValues || [];
-
-  var env = jasmine.getEnv();
-
-  var hasKey = function(obj, keyName) {
-    return obj != null && obj[keyName] !== jasmine.undefined;
-  };
-
-  for (var property in this.sample) {
-    if (!hasKey(other, property) && hasKey(this.sample, property)) {
-      mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
-    }
-    else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
-      mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
-    }
-  }
-
-  return (mismatchKeys.length === 0 && mismatchValues.length === 0);
+    this.sample = sample;
+};
+
+jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function (other, mismatchKeys, mismatchValues) {
+    mismatchKeys = mismatchKeys || [];
+    mismatchValues = mismatchValues || [];
+
+    var env = jasmine.getEnv();
+
+    var hasKey = function (obj, keyName) {
+        return obj != null && obj[keyName] !== jasmine.undefined;
+    };
+
+    for (var property in this.sample) {
+        if (!hasKey(other, property) && hasKey(this.sample, property)) {
+            mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
+        }
+        else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
+            mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
+        }
+    }
+
+    return (mismatchKeys.length === 0 && mismatchValues.length === 0);
 };
 
 jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () {
-  return "<jasmine.objectContaining(" + jasmine.pp(this.sample) + ")>";
+    return "<jasmine.objectContaining(" + jasmine.pp(this.sample) + ")>";
 };
 // Mock setTimeout, clearTimeout
 // Contributed by Pivotal Computer Systems, www.pivotalsf.com
 
-jasmine.FakeTimer = function() {
-  this.reset();
-
-  var self = this;
-  self.setTimeout = function(funcToCall, millis) {
-    self.timeoutsMade++;
-    self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
-    return self.timeoutsMade;
-  };
-
-  self.setInterval = function(funcToCall, millis) {
-    self.timeoutsMade++;
-    self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
-    return self.timeoutsMade;
-  };
-
-  self.clearTimeout = function(timeoutKey) {
-    self.scheduledFunctions[timeoutKey] = jasmine.undefined;
-  };
-
-  self.clearInterval = function(timeoutKey) {
-    self.scheduledFunctions[timeoutKey] = jasmine.undefined;
-  };
-
-};
-
-jasmine.FakeTimer.prototype.reset = function() {
-  this.timeoutsMade = 0;
-  this.scheduledFunctions = {};
-  this.nowMillis = 0;
-};
-
-jasmine.FakeTimer.prototype.tick = function(millis) {
-  var oldMillis = this.nowMillis;
-  var newMillis = oldMillis + millis;
-  this.runFunctionsWithinRange(oldMillis, newMillis);
-  this.nowMillis = newMillis;
-};
-
-jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
-  var scheduledFunc;
-  var funcsToRun = [];
-  for (var timeoutKey in this.scheduledFunctions) {
-    scheduledFunc = this.scheduledFunctions[timeoutKey];
-    if (scheduledFunc != jasmine.undefined &&
-        scheduledFunc.runAtMillis >= oldMillis &&
-        scheduledFunc.runAtMillis <= nowMillis) {
-      funcsToRun.push(scheduledFunc);
-      this.scheduledFunctions[timeoutKey] = jasmine.undefined;
-    }
-  }
-
-  if (funcsToRun.length > 0) {
-    funcsToRun.sort(function(a, b) {
-      return a.runAtMillis - b.runAtMillis;
-    });
-    for (var i = 0; i < funcsToRun.length; ++i) {
-      try {
-        var funcToRun = funcsToRun[i];
-        this.nowMillis = funcToRun.runAtMillis;
-        funcToRun.funcToCall();
-        if (funcToRun.recurring) {
-          this.scheduleFunction(funcToRun.timeoutKey,
-              funcToRun.funcToCall,
-              funcToRun.millis,
-              true);
-        }
-      } catch(e) {
-      }
-    }
-    this.runFunctionsWithinRange(oldMillis, nowMillis);
-  }
-};
-
-jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
-  this.scheduledFunctions[timeoutKey] = {
-    runAtMillis: this.nowMillis + millis,
-    funcToCall: funcToCall,
-    recurring: recurring,
-    timeoutKey: timeoutKey,
-    millis: millis
-  };
+jasmine.FakeTimer = function () {
+    this.reset();
+
+    var self = this;
+    self.setTimeout = function (funcToCall, millis) {
+        self.timeoutsMade++;
+        self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
+        return self.timeoutsMade;
+    };
+
+    self.setInterval = function (funcToCall, millis) {
+        self.timeoutsMade++;
+        self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
+        return self.timeoutsMade;
+    };
+
+    self.clearTimeout = function (timeoutKey) {
+        self.scheduledFunctions[timeoutKey] = jasmine.undefined;
+    };
+
+    self.clearInterval = function (timeoutKey) {
+        self.scheduledFunctions[timeoutKey] = jasmine.undefined;
+    };
+
+};
+
+jasmine.FakeTimer.prototype.reset = function () {
+    this.timeoutsMade = 0;
+    this.scheduledFunctions = {};
+    this.nowMillis = 0;
+};
+
+jasmine.FakeTimer.prototype.tick = function (millis) {
+    var oldMillis = this.nowMillis;
+    var newMillis = oldMillis + millis;
+    this.runFunctionsWithinRange(oldMillis, newMillis);
+    this.nowMillis = newMillis;
+};
+
+jasmine.FakeTimer.prototype.runFunctionsWithinRange = function (oldMillis, nowMillis) {
+    var scheduledFunc;
+    var funcsToRun = [];
+    for (var timeoutKey in this.scheduledFunctions) {
+        scheduledFunc = this.scheduledFunctions[timeoutKey];
+        if (scheduledFunc != jasmine.undefined &&
+            scheduledFunc.runAtMillis >= oldMillis &&
+            scheduledFunc.runAtMillis <= nowMillis) {
+            funcsToRun.push(scheduledFunc);
+            this.scheduledFunctions[timeoutKey] = jasmine.undefined;
+        }
+    }
+
+    if (funcsToRun.length > 0) {
+        funcsToRun.sort(function (a, b) {
+            return a.runAtMillis - b.runAtMillis;
+        });
+        for (var i = 0; i < funcsToRun.length; ++i) {
+            try {
+                var funcToRun = funcsToRun[i];
+                this.nowMillis = funcToRun.runAtMillis;
+                funcToRun.funcToCall();
+                if (funcToRun.recurring) {
+                    this.scheduleFunction(funcToRun.timeoutKey,
+                        funcToRun.funcToCall,
+                        funcToRun.millis,
+                        true);
+                }
+            } catch (e) {
+            }
+        }
+        this.runFunctionsWithinRange(oldMillis, nowMillis);
+    }
+};
+
+jasmine.FakeTimer.prototype.scheduleFunction = function (timeoutKey, funcToCall, millis, recurring) {
+    this.scheduledFunctions[timeoutKey] = {
+        runAtMillis: this.nowMillis + millis,
+        funcToCall: funcToCall,
+        recurring: recurring,
+        timeoutKey: timeoutKey,
+        millis: millis
+    };
 };
 
 /**
  * @namespace
  */
 jasmine.Clock = {
-  defaultFakeTimer: new jasmine.FakeTimer(),
-
-  reset: function() {
-    jasmine.Clock.assertInstalled();
-    jasmine.Clock.defaultFakeTimer.reset();
-  },
-
-  tick: function(millis) {
-    jasmine.Clock.assertInstalled();
-    jasmine.Clock.defaultFakeTimer.tick(millis);
-  },
-
-  runFunctionsWithinRange: function(oldMillis, nowMillis) {
-    jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
-  },
-
-  scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
-    jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
-  },
-
-  useMock: function() {
-    if (!jasmine.Clock.isInstalled()) {
-      var spec = jasmine.getEnv().currentSpec;
-      spec.after(jasmine.Clock.uninstallMock);
-
-      jasmine.Clock.installMock();
-    }
-  },
-
-  installMock: function() {
-    jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
-  },
-
-  uninstallMock: function() {
-    jasmine.Clock.assertInstalled();
-    jasmine.Clock.installed = jasmine.Clock.real;
-  },
-
-  real: {
-    setTimeout: jasmine.getGlobal().setTimeout,
-    clearTimeout: jasmine.getGlobal().clearTimeout,
-    setInterval: jasmine.getGlobal().setInterval,
-    clearInterval: jasmine.getGlobal().clearInterval
-  },
-
-  assertInstalled: function() {
-    if (!jasmine.Clock.isInstalled()) {
-      throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
-    }
-  },
-
-  isInstalled: function() {
-    return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
-  },
-
-  installed: null
+    defaultFakeTimer: new jasmine.FakeTimer(),
+
+    reset: function () {
+        jasmine.Clock.assertInstalled();
+        jasmine.Clock.defaultFakeTimer.reset();
+    },
+
+    tick: function (millis) {
+        jasmine.Clock.assertInstalled();
+        jasmine.Clock.defaultFakeTimer.tick(millis);
+    },
+
+    runFunctionsWithinRange: function (oldMillis, nowMillis) {
+        jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
+    },
+
+    scheduleFunction: function (timeoutKey, funcToCall, millis, recurring) {
+        jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
+    },
+
+    useMock: function () {
+        if (!jasmine.Clock.isInstalled()) {
+            var spec = jasmine.getEnv().currentSpec;
+            spec.after(jasmine.Clock.uninstallMock);
+
+            jasmine.Clock.installMock();
+        }
+    },
+
+    installMock: function () {
+        jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
+    },
+
+    uninstallMock: function () {
+        jasmine.Clock.assertInstalled();
+        jasmine.Clock.installed = jasmine.Clock.real;
+    },
+
+    real: {
+        setTimeout: jasmine.getGlobal().setTimeout,
+        clearTimeout: jasmine.getGlobal().clearTimeout,
+        setInterval: jasmine.getGlobal().setInterval,
+        clearInterval: jasmine.getGlobal().clearInterval
+    },
+
+    assertInstalled: function () {
+        if (!jasmine.Clock.isInstalled()) {
+            throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
+        }
+    },
+
+    isInstalled: function () {
+        return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
+    },
+
+    installed: null
 };
 jasmine.Clock.installed = jasmine.Clock.real;
 
 //else for IE support
-jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
-  if (jasmine.Clock.installed.setTimeout.apply) {
-    return jasmine.Clock.installed.setTimeout.apply(this, arguments);
-  } else {
-    return jasmine.Clock.installed.setTimeout(funcToCall, millis);
-  }
-};
-
-jasmine.getGlobal().setInterval = function(funcToCall, millis) {
-  if (jasmine.Clock.installed.setInterval.apply) {
-    return jasmine.Clock.installed.setInterval.apply(this, arguments);
-  } else {
-    return jasmine.Clock.installed.setInterval(funcToCall, millis);
-  }
-};
-
-jasmine.getGlobal().clearTimeout = function(timeoutKey) {
-  if (jasmine.Clock.installed.clearTimeout.apply) {
-    return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
-  } else {
-    return jasmine.Clock.installed.clearTimeout(timeoutKey);
-  }
-};
-
-jasmine.getGlobal().clearInterval = function(timeoutKey) {
-  if (jasmine.Clock.installed.clearTimeout.apply) {
-    return jasmine.Clock.installed.clearInterval.apply(this, arguments);
-  } else {
-    return jasmine.Clock.installed.clearInterval(timeoutKey);
-  }
+jasmine.getGlobal().setTimeout = function (funcToCall, millis) {
+    if (jasmine.Clock.installed.setTimeout.apply) {
+        return jasmine.Clock.installed.setTimeout.apply(this, arguments);
+    } else {
+        return jasmine.Clock.installed.setTimeout(funcToCall, millis);
+    }
+};
+
+jasmine.getGlobal().setInterval = function (funcToCall, millis) {
+    if (jasmine.Clock.installed.setInterval.apply) {
+        return jasmine.Clock.installed.setInterval.apply(this, arguments);
+    } else {
+        return jasmine.Clock.installed.setInterval(funcToCall, millis);
+    }
+};
+
+jasmine.getGlobal().clearTimeout = function (timeoutKey) {
+    if (jasmine.Clock.installed.clearTimeout.apply) {
+        return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
+    } else {
+        return jasmine.Clock.installed.clearTimeout(timeoutKey);
+    }
+};
+
+jasmine.getGlobal().clearInterval = function (timeoutKey) {
+    if (jasmine.Clock.installed.clearTimeout.apply) {
+        return jasmine.Clock.installed.clearInterval.apply(this, arguments);
+    } else {
+        return jasmine.Clock.installed.clearInterval(timeoutKey);
+    }
 };
 
 /**
  * @constructor
  */
-jasmine.MultiReporter = function() {
-  this.subReporters_ = [];
+jasmine.MultiReporter = function () {
+    this.subReporters_ = [];
 };
 jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter);
 
-jasmine.MultiReporter.prototype.addReporter = function(reporter) {
-  this.subReporters_.push(reporter);
-};
-
-(function() {
-  var functionNames = [
-    "reportRunnerStarting",
-    "reportRunnerResults",
-    "reportSuiteResults",
-    "reportSpecStarting",
-    "reportSpecResults",
-    "log"
-  ];
-  for (var i = 0; i < functionNames.length; i++) {
-    var functionName = functionNames[i];
-    jasmine.MultiReporter.prototype[functionName] = (function(functionName) {
-      return function() {
-        for (var j = 0; j < this.subReporters_.length; j++) {
-          var subReporter = this.subReporters_[j];
-          if (subReporter[functionName]) {
-            subReporter[functionName].apply(subReporter, arguments);
-          }
-        }
-      };
-    })(functionName);
-  }
+jasmine.MultiReporter.prototype.addReporter = function (reporter) {
+    this.subReporters_.push(reporter);
+};
+
+(function () {
+    var functionNames = [
+        "reportRunnerStarting",
+        "reportRunnerResults",
+        "reportSuiteResults",
+        "reportSpecStarting",
+        "reportSpecResults",
+        "log"
+    ];
+    for (var i = 0; i < functionNames.length; i++) {
+        var functionName = functionNames[i];
+        jasmine.MultiReporter.prototype[functionName] = (function (functionName) {
+            return function () {
+                for (var j = 0; j < this.subReporters_.length; j++) {
+                    var subReporter = this.subReporters_[j];
+                    if (subReporter[functionName]) {
+                        subReporter[functionName].apply(subReporter, arguments);
+                    }
+                }
+            };
+        })(functionName);
+    }
 })();
 /**
  * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults
  *
  * @constructor
  */
-jasmine.NestedResults = function() {
-  /**
-   * The total count of results
-   */
-  this.totalCount = 0;
-  /**
-   * Number of passed results
-   */
-  this.passedCount = 0;
-  /**
-   * Number of failed results
-   */
-  this.failedCount = 0;
-  /**
-   * Was this suite/spec skipped?
-   */
-  this.skipped = false;
-  /**
-   * @ignore
-   */
-  this.items_ = [];
+jasmine.NestedResults = function () {
+    /**
+     * The total count of results
+     */
+    this.totalCount = 0;
+    /**
+     * Number of passed results
+     */
+    this.passedCount = 0;
+    /**
+     * Number of failed results
+     */
+    this.failedCount = 0;
+    /**
+     * Was this suite/spec skipped?
+     */
+    this.skipped = false;
+    /**
+     * @ignore
+     */
+    this.items_ = [];
 };
 
 /**
@@ -1780,58 +1780,58 @@
  *
  * @param result
  */
-jasmine.NestedResults.prototype.rollupCounts = function(result) {
-  this.totalCount += result.totalCount;
-  this.passedCount += result.passedCount;
-  this.failedCount += result.failedCount;
+jasmine.NestedResults.prototype.rollupCounts = function (result) {
+    this.totalCount += result.totalCount;
+    this.passedCount += result.passedCount;
+    this.failedCount += result.failedCount;
 };
 
 /**
  * Adds a log message.
  * @param values Array of message parts which will be concatenated later.
  */
-jasmine.NestedResults.prototype.log = function(values) {
-  this.items_.push(new jasmine.MessageResult(values));
+jasmine.NestedResults.prototype.log = function (values) {
+    this.items_.push(new jasmine.MessageResult(values));
 };
 
 /**
  * Getter for the results: message & results.
  */
-jasmine.NestedResults.prototype.getItems = function() {
-  return this.items_;
+jasmine.NestedResults.prototype.getItems = function () {
+    return this.items_;
 };
 
 /**
  * Adds a result, tracking counts (total, passed, & failed)
  * @param {jasmine.ExpectationResult|jasmine.NestedResults} result
  */
-jasmine.NestedResults.prototype.addResult = function(result) {
-  if (result.type != 'log') {
-    if (result.items_) {
-      this.rollupCounts(result);
-    } else {
-      this.totalCount++;
-      if (result.passed()) {
-        this.passedCount++;
-      } else {
-        this.failedCount++;
-      }
-    }
-  }
-  this.items_.push(result);
+jasmine.NestedResults.prototype.addResult = function (result) {
+    if (result.type != 'log') {
+        if (result.items_) {
+            this.rollupCounts(result);
+        } else {
+            this.totalCount++;
+            if (result.passed()) {
+                this.passedCount++;
+            } else {
+                this.failedCount++;
+            }
+        }
+    }
+    this.items_.push(result);
 };
 
 /**
  * @returns {Boolean} True if <b>everything</b> below passed
  */
-jasmine.NestedResults.prototype.passed = function() {
-  return this.passedCount === this.totalCount;
+jasmine.NestedResults.prototype.passed = function () {
+    return this.passedCount === this.totalCount;
 };
 /**
  * Base class for pretty printing for expectation results.
  */
-jasmine.PrettyPrinter = function() {
-  this.ppNestLevel_ = 0;
+jasmine.PrettyPrinter = function () {
+    this.ppNestLevel_ = 0;
 };
 
 /**
@@ -1839,57 +1839,57 @@
  *
  * @param value
  */
-jasmine.PrettyPrinter.prototype.format = function(value) {
-  if (this.ppNestLevel_ > 40) {
-    throw new Error('jasmine.PrettyPrinter: format() nested too deeply!');
-  }
-
-  this.ppNestLevel_++;
-  try {
-    if (value === jasmine.undefined) {
-      this.emitScalar('undefined');
-    } else if (value === null) {
-      this.emitScalar('null');
-    } else if (value === jasmine.getGlobal()) {
-      this.emitScalar('<global>');
-    } else if (value.jasmineToString) {
-      this.emitScalar(value.jasmineToString());
-    } else if (typeof value === 'string') {
-      this.emitString(value);
-    } else if (jasmine.isSpy(value)) {
-      this.emitScalar("spy on " + value.identity);
-    } else if (value instanceof RegExp) {
-      this.emitScalar(value.toString());
-    } else if (typeof value === 'function') {
-      this.emitScalar('Function');
-    } else if (typeof value.nodeType === 'number') {
-      this.emitScalar('HTMLNode');
-    } else if (value instanceof Date) {
-      this.emitScalar('Date(' + value + ')');
-    } else if (value.__Jasmine_been_here_before__) {
-      this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>');
-    } else if (jasmine.isArray_(value) || typeof value == 'object') {
-      value.__Jasmine_been_here_before__ = true;
-      if (jasmine.isArray_(value)) {
-        this.emitArray(value);
-      } else {
-        this.emitObject(value);
-      }
-      delete value.__Jasmine_been_here_before__;
-    } else {
-      this.emitScalar(value.toString());
-    }
-  } finally {
-    this.ppNestLevel_--;
-  }
-};
-
-jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
-  for (var property in obj) {
-    if (property == '__Jasmine_been_here_before__') continue;
-    fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined && 
-                                         obj.__lookupGetter__(property) !== null) : false);
-  }
+jasmine.PrettyPrinter.prototype.format = function (value) {
+    if (this.ppNestLevel_ > 40) {
+        throw new Error('jasmine.PrettyPrinter: format() nested too deeply!');
+    }
+
+    this.ppNestLevel_++;
+    try {
+        if (value === jasmine.undefined) {
+            this.emitScalar('undefined');
+        } else if (value === null) {
+            this.emitScalar('null');
+        } else if (value === jasmine.getGlobal()) {
+            this.emitScalar('<global>');
+        } else if (value.jasmineToString) {
+            this.emitScalar(value.jasmineToString());
+        } else if (typeof value === 'string') {
+            this.emitString(value);
+        } else if (jasmine.isSpy(value)) {
+            this.emitScalar("spy on " + value.identity);
+        } else if (value instanceof RegExp) {
+            this.emitScalar(value.toString());
+        } else if (typeof value === 'function') {
+            this.emitScalar('Function');
+        } else if (typeof value.nodeType === 'number') {
+            this.emitScalar('HTMLNode');
+        } else if (value instanceof Date) {
+            this.emitScalar('Date(' + value + ')');
+        } else if (value.__Jasmine_been_here_before__) {
+            this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>');
+        } else if (jasmine.isArray_(value) || typeof value == 'object') {
+            value.__Jasmine_been_here_before__ = true;
+            if (jasmine.isArray_(value)) {
+                this.emitArray(value);
+            } else {
+                this.emitObject(value);
+            }
+            delete value.__Jasmine_been_here_before__;
+        } else {
+            this.emitScalar(value.toString());
+        }
+    } finally {
+        this.ppNestLevel_--;
+    }
+};
+
+jasmine.PrettyPrinter.prototype.iterateObject = function (obj, fn) {
+    for (var property in obj) {
+        if (property == '__Jasmine_been_here_before__') continue;
+        fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined &&
+            obj.__lookupGetter__(property) !== null) : false);
+    }
 };
 
 jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;
@@ -1897,155 +1897,155 @@
 jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;
 jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;
 
-jasmine.StringPrettyPrinter = function() {
-  jasmine.PrettyPrinter.call(this);
-
-  this.string = '';
+jasmine.StringPrettyPrinter = function () {
+    jasmine.PrettyPrinter.call(this);
+
+    this.string = '';
 };
 jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
 
-jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
-  this.append(value);
-};
-
-jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
-  this.append("'" + value + "'");
-};
-
-jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
-  this.append('[ ');
-  for (var i = 0; i < array.length; i++) {
-    if (i > 0) {
-      this.append(', ');
-    }
-    this.format(array[i]);
-  }
-  this.append(' ]');
-};
-
-jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
-  var self = this;
-  this.append('{ ');
-  var first = true;
-
-  this.iterateObject(obj, function(property, isGetter) {
-    if (first) {
-      first = false;
-    } else {
-      self.append(', ');
-    }
-
-    self.append(property);
-    self.append(' : ');
-    if (isGetter) {
-      self.append('<getter>');
-    } else {
-      self.format(obj[property]);
-    }
-  });
-
-  this.append(' }');
-};
-
-jasmine.StringPrettyPrinter.prototype.append = function(value) {
-  this.string += value;
-};
-jasmine.Queue = function(env) {
-  this.env = env;
-  this.blocks = [];
-  this.running = false;
-  this.index = 0;
-  this.offset = 0;
-  this.abort = false;
-};
-
-jasmine.Queue.prototype.addBefore = function(block) {
-  this.blocks.unshift(block);
-};
-
-jasmine.Queue.prototype.add = function(block) {
-  this.blocks.push(block);
-};
-
-jasmine.Queue.prototype.insertNext = function(block) {
-  this.blocks.splice((this.index + this.offset + 1), 0, block);
-  this.offset++;
-};
-
-jasmine.Queue.prototype.start = function(onComplete) {
-  this.running = true;
-  this.onComplete = onComplete;
-  this.next_();
-};
-
-jasmine.Queue.prototype.isRunning = function() {
-  return this.running;
+jasmine.StringPrettyPrinter.prototype.emitScalar = function (value) {
+    this.append(value);
+};
+
+jasmine.StringPrettyPrinter.prototype.emitString = function (value) {
+    this.append("'" + value + "'");
+};
+
+jasmine.StringPrettyPrinter.prototype.emitArray = function (array) {
+    this.append('[ ');
+    for (var i = 0; i < array.length; i++) {
+        if (i > 0) {
+            this.append(', ');
+        }
+        this.format(array[i]);
+    }
+    this.append(' ]');
+};
+
+jasmine.StringPrettyPrinter.prototype.emitObject = function (obj) {
+    var self = this;
+    this.append('{ ');
+    var first = true;
+
+    this.iterateObject(obj, function (property, isGetter) {
+        if (first) {
+            first = false;
+        } else {
+            self.append(', ');
+        }
+
+        self.append(property);
+        self.append(' : ');
+        if (isGetter) {
+            self.append('<getter>');
+        } else {
+            self.format(obj[property]);
+        }
+    });
+
+    this.append(' }');
+};
+
+jasmine.StringPrettyPrinter.prototype.append = function (value) {
+    this.string += value;
+};
+jasmine.Queue = function (env) {
+    this.env = env;
+    this.blocks = [];
+    this.running = false;
+    this.index = 0;
+    this.offset = 0;
+    this.abort = false;
+};
+
+jasmine.Queue.prototype.addBefore = function (block) {
+    this.blocks.unshift(block);
+};
+
+jasmine.Queue.prototype.add = function (block) {
+    this.blocks.push(block);
+};
+
+jasmine.Queue.prototype.insertNext = function (block) {
+    this.blocks.splice((this.index + this.offset + 1), 0, block);
+    this.offset++;
+};
+
+jasmine.Queue.prototype.start = function (onComplete) {
+    this.running = true;
+    this.onComplete = onComplete;
+    this.next_();
+};
+
+jasmine.Queue.prototype.isRunning = function () {
+    return this.running;
 };
 
 jasmine.Queue.LOOP_DONT_RECURSE = true;
 
-jasmine.Queue.prototype.next_ = function() {
-  var self = this;
-  var goAgain = true;
-
-  while (goAgain) {
-    goAgain = false;
-    
-    if (self.index < self.blocks.length && !this.abort) {
-      var calledSynchronously = true;
-      var completedSynchronously = false;
-
-      var onComplete = function () {
-        if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
-          completedSynchronously = true;
-          return;
-        }
-
-        if (self.blocks[self.index].abort) {
-          self.abort = true;
-        }
-
-        self.offset = 0;
-        self.index++;
-
-        var now = new Date().getTime();
-        if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {
-          self.env.lastUpdate = now;
-          self.env.setTimeout(function() {
-            self.next_();
-          }, 0);
+jasmine.Queue.prototype.next_ = function () {
+    var self = this;
+    var goAgain = true;
+
+    while (goAgain) {
+        goAgain = false;
+
+        if (self.index < self.blocks.length && !this.abort) {
+            var calledSynchronously = true;
+            var completedSynchronously = false;
+
+            var onComplete = function () {
+                if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
+                    completedSynchronously = true;
+                    return;
+                }
+
+                if (self.blocks[self.index].abort) {
+                    self.abort = true;
+                }
+
+                self.offset = 0;
+                self.index++;
+
+                var now = new Date().getTime();
+                if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {
+                    self.env.lastUpdate = now;
+                    self.env.setTimeout(function () {
+                        self.next_();
+                    }, 0);
+                } else {
+                    if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {
+                        goAgain = true;
+                    } else {
+                        self.next_();
+                    }
+                }
+            };
+            self.blocks[self.index].execute(onComplete);
+
+            calledSynchronously = false;
+            if (completedSynchronously) {
+                onComplete();
+            }
+
         } else {
-          if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {
-            goAgain = true;
-          } else {
-            self.next_();
-          }
-        }
-      };
-      self.blocks[self.index].execute(onComplete);
-
-      calledSynchronously = false;
-      if (completedSynchronously) {
-        onComplete();
-      }
-      
-    } else {
-      self.running = false;
-      if (self.onComplete) {
-        self.onComplete();
-      }
-    }
-  }
-};
-
-jasmine.Queue.prototype.results = function() {
-  var results = new jasmine.NestedResults();
-  for (var i = 0; i < this.blocks.length; i++) {
-    if (this.blocks[i].results) {
-      results.addResult(this.blocks[i].results());
-    }
-  }
-  return results;
+            self.running = false;
+            if (self.onComplete) {
+                self.onComplete();
+            }
+        }
+    }
+};
+
+jasmine.Queue.prototype.results = function () {
+    var results = new jasmine.NestedResults();
+    for (var i = 0; i < this.blocks.length; i++) {
+        if (this.blocks[i].results) {
+            results.addResult(this.blocks[i].results());
+        }
+    }
+    return results;
 };
 
 
@@ -2055,76 +2055,76 @@
  * @constructor
  * @param {jasmine.Env} env
  */
-jasmine.Runner = function(env) {
-  var self = this;
-  self.env = env;
-  self.queue = new jasmine.Queue(env);
-  self.before_ = [];
-  self.after_ = [];
-  self.suites_ = [];
-};
-
-jasmine.Runner.prototype.execute = function() {
-  var self = this;
-  if (self.env.reporter.reportRunnerStarting) {
-    self.env.reporter.reportRunnerStarting(this);
-  }
-  self.queue.start(function () {
-    self.finishCallback();
-  });
-};
-
-jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
-  beforeEachFunction.typeName = 'beforeEach';
-  this.before_.splice(0,0,beforeEachFunction);
-};
-
-jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
-  afterEachFunction.typeName = 'afterEach';
-  this.after_.splice(0,0,afterEachFunction);
-};
-
-
-jasmine.Runner.prototype.finishCallback = function() {
-  this.env.reporter.reportRunnerResults(this);
-};
-
-jasmine.Runner.prototype.addSuite = function(suite) {
-  this.suites_.push(suite);
-};
-
-jasmine.Runner.prototype.add = function(block) {
-  if (block instanceof jasmine.Suite) {
-    this.addSuite(block);
-  }
-  this.queue.add(block);
+jasmine.Runner = function (env) {
+    var self = this;
+    self.env = env;
+    self.queue = new jasmine.Queue(env);
+    self.before_ = [];
+    self.after_ = [];
+    self.suites_ = [];
+};
+
+jasmine.Runner.prototype.execute = function () {
+    var self = this;
+    if (self.env.reporter.reportRunnerStarting) {
+        self.env.reporter.reportRunnerStarting(this);
+    }
+    self.queue.start(function () {
+        self.finishCallback();
+    });
+};
+
+jasmine.Runner.prototype.beforeEach = function (beforeEachFunction) {
+    beforeEachFunction.typeName = 'beforeEach';
+    this.before_.splice(0, 0, beforeEachFunction);
+};
+
+jasmine.Runner.prototype.afterEach = function (afterEachFunction) {
+    afterEachFunction.typeName = 'afterEach';
+    this.after_.splice(0, 0, afterEachFunction);
+};
+
+
+jasmine.Runner.prototype.finishCallback = function () {
+    this.env.reporter.reportRunnerResults(this);
+};
+
+jasmine.Runner.prototype.addSuite = function (suite) {
+    this.suites_.push(suite);
+};
+
+jasmine.Runner.prototype.add = function (block) {
+    if (block instanceof jasmine.Suite) {
+        this.addSuite(block);
+    }
+    this.queue.add(block);
 };
 
 jasmine.Runner.prototype.specs = function () {
-  var suites = this.suites();
-  var specs = [];
-  for (var i = 0; i < suites.length; i++) {
-    specs = specs.concat(suites[i].specs());
-  }
-  return specs;
-};
-
-jasmine.Runner.prototype.suites = function() {
-  return this.suites_;
-};
-
-jasmine.Runner.prototype.topLevelSuites = function() {
-  var topLevelSuites = [];
-  for (var i = 0; i < this.suites_.length; i++) {
-    if (!this.suites_[i].parentSuite) {
-      topLevelSuites.push(this.suites_[i]);
-    }
-  }
-  return topLevelSuites;
-};
-
-jasmine.Runner.prototype.results = function() {
-  return this.queue.results();
+    var suites = this.suites();
+    var specs = [];
+    for (var i = 0; i < suites.length; i++) {
+        specs = specs.concat(suites[i].specs());
+    }
+    return specs;
+};
+
+jasmine.Runner.prototype.suites = function () {
+    return this.suites_;
+};
+
+jasmine.Runner.prototype.topLevelSuites = function () {
+    var topLevelSuites = [];
+    for (var i = 0; i < this.suites_.length; i++) {
+        if (!this.suites_[i].parentSuite) {
+            topLevelSuites.push(this.suites_[i]);
+        }
+    }
+    return topLevelSuites;
+};
+
+jasmine.Runner.prototype.results = function () {
+    return this.queue.results();
 };
 /**
  * Internal representation of a Jasmine specification, or test.
@@ -2134,35 +2134,35 @@
  * @param {jasmine.Suite} suite
  * @param {String} description
  */
-jasmine.Spec = function(env, suite, description) {
-  if (!env) {
-    throw new Error('jasmine.Env() required');
-  }
-  if (!suite) {
-    throw new Error('jasmine.Suite() required');
-  }
-  var spec = this;
-  spec.id = env.nextSpecId ? env.nextSpecId() : null;
-  spec.env = env;
-  spec.suite = suite;
-  spec.description = description;
-  spec.queue = new jasmine.Queue(env);
-
-  spec.afterCallbacks = [];
-  spec.spies_ = [];
-
-  spec.results_ = new jasmine.NestedResults();
-  spec.results_.description = description;
-  spec.matchersClass = null;
-};
-
-jasmine.Spec.prototype.getFullName = function() {
-  return this.suite.getFullName() + ' ' + this.description + '.';
-};
-
-
-jasmine.Spec.prototype.results = function() {
-  return this.results_;
+jasmine.Spec = function (env, suite, description) {
+    if (!env) {
+        throw new Error('jasmine.Env() required');
+    }
+    if (!suite) {
+        throw new Error('jasmine.Suite() required');
+    }
+    var spec = this;
+    spec.id = env.nextSpecId ? env.nextSpecId() : null;
+    spec.env = env;
+    spec.suite = suite;
+    spec.description = description;
+    spec.queue = new jasmine.Queue(env);
+
+    spec.afterCallbacks = [];
+    spec.spies_ = [];
+
+    spec.results_ = new jasmine.NestedResults();
+    spec.results_.description = description;
+    spec.matchersClass = null;
+};
+
+jasmine.Spec.prototype.getFullName = function () {
+    return this.suite.getFullName() + ' ' + this.description + '.';
+};
+
+
+jasmine.Spec.prototype.results = function () {
+    return this.results_;
 };
 
 /**
@@ -2170,35 +2170,35 @@
  *
  * Be careful not to leave calls to <code>jasmine.log</code> in production code.
  */
-jasmine.Spec.prototype.log = function() {
-  return this.results_.log(arguments);
+jasmine.Spec.prototype.log = function () {
+    return this.results_.log(arguments);
 };
 
 jasmine.Spec.prototype.runs = function (func) {
-  var block = new jasmine.Block(this.env, func, this);
-  this.addToQueue(block);
-  return this;
+    var block = new jasmine.Block(this.env, func, this);
+    this.addToQueue(block);
+    return this;
 };
 
 jasmine.Spec.prototype.addToQueue = function (block) {
-  if (this.queue.isRunning()) {
-    this.queue.insertNext(block);
-  } else {
-    this.queue.add(block);
-  }
+    if (this.queue.isRunning()) {
+        this.queue.insertNext(block);
+    } else {
+        this.queue.add(block);
+    }
 };
 
 /**
  * @param {jasmine.ExpectationResult} result
  */
-jasmine.Spec.prototype.addMatcherResult = function(result) {
-  this.results_.addResult(result);
-};
-
-jasmine.Spec.prototype.expect = function(actual) {
-  var positive = new (this.getMatchersClass_())(this.env, actual, this);
-  positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
-  return positive;
+jasmine.Spec.prototype.addMatcherResult = function (result) {
+    this.results_.addResult(result);
+};
+
+jasmine.Spec.prototype.expect = function (actual) {
+    var positive = new (this.getMatchersClass_())(this.env, actual, this);
+    positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
+    return positive;
 };
 
 /**
@@ -2207,10 +2207,10 @@
  * @deprecated Use waitsFor() instead
  * @param {Number} timeout milliseconds to wait
  */
-jasmine.Spec.prototype.waits = function(timeout) {
-  var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
-  this.addToQueue(waitsFunc);
-  return this;
+jasmine.Spec.prototype.waits = function (timeout) {
+    var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
+    this.addToQueue(waitsFunc);
+    return this;
 };
 
 /**
@@ -2220,153 +2220,153 @@
  * @param {String} optional_timeoutMessage
  * @param {Number} optional_timeout
  */
-jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
-  var latchFunction_ = null;
-  var optional_timeoutMessage_ = null;
-  var optional_timeout_ = null;
-
-  for (var i = 0; i < arguments.length; i++) {
-    var arg = arguments[i];
-    switch (typeof arg) {
-      case 'function':
-        latchFunction_ = arg;
-        break;
-      case 'string':
-        optional_timeoutMessage_ = arg;
-        break;
-      case 'number':
-        optional_timeout_ = arg;
-        break;
-    }
-  }
-
-  var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
-  this.addToQueue(waitsForFunc);
-  return this;
+jasmine.Spec.prototype.waitsFor = function (latchFunction, optional_timeoutMessage, optional_timeout) {
+    var latchFunction_ = null;
+    var optional_timeoutMessage_ = null;
+    var optional_timeout_ = null;
+
+    for (var i = 0; i < arguments.length; i++) {
+        var arg = arguments[i];
+        switch (typeof arg) {
+            case 'function':
+                latchFunction_ = arg;
+                break;
+            case 'string':
+                optional_timeoutMessage_ = arg;
+                break;
+            case 'number':
+                optional_timeout_ = arg;
+                break;
+        }
+    }
+
+    var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
+    this.addToQueue(waitsForFunc);
+    return this;
 };
 
 jasmine.Spec.prototype.fail = function (e) {
-  var expectationResult = new jasmine.ExpectationResult({
-    passed: false,
-    message: e ? jasmine.util.formatException(e) : 'Exception',
-    trace: { stack: e.stack }
-  });
-  this.results_.addResult(expectationResult);
-};
-
-jasmine.Spec.prototype.getMatchersClass_ = function() {
-  return this.matchersClass || this.env.matchersClass;
-};
-
-jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
-  var parent = this.getMatchersClass_();
-  var newMatchersClass = function() {
-    parent.apply(this, arguments);
-  };
-  jasmine.util.inherit(newMatchersClass, parent);
-  jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
-  this.matchersClass = newMatchersClass;
-};
-
-jasmine.Spec.prototype.finishCallback = function() {
-  this.env.reporter.reportSpecResults(this);
-};
-
-jasmine.Spec.prototype.finish = function(onComplete) {
-  this.removeAllSpies();
-  this.finishCallback();
-  if (onComplete) {
-    onComplete();
-  }
-};
-
-jasmine.Spec.prototype.after = function(doAfter) {
-  if (this.queue.isRunning()) {
-    this.queue.add(new jasmine.Block(this.env, doAfter, this));
-  } else {
-    this.afterCallbacks.unshift(doAfter);
-  }
-};
-
-jasmine.Spec.prototype.execute = function(onComplete) {
-  var spec = this;
-  if (!spec.env.specFilter(spec)) {
-    spec.results_.skipped = true;
-    spec.finish(onComplete);
-    return;
-  }
-
-  this.env.reporter.reportSpecStarting(this);
-
-  spec.env.currentSpec = spec;
-
-  spec.addBeforesAndAftersToQueue();
-
-  spec.queue.start(function () {
-    spec.finish(onComplete);
-  });
-};
-
-jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
-  var runner = this.env.currentRunner();
-  var i;
-
-  for (var suite = this.suite; suite; suite = suite.parentSuite) {
-    for (i = 0; i < suite.before_.length; i++) {
-      this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
-    }
-  }
-  for (i = 0; i < runner.before_.length; i++) {
-    this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
-  }
-  for (i = 0; i < this.afterCallbacks.length; i++) {
-    this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this));
-  }
-  for (suite = this.suite; suite; suite = suite.parentSuite) {
-    for (i = 0; i < suite.after_.length; i++) {
-      this.queue.add(new jasmine.Block(this.env, suite.after_[i], this));
-    }
-  }
-  for (i = 0; i < runner.after_.length; i++) {
-    this.queue.add(new jasmine.Block(this.env, runner.after_[i], this));
-  }
-};
-
-jasmine.Spec.prototype.explodes = function() {
-  throw 'explodes function should not have been called';
-};
-
-jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
-  if (obj == jasmine.undefined) {
-    throw "spyOn could not find an object to spy upon for " + methodName + "()";
-  }
-
-  if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
-    throw methodName + '() method does not exist';
-  }
-
-  if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
-    throw new Error(methodName + ' has already been spied upon');
-  }
-
-  var spyObj = jasmine.createSpy(methodName);
-
-  this.spies_.push(spyObj);
-  spyObj.baseObj = obj;
-  spyObj.methodName = methodName;
-  spyObj.originalValue = obj[methodName];
-
-  obj[methodName] = spyObj;
-
-  return spyObj;
-};
-
-jasmine.Spec.prototype.removeAllSpies = function() {
-  for (var i = 0; i < this.spies_.length; i++) {
-    var spy = this.spies_[i];
-    spy.baseObj[spy.methodName] = spy.originalValue;
-  }
-  this.spies_ = [];
+    var expectationResult = new jasmine.ExpectationResult({
+        passed: false,
+        message: e ? jasmine.util.formatException(e) : 'Exception',
+        trace: { stack: e.stack }
+    });
+    this.results_.addResult(expectationResult);
+};
+
+jasmine.Spec.prototype.getMatchersClass_ = function () {
+    return this.matchersClass || this.env.matchersClass;
+};
+
+jasmine.Spec.prototype.addMatchers = function (matchersPrototype) {
+    var parent = this.getMatchersClass_();
+    var newMatchersClass = function () {
+        parent.apply(this, arguments);
+    };
+    jasmine.util.inherit(newMatchersClass, parent);
+    jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
+    this.matchersClass = newMatchersClass;
+};
+
+jasmine.Spec.prototype.finishCallback = function () {
+    this.env.reporter.reportSpecResults(this);
+};
+
+jasmine.Spec.prototype.finish = function (onComplete) {
+    this.removeAllSpies();
+    this.finishCallback();
+    if (onComplete) {
+        onComplete();
+    }
+};
+
+jasmine.Spec.prototype.after = function (doAfter) {
+    if (this.queue.isRunning()) {
+        this.queue.add(new jasmine.Block(this.env, doAfter, this));
+    } else {
+        this.afterCallbacks.unshift(doAfter);
+    }
+};
+
+jasmine.Spec.prototype.execute = function (onComplete) {
+    var spec = this;
+    if (!spec.env.specFilter(spec)) {
+        spec.results_.skipped = true;
+        spec.finish(onComplete);
+        return;
+    }
+
+    this.env.reporter.reportSpecStarting(this);
+
+    spec.env.currentSpec = spec;
+
+    spec.addBeforesAndAftersToQueue();
+
+    spec.queue.start(function () {
+        spec.finish(onComplete);
+    });
+};
+
+jasmine.Spec.prototype.addBeforesAndAftersToQueue = function () {
+    var runner = this.env.currentRunner();
+    var i;
+
+    for (var suite = this.suite; suite; suite = suite.parentSuite) {
+        for (i = 0; i < suite.before_.length; i++) {
+            this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
+        }
+    }
+    for (i = 0; i < runner.before_.length; i++) {
+        this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
+    }
+    for (i = 0; i < this.afterCallbacks.length; i++) {
+        this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this));
+    }
+    for (suite = this.suite; suite; suite = suite.parentSuite) {
+        for (i = 0; i < suite.after_.length; i++) {
+            this.queue.add(new jasmine.Block(this.env, suite.after_[i], this));
+        }
+    }
+    for (i = 0; i < runner.after_.length; i++) {
+        this.queue.add(new jasmine.Block(this.env, runner.after_[i], this));
+    }
+};
+
+jasmine.Spec.prototype.explodes = function () {
+    throw 'explodes function should not have been called';
+};
+
+jasmine.Spec.prototype.spyOn = function (obj, methodName, ignoreMethodDoesntExist) {
+    if (obj == jasmine.undefined) {
+        throw "spyOn could not find an object to spy upon for " + methodName + "()";
+    }
+
+    if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
+        throw methodName + '() method does not exist';
+    }
+
+    if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
+        throw new Error(methodName + ' has already been spied upon');
+    }
+
+    var spyObj = jasmine.createSpy(methodName);
+
+    this.spies_.push(spyObj);
+    spyObj.baseObj = obj;
+    spyObj.methodName = methodName;
+    spyObj.originalValue = obj[methodName];
+
+    obj[methodName] = spyObj;
+
+    return spyObj;
+};
+
+jasmine.Spec.prototype.removeAllSpies = function () {
+    for (var i = 0; i < this.spies_.length; i++) {
+        var spy = this.spies_[i];
+        spy.baseObj[spy.methodName] = spy.originalValue;
+    }
+    this.spies_ = [];
 };
 
 /**
@@ -2378,93 +2378,93 @@
  * @param {Function} specDefinitions
  * @param {jasmine.Suite} parentSuite
  */
-jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
-  var self = this;
-  self.id = env.nextSuiteId ? env.nextSuiteId() : null;
-  self.description = description;
-  self.queue = new jasmine.Queue(env);
-  self.parentSuite = parentSuite;
-  self.env = env;
-  self.before_ = [];
-  self.after_ = [];
-  self.children_ = [];
-  self.suites_ = [];
-  self.specs_ = [];
-};
-
-jasmine.Suite.prototype.getFullName = function() {
-  var fullName = this.description;
-  for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
-    fullName = parentSuite.description + ' ' + fullName;
-  }
-  return fullName;
-};
-
-jasmine.Suite.prototype.finish = function(onComplete) {
-  this.env.reporter.reportSuiteResults(this);
-  this.finished = true;
-  if (typeof(onComplete) == 'function') {
-    onComplete();
-  }
-};
-
-jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
-  beforeEachFunction.typeName = 'beforeEach';
-  this.before_.unshift(beforeEachFunction);
-};
-
-jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
-  afterEachFunction.typeName = 'afterEach';
-  this.after_.unshift(afterEachFunction);
-};
-
-jasmine.Suite.prototype.results = function() {
-  return this.queue.results();
-};
-
-jasmine.Suite.prototype.add = function(suiteOrSpec) {
-  this.children_.push(suiteOrSpec);
-  if (suiteOrSpec instanceof jasmine.Suite) {
-    this.suites_.push(suiteOrSpec);
-    this.env.currentRunner().addSuite(suiteOrSpec);
-  } else {
-    this.specs_.push(suiteOrSpec);
-  }
-  this.queue.add(suiteOrSpec);
-};
-
-jasmine.Suite.prototype.specs = function() {
-  return this.specs_;
-};
-
-jasmine.Suite.prototype.suites = function() {
-  return this.suites_;
-};
-
-jasmine.Suite.prototype.children = function() {
-  return this.children_;
-};
-
-jasmine.Suite.prototype.execute = function(onComplete) {
-  var self = this;
-  this.queue.start(function () {
-    self.finish(onComplete);
-  });
-};
-jasmine.WaitsBlock = function(env, timeout, spec) {
-  this.timeout = timeout;
-  jasmine.Block.call(this, env, null, spec);
+jasmine.Suite = function (env, description, specDefinitions, parentSuite) {
+    var self = this;
+    self.id = env.nextSuiteId ? env.nextSuiteId() : null;
+    self.description = description;
+    self.queue = new jasmine.Queue(env);
+    self.parentSuite = parentSuite;
+    self.env = env;
+    self.before_ = [];
+    self.after_ = [];
+    self.children_ = [];
+    self.suites_ = [];
+    self.specs_ = [];
+};
+
+jasmine.Suite.prototype.getFullName = function () {
+    var fullName = this.description;
+    for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
+        fullName = parentSuite.description + ' ' + fullName;
+    }
+    return fullName;
+};
+
+jasmine.Suite.prototype.finish = function (onComplete) {
+    this.env.reporter.reportSuiteResults(this);
+    this.finished = true;
+    if (typeof(onComplete) == 'function') {
+        onComplete();
+    }
+};
+
+jasmine.Suite.prototype.beforeEach = function (beforeEachFunction) {
+    beforeEachFunction.typeName = 'beforeEach';
+    this.before_.unshift(beforeEachFunction);
+};
+
+jasmine.Suite.prototype.afterEach = function (afterEachFunction) {
+    afterEachFunction.typeName = 'afterEach';
+    this.after_.unshift(afterEachFunction);
+};
+
+jasmine.Suite.prototype.results = function () {
+    return this.queue.results();
+};
+
+jasmine.Suite.prototype.add = function (suiteOrSpec) {
+    this.children_.push(suiteOrSpec);
+    if (suiteOrSpec instanceof jasmine.Suite) {
+        this.suites_.push(suiteOrSpec);
+        this.env.currentRunner().addSuite(suiteOrSpec);
+    } else {
+        this.specs_.push(suiteOrSpec);
+    }
+    this.queue.add(suiteOrSpec);
+};
+
+jasmine.Suite.prototype.specs = function () {
+    return this.specs_;
+};
+
+jasmine.Suite.prototype.suites = function () {
+    return this.suites_;
+};
+
+jasmine.Suite.prototype.children = function () {
+    return this.children_;
+};
+
+jasmine.Suite.prototype.execute = function (onComplete) {
+    var self = this;
+    this.queue.start(function () {
+        self.finish(onComplete);
+    });
+};
+jasmine.WaitsBlock = function (env, timeout, spec) {
+    this.timeout = timeout;
+    jasmine.Block.call(this, env, null, spec);
 };
 
 jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
 
 jasmine.WaitsBlock.prototype.execute = function (onComplete) {
-  if (jasmine.VERBOSE) {
-    this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
-  }
-  this.env.setTimeout(function () {
-    onComplete();
-  }, this.timeout);
+    if (jasmine.VERBOSE) {
+        this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
+    }
+    this.env.setTimeout(function () {
+        onComplete();
+    }, this.timeout);
 };
 /**
  * A block which waits for some condition to become true, with timeout.
@@ -2477,54 +2477,54 @@
  * @param {String} message The message to display if the desired condition hasn't been met within the given time period.
  * @param {jasmine.Spec} spec The Jasmine spec.
  */
-jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
-  this.timeout = timeout || env.defaultTimeoutInterval;
-  this.latchFunction = latchFunction;
-  this.message = message;
-  this.totalTimeSpentWaitingForLatch = 0;
-  jasmine.Block.call(this, env, null, spec);
+jasmine.WaitsForBlock = function (env, timeout, latchFunction, message, spec) {
+    this.timeout = timeout || env.defaultTimeoutInterval;
+    this.latchFunction = latchFunction;
+    this.message = message;
+    this.totalTimeSpentWaitingForLatch = 0;
+    jasmine.Block.call(this, env, null, spec);
 };
 jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
 
 jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
 
-jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
-  if (jasmine.VERBOSE) {
-    this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
-  }
-  var latchFunctionResult;
-  try {
-    latchFunctionResult = this.latchFunction.apply(this.spec);
-  } catch (e) {
-    this.spec.fail(e);
-    onComplete();
-    return;
-  }
-
-  if (latchFunctionResult) {
-    onComplete();
-  } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
-    var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
-    this.spec.fail({
-      name: 'timeout',
-      message: message
-    });
-
-    this.abort = true;
-    onComplete();
-  } else {
-    this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
-    var self = this;
-    this.env.setTimeout(function() {
-      self.execute(onComplete);
-    }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
-  }
-};
-
-jasmine.version_= {
-  "major": 1,
-  "minor": 2,
-  "build": 0,
-  "revision": 1337005947
-};
-
+jasmine.WaitsForBlock.prototype.execute = function (onComplete) {
+    if (jasmine.VERBOSE) {
+        this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
+    }
+    var latchFunctionResult;
+    try {
+        latchFunctionResult = this.latchFunction.apply(this.spec);
+    } catch (e) {
+        this.spec.fail(e);
+        onComplete();
+        return;
+    }
+
+    if (latchFunctionResult) {
+        onComplete();
+    } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
+        var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
+        this.spec.fail({
+            name: 'timeout',
+            message: message
+        });
+
+        this.abort = true;
+        onComplete();
+    } else {
+        this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
+        var self = this;
+        this.env.setTimeout(function () {
+            self.execute(onComplete);
+        }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
+    }
+};
+
+jasmine.version_ = {
+    "major": 1,
+    "minor": 2,
+    "build": 0,
+    "revision": 1337005947
+};
+

--- a/js/flotr2/make/basic.json
+++ b/js/flotr2/make/basic.json
@@ -1,26 +1,26 @@
 {
-  "JAVASCRIPT": {
-    "DIST_DIR": "./build",
-    "flotr2-basic": [
-      "./js/Flotr.js",
-      "./js/DefaultOptions.js",
-      "./js/DOM.js",
-      "./js/EventAdapter.js",
-      "./js/Color.js",
-      "./js/Date.js",
-      "./js/Text.js",
-      "./js/Graph.js",
-      "./js/Axis.js",
-      "./js/Series.js",
-      "./js/types/lines.js",
-      "./js/types/bars.js",
-      "./js/types/markers.js",
-      "./js/types/points.js",
-      "./js/plugins/grid.js",
-      "./js/plugins/labels.js",
-      "./js/plugins/legend.js",
-      "./js/plugins/titles.js"
-    ]
-  }
+    "JAVASCRIPT": {
+        "DIST_DIR": "./build",
+        "flotr2-basic": [
+            "./js/Flotr.js",
+            "./js/DefaultOptions.js",
+            "./js/DOM.js",
+            "./js/EventAdapter.js",
+            "./js/Color.js",
+            "./js/Date.js",
+            "./js/Text.js",
+            "./js/Graph.js",
+            "./js/Axis.js",
+            "./js/Series.js",
+            "./js/types/lines.js",
+            "./js/types/bars.js",
+            "./js/types/markers.js",
+            "./js/types/points.js",
+            "./js/plugins/grid.js",
+            "./js/plugins/labels.js",
+            "./js/plugins/legend.js",
+            "./js/plugins/titles.js"
+        ]
+    }
 }
 

--- a/js/flotr2/make/build.json
+++ b/js/flotr2/make/build.json
@@ -1,98 +1,113 @@
 {
-  "JAVASCRIPT": {
-    "DIST_DIR": "./build",
-    "ie": [
-      { "src": "./lib/excanvas.js", "jshint": false },
-      { "src": "./lib/base64.js", "jshint": false },
-      { "src": "./lib/canvastext.js", "jshint": false }
-    ],
-    "lib": [
-      { "src": "./lib/bean.js", "jshint": false },
-      { "src": "./lib/underscore.js", "jshint": false }
-    ],
-    "flotr2": [
-      "./js/Flotr.js",
-      "./js/DefaultOptions.js",
-      "./js/Color.js",
-      "./js/Date.js",
-      "./js/DOM.js",
-      "./js/EventAdapter.js",
-      "./js/Text.js",
-      "./js/Graph.js",
-      "./js/Axis.js",
-      "./js/Series.js",
-      "./js/types/lines.js",
-      "./js/types/bars.js",
-      "./js/types/bubbles.js",
-      "./js/types/candles.js",
-      "./js/types/gantt.js",
-      "./js/types/markers.js",
-      "./js/types/pie.js",
-      "./js/types/points.js",
-      "./js/types/radar.js",
-      "./js/types/timeline.js",
-      "./js/plugins/crosshair.js",
-      "./js/plugins/download.js",
-      "./js/plugins/grid.js",
-      "./js/plugins/hit.js",
-      "./js/plugins/selection.js",
-      "./js/plugins/labels.js",
-      "./js/plugins/legend.js",
-      "./js/plugins/spreadsheet.js",
-      "./js/plugins/titles.js"
-    ],
-    "flotr2-basic": [
-      "./js/Flotr.js",
-      "./js/DefaultOptions.js",
-      "./js/DOM.js",
-      "./js/EventAdapter.js",
-      "./js/Color.js",
-      "./js/Date.js",
-      "./js/Text.js",
-      "./js/Graph.js",
-      "./js/Axis.js",
-      "./js/Series.js",
-      "./js/types/lines.js",
-      "./js/types/bars.js",
-      "./js/types/markers.js",
-      "./js/types/points.js",
-      "./js/plugins/grid.js",
-      "./js/plugins/labels.js",
-      "./js/plugins/legend.js",
-      "./js/plugins/titles.js"
-    ],
-    "examples": [
-      "./examples/js/Examples.js",
-      "./examples/js/Example.js",
-      "./examples/js/Editor.js",
-      "./examples/js/Profile.js"
-    ],
-    "examples-types": [
-      "./examples/js/ExampleList.js",
-      "./examples/js/examples/basic.js",
-      "./examples/js/examples/basic-stacked.js",
-      "./examples/js/examples/basic-axis.js",
-      "./examples/js/examples/basic-bars.js",
-      "./examples/js/examples/basic-bars-stacked.js",
-      "./examples/js/examples/basic-pie.js",
-      "./examples/js/examples/basic-radar.js",
-      "./examples/js/examples/basic-bubble.js",
-      "./examples/js/examples/basic-candle.js",
-      "./examples/js/examples/basic-legend.js",
-      "./examples/js/examples/mouse-tracking.js",
-      "./examples/js/examples/mouse-zoom.js",
-      "./examples/js/examples/mouse-drag.js",
-      "./examples/js/examples/basic-time.js",
-      "./examples/js/examples/negative-values.js",
-      "./examples/js/examples/click-example.js",
-      "./examples/js/examples/download-image.js",
-      "./examples/js/examples/download-data.js",
-      "./examples/js/examples/advanced-titles.js",
-      "./examples/js/examples/color-gradients.js",
-      "./examples/js/examples/profile-bars.js",
-      "./examples/js/examples/basic-timeline.js",
-      "./examples/js/examples/advanced-markers.js"
-    ]
-  }
+    "JAVASCRIPT": {
+        "DIST_DIR": "./build",
+        "ie": [
+            {
+                "src": "./lib/excanvas.js",
+                "jshint": false
+            },
+            {
+                "src": "./lib/base64.js",
+                "jshint": false
+            },
+            {
+                "src": "./lib/canvastext.js",
+                "jshint": false
+            }
+        ],
+        "lib": [
+            {
+                "src": "./lib/bean.js",
+                "jshint": false
+            },
+            {
+                "src": "./lib/underscore.js",
+                "jshint": false
+            }
+        ],
+        "flotr2": [
+            "./js/Flotr.js",
+            "./js/DefaultOptions.js",
+            "./js/Color.js",
+            "./js/Date.js",
+            "./js/DOM.js",
+            "./js/EventAdapter.js",
+            "./js/Text.js",
+            "./js/Graph.js",
+            "./js/Axis.js",
+            "./js/Series.js",
+            "./js/types/lines.js",
+            "./js/types/bars.js",
+            "./js/types/bubbles.js",
+            "./js/types/candles.js",
+            "./js/types/gantt.js",
+            "./js/types/markers.js",
+            "./js/types/pie.js",
+            "./js/types/points.js",
+            "./js/types/radar.js",
+            "./js/types/timeline.js",
+            "./js/plugins/crosshair.js",
+            "./js/plugins/download.js",
+            "./js/plugins/grid.js",
+            "./js/plugins/hit.js",
+            "./js/plugins/selection.js",
+            "./js/plugins/labels.js",
+            "./js/plugins/legend.js",
+            "./js/plugins/spreadsheet.js",
+            "./js/plugins/titles.js"
+        ],
+        "flotr2-basic": [
+            "./js/Flotr.js",
+            "./js/DefaultOptions.js",
+            "./js/DOM.js",
+            "./js/EventAdapter.js",
+            "./js/Color.js",
+            "./js/Date.js",
+            "./js/Text.js",
+            "./js/Graph.js",
+            "./js/Axis.js",
+            "./js/Series.js",
+            "./js/types/lines.js",
+            "./js/types/bars.js",
+            "./js/types/markers.js",
+            "./js/types/points.js",
+            "./js/plugins/grid.js",
+            "./js/plugins/labels.js",
+            "./js/plugins/legend.js",
+            "./js/plugins/titles.js"
+        ],
+        "examples": [
+            "./examples/js/Examples.js",
+            "./examples/js/Example.js",
+            "./examples/js/Editor.js",
+            "./examples/js/Profile.js"
+        ],
+        "examples-types": [
+            "./examples/js/ExampleList.js",
+            "./examples/js/examples/basic.js",
+            "./examples/js/examples/basic-stacked.js",
+            "./examples/js/examples/basic-axis.js",
+            "./examples/js/examples/basic-bars.js",
+            "./examples/js/examples/basic-bars-stacked.js",
+            "./examples/js/examples/basic-pie.js",
+            "./examples/js/examples/basic-radar.js",
+            "./examples/js/examples/basic-bubble.js",
+            "./examples/js/examples/basic-candle.js",
+            "./examples/js/examples/basic-legend.js",
+            "./examples/js/examples/mouse-tracking.js",
+            "./examples/js/examples/mouse-zoom.js",
+            "./examples/js/examples/mouse-drag.js",
+            "./examples/js/examples/basic-time.js",
+            "./examples/js/examples/negative-values.js",
+            "./examples/js/examples/click-example.js",
+            "./examples/js/examples/download-image.js",
+            "./examples/js/examples/download-data.js",
+            "./examples/js/examples/advanced-titles.js",
+            "./examples/js/examples/color-gradients.js",
+            "./examples/js/examples/profile-bars.js",
+            "./examples/js/examples/basic-timeline.js",
+            "./examples/js/examples/advanced-markers.js"
+        ]
+    }
 }
 

--- a/js/flotr2/make/examples.json
+++ b/js/flotr2/make/examples.json
@@ -1,39 +1,39 @@
 {
-  "JAVASCRIPT": {
-    "DIST_DIR": "./build",
-    "examples": [
-      "./examples/js/Examples.js",
-      "./examples/js/Example.js",
-      "./examples/js/Editor.js",
-      "./examples/js/Profile.js"
-    ],
-    "examples-types": [
-      "./examples/js/ExampleList.js",
-      "./examples/js/examples/basic.js",
-      "./examples/js/examples/basic-stacked.js",
-      "./examples/js/examples/basic-stepped.js",
-      "./examples/js/examples/basic-axis.js",
-      "./examples/js/examples/basic-bars.js",
-      "./examples/js/examples/basic-bars-stacked.js",
-      "./examples/js/examples/basic-pie.js",
-      "./examples/js/examples/basic-radar.js",
-      "./examples/js/examples/basic-bubble.js",
-      "./examples/js/examples/basic-candle.js",
-      "./examples/js/examples/basic-legend.js",
-      "./examples/js/examples/mouse-tracking.js",
-      "./examples/js/examples/mouse-zoom.js",
-      "./examples/js/examples/mouse-drag.js",
-      "./examples/js/examples/basic-time.js",
-      "./examples/js/examples/negative-values.js",
-      "./examples/js/examples/click-example.js",
-      "./examples/js/examples/download-image.js",
-      "./examples/js/examples/download-data.js",
-      "./examples/js/examples/advanced-titles.js",
-      "./examples/js/examples/color-gradients.js",
-      "./examples/js/examples/profile-bars.js",
-      "./examples/js/examples/basic-timeline.js",
-      "./examples/js/examples/advanced-markers.js"
-    ]
-  }
+    "JAVASCRIPT": {
+        "DIST_DIR": "./build",
+        "examples": [
+            "./examples/js/Examples.js",
+            "./examples/js/Example.js",
+            "./examples/js/Editor.js",
+            "./examples/js/Profile.js"
+        ],
+        "examples-types": [
+            "./examples/js/ExampleList.js",
+            "./examples/js/examples/basic.js",
+            "./examples/js/examples/basic-stacked.js",
+            "./examples/js/examples/basic-stepped.js",
+            "./examples/js/examples/basic-axis.js",
+            "./examples/js/examples/basic-bars.js",
+            "./examples/js/examples/basic-bars-stacked.js",
+            "./examples/js/examples/basic-pie.js",
+            "./examples/js/examples/basic-radar.js",
+            "./examples/js/examples/basic-bubble.js",
+            "./examples/js/examples/basic-candle.js",
+            "./examples/js/examples/basic-legend.js",
+            "./examples/js/examples/mouse-tracking.js",
+            "./examples/js/examples/mouse-zoom.js",
+            "./examples/js/examples/mouse-drag.js",
+            "./examples/js/examples/basic-time.js",
+            "./examples/js/examples/negative-values.js",
+            "./examples/js/examples/click-example.js",
+            "./examples/js/examples/download-image.js",
+            "./examples/js/examples/download-data.js",
+            "./examples/js/examples/advanced-titles.js",
+            "./examples/js/examples/color-gradients.js",
+            "./examples/js/examples/profile-bars.js",
+            "./examples/js/examples/basic-timeline.js",
+            "./examples/js/examples/advanced-markers.js"
+        ]
+    }
 }
 

--- a/js/flotr2/make/flotr2.json
+++ b/js/flotr2/make/flotr2.json
@@ -1,37 +1,37 @@
 {
-  "JAVASCRIPT": {
-    "DIST_DIR": "./build",
-    "flotr2": [
-      "./js/Flotr.js",
-      "./js/DefaultOptions.js",
-      "./js/Color.js",
-      "./js/Date.js",
-      "./js/DOM.js",
-      "./js/EventAdapter.js",
-      "./js/Text.js",
-      "./js/Graph.js",
-      "./js/Axis.js",
-      "./js/Series.js",
-      "./js/types/lines.js",
-      "./js/types/bars.js",
-      "./js/types/bubbles.js",
-      "./js/types/candles.js",
-      "./js/types/gantt.js",
-      "./js/types/markers.js",
-      "./js/types/pie.js",
-      "./js/types/points.js",
-      "./js/types/radar.js",
-      "./js/types/timeline.js",
-      "./js/plugins/crosshair.js",
-      "./js/plugins/download.js",
-      "./js/plugins/grid.js",
-      "./js/plugins/hit.js",
-      "./js/plugins/selection.js",
-      "./js/plugins/labels.js",
-      "./js/plugins/legend.js",
-      "./js/plugins/spreadsheet.js",
-      "./js/plugins/titles.js"
-    ]
-  }
+    "JAVASCRIPT": {
+        "DIST_DIR": "./build",
+        "flotr2": [
+            "./js/Flotr.js",
+            "./js/DefaultOptions.js",
+            "./js/Color.js",
+            "./js/Date.js",
+            "./js/DOM.js",
+            "./js/EventAdapter.js",
+            "./js/Text.js",
+            "./js/Graph.js",
+            "./js/Axis.js",
+            "./js/Series.js",
+            "./js/types/lines.js",
+            "./js/types/bars.js",
+            "./js/types/bubbles.js",
+            "./js/types/candles.js",
+            "./js/types/gantt.js",
+            "./js/types/markers.js",
+            "./js/types/pie.js",
+            "./js/types/points.js",
+            "./js/types/radar.js",
+            "./js/types/timeline.js",
+            "./js/plugins/crosshair.js",
+            "./js/plugins/download.js",
+            "./js/plugins/grid.js",
+            "./js/plugins/hit.js",
+            "./js/plugins/selection.js",
+            "./js/plugins/labels.js",
+            "./js/plugins/legend.js",
+            "./js/plugins/spreadsheet.js",
+            "./js/plugins/titles.js"
+        ]
+    }
 }
 

--- a/js/flotr2/make/ie.json
+++ b/js/flotr2/make/ie.json
@@ -1,11 +1,20 @@
 {
-  "JAVASCRIPT": {
-    "DIST_DIR": "./build",
-    "ie": [
-      { "src": "./lib/excanvas.js", "jshint": false },
-      { "src": "./lib/base64.js", "jshint": false },
-      { "src": "./lib/canvastext.js", "jshint": false }
-    ]
-  }
+    "JAVASCRIPT": {
+        "DIST_DIR": "./build",
+        "ie": [
+            {
+                "src": "./lib/excanvas.js",
+                "jshint": false
+            },
+            {
+                "src": "./lib/base64.js",
+                "jshint": false
+            },
+            {
+                "src": "./lib/canvastext.js",
+                "jshint": false
+            }
+        ]
+    }
 }
 

--- a/js/flotr2/make/lib.json
+++ b/js/flotr2/make/lib.json
@@ -1,12 +1,18 @@
 {
-  "JAVASCRIPT": {
-    "DIST_DIR": "./build",
-    "bean": [
-      { "src": "./lib/bean.js", "jshint": false }
-    ],
-    "underscore": [
-      { "src": "./lib/underscore.js", "jshint": false }
-    ]
-  }
+    "JAVASCRIPT": {
+        "DIST_DIR": "./build",
+        "bean": [
+            {
+                "src": "./lib/bean.js",
+                "jshint": false
+            }
+        ],
+        "underscore": [
+            {
+                "src": "./lib/underscore.js",
+                "jshint": false
+            }
+        ]
+    }
 }
 

--- a/js/flotr2/spec/Chart.js
+++ b/js/flotr2/spec/Chart.js
@@ -1,121 +1,133 @@
 describe('Charts', function () {
 
-  var
-    width = 480,
-    height = 320,
-    a, b, options, defaults;
+    var
+        width = 480,
+        height = 320,
+        a, b, options, defaults;
 
-  defaults = {
-    width : 480,
-    height : 320,
-    color : "rgb(192,216,0)",
-    context : null,
-    data : null,
-    fill : false,
-    fillColor : null,
-    fillOpacity : 0.4,
-    fillStyle : "rgba(192,216,0,0.4)",
-    fontColor : "#545454",
-    fontSize : 7.5,
-    htmlText : true,
-    lineWidth : 2,
-    shadowSize : 4,
-    show : false,
-    stacked : false,
-    textEnabled : true,
-    xScale : function (x) { return x; },
-    yScale : function (y) { return height - y; }
-  };
+    defaults = {
+        width: 480,
+        height: 320,
+        color: "rgb(192,216,0)",
+        context: null,
+        data: null,
+        fill: false,
+        fillColor: null,
+        fillOpacity: 0.4,
+        fillStyle: "rgba(192,216,0,0.4)",
+        fontColor: "#545454",
+        fontSize: 7.5,
+        htmlText: true,
+        lineWidth: 2,
+        shadowSize: 4,
+        show: false,
+        stacked: false,
+        textEnabled: true,
+        xScale: function (x) {
+            return x;
+        },
+        yScale: function (y) {
+            return height - y;
+        }
+    };
 
-  /**
-   * @param skip bool  Skip test against development version (use this when developing test)
-   */
-  function drawTest (data, o, skip) {
-    options.data = data;
-    if (o) _.extend(options, o);
+    /**
+     * @param skip bool  Skip test against development version (use this when developing test)
+     */
+    function drawTest(data, o, skip) {
+        options.data = data;
+        if (o) _.extend(options, o);
 
-    if (!skip) TestFlotr.graphTypes.lines.draw(options);
-    options.context = b.getContext('2d');
-    StableFlotr.graphTypes.lines.draw(options);
+        if (!skip) TestFlotr.graphTypes.lines.draw(options);
+        options.context = b.getContext('2d');
+        StableFlotr.graphTypes.lines.draw(options);
 
-    expect(b).toImageDiffEqual(a);
-  }
+        expect(b).toImageDiffEqual(a);
+    }
 
-  describe('Lines', function () {
+    describe('Lines', function () {
 
-    beforeEach(function () {
-      options = _.clone(defaults);
+        beforeEach(function () {
+            options = _.clone(defaults);
+        });
+
+        /*
+         describe('Data', function () {
+         it('gets a range', function () {
+         options.stacked = true;
+         options.data = [[0, 0], [240, 160], [480, 320]];
+         range = TestFlotr.graphTypes.lines.range(options);
+         expect(range.min).toEqual(0);
+         expect(range.max).toEqual(320);
+         });
+         });
+         */
+
+        describe('Draw', function () {
+
+            beforeEach(function () {
+                this.addMatchers(imagediff.jasmine);
+                a = imagediff.createCanvas(width, height);
+                b = imagediff.createCanvas(width, height);
+                options.context = a.getContext('2d');
+            });
+
+            it('draws a line chart', function () {
+                drawTest([
+                    [0, 0],
+                    [240, 300],
+                    [480, 0]
+                ]);
+            });
+
+            it('skips null values', function () {
+                drawTest([
+                    [0, 0],
+                    [100, 50],
+                    [200, null],
+                    [300, 150],
+                    [400, 200],
+                    [480, 240]
+                ]);
+            });
+
+            it('draws two lines', function () {
+                // First line
+                drawTest([
+                    [0, 0],
+                    [240, 160],
+                    [480, 320]
+                ]);
+
+                // Second Line
+                options.context = a.getContext('2d');
+                drawTest([
+                    [0, 320],
+                    [240, 160],
+                    [480, 0]
+                ]);
+            });
+
+            it('fills a line', function () {
+                drawTest([
+                    [0, 0],
+                    [240, 300],
+                    [480, 0]
+                ], {
+                    fill: true
+                });
+            });
+
+            it('draws no shadow', function () {
+                drawTest([
+                    [0, 0],
+                    [240, 300],
+                    [480, 0]
+                ], {
+                    shadowSize: 0
+                });
+            });
+        });
     });
-
-    /*
-    describe('Data', function () {
-      it('gets a range', function () {
-        options.stacked = true;
-        options.data = [[0, 0], [240, 160], [480, 320]];
-        range = TestFlotr.graphTypes.lines.range(options);
-        expect(range.min).toEqual(0);
-        expect(range.max).toEqual(320);
-      });
-    });
-    */
-
-    describe('Draw', function () {
-
-      beforeEach(function () {
-        this.addMatchers(imagediff.jasmine);
-        a = imagediff.createCanvas(width, height);
-        b = imagediff.createCanvas(width, height);
-        options.context = a.getContext('2d');
-      });
-
-      it('draws a line chart', function () {
-        drawTest([
-          [0, 0],
-          [240, 300],
-          [480, 0]
-        ]);
-      });
-
-      it('skips null values', function () {
-        drawTest([
-          [0, 0],
-          [100, 50],
-          [200, null],
-          [300, 150],
-          [400, 200],
-          [480, 240]
-        ]);
-      });
-
-      it('draws two lines', function () {
-        // First line
-        drawTest([[0, 0], [240, 160], [480, 320]]);
-
-        // Second Line
-        options.context = a.getContext('2d');
-        drawTest([[0, 320], [240, 160], [480, 0]]);
-      });
-
-      it('fills a line', function () {
-        drawTest([
-          [0, 0],
-          [240, 300],
-          [480, 0]
-        ], {
-          fill : true
-        });
-      });
-
-      it('draws no shadow', function () {
-        drawTest([
-          [0, 0],
-          [240, 300],
-          [480, 0]
-        ], {
-          shadowSize : 0
-        });
-      });
-    });
-  });
 });
 

--- a/js/flotr2/spec/Color.js
+++ b/js/flotr2/spec/Color.js
@@ -1,93 +1,93 @@
 describe('Colors', function () {
 
-  describe('Color Construction', function () {
-    it('should have a color class', function () {
-      expect(TestFlotr.Color).not.toBeUndefined();
+    describe('Color Construction', function () {
+        it('should have a color class', function () {
+            expect(TestFlotr.Color).not.toBeUndefined();
+        });
+
+        it('should create a color', function () {
+            var color = new TestFlotr.Color(0, 0, 0, 0);
+            expect(color).toBeTruthy();
+        });
+
+        it('should have rgba attributes', function () {
+            var color = new TestFlotr.Color(0, 0, 0, 0);
+            expect(color.r).toEqual(0);
+            expect(color.g).toEqual(0);
+            expect(color.b).toEqual(0);
+            expect(color.a).toEqual(1.0);
+        });
     });
 
-    it('should create a color', function () {
-      var color = new TestFlotr.Color(0, 0, 0, 0);
-      expect(color).toBeTruthy();
+    describe('Color Manipulation', function () {
+
+        var
+            color;
+
+        afterEach(function () {
+            color = null;
+        });
+
+        it('normalizes colors to upper bound', function () {
+            color = new TestFlotr.Color(1000, 1000, 1000, 10);
+            expect(color.r).toEqual(255);
+            expect(color.g).toEqual(255);
+            expect(color.b).toEqual(255);
+            expect(color.a).toEqual(1.0);
+        });
+
+        it('normalizes colors to lower bound', function () {
+            color = new TestFlotr.Color(-1000, -1000, -1000, -10);
+            expect(color.r).toEqual(0);
+            expect(color.g).toEqual(0);
+            expect(color.b).toEqual(0);
+            expect(color.a).toEqual(0.0);
+        });
+
+        it('scales colors', function () {
+            color = new TestFlotr.Color(200, 200, 200, 1.0);
+            color.scale(.5, .5, .5, .5);
+            expect(color.r).toEqual(100);
+            expect(color.g).toEqual(100);
+            expect(color.b).toEqual(100);
+            expect(color.a).toEqual(0.5);
+        });
     });
 
-    it('should have rgba attributes', function () {
-      var color = new TestFlotr.Color(0, 0, 0, 0);
-      expect(color.r).toEqual(0);
-      expect(color.g).toEqual(0);
-      expect(color.b).toEqual(0);
-      expect(color.a).toEqual(1.0);
+    describe('Color Conversion', function () {
+
+        var
+            color;
+
+        beforeEach(function () {
+            color = new TestFlotr.Color(200, 200, 200, 1.0);
+        });
+        afterEach(function () {
+            color = null;
+        });
+
+        it('should convert colors to strings, rgb', function () {
+            expect(color.toString()).toEqual('rgb(200,200,200)');
+        });
+
+        it('should convert colors to strings, rgba', function () {
+            color.a = 0.5;
+            color.normalize();
+            expect(color.toString()).toEqual('rgba(200,200,200,0.5)');
+        });
+
+        it('should clone colors', function () {
+
+            var
+                color2 = color.clone();
+
+            expect(color.toString()).toEqual(color2.toString());
+
+            color.a = 0.5;
+            color.normalize();
+            color2 = color.clone();
+            expect(color.toString()).toEqual(color2.toString());
+        });
     });
-  });
-
-  describe('Color Manipulation', function () {
-
-    var
-      color;
-
-    afterEach(function () {
-      color = null;
-    });
-
-    it('normalizes colors to upper bound', function () {
-      color = new TestFlotr.Color(1000, 1000, 1000, 10);
-      expect(color.r).toEqual(255);
-      expect(color.g).toEqual(255);
-      expect(color.b).toEqual(255);
-      expect(color.a).toEqual(1.0);
-    });
-
-    it('normalizes colors to lower bound', function () {
-      color = new TestFlotr.Color(-1000, -1000, -1000, -10);
-      expect(color.r).toEqual(0);
-      expect(color.g).toEqual(0);
-      expect(color.b).toEqual(0);
-      expect(color.a).toEqual(0.0);
-    });
-
-    it('scales colors', function () {
-	    color = new TestFlotr.Color(200, 200, 200, 1.0);
-      color.scale(.5, .5, .5, .5);
-      expect(color.r).toEqual(100);
-      expect(color.g).toEqual(100);
-      expect(color.b).toEqual(100);
-      expect(color.a).toEqual(0.5);
-    });
-  });
-
-  describe('Color Conversion', function () {
-
-    var
-      color;
-
-    beforeEach(function () {
-	    color = new TestFlotr.Color(200, 200, 200, 1.0);
-    });
-    afterEach(function () {
-      color = null;
-    });
-
-    it('should convert colors to strings, rgb', function () {
-      expect(color.toString()).toEqual('rgb(200,200,200)');
-    });
-
-    it('should convert colors to strings, rgba', function () {
-      color.a = 0.5;
-      color.normalize();
-      expect(color.toString()).toEqual('rgba(200,200,200,0.5)');
-    });
-
-    it('should clone colors', function () {
-
-      var
-        color2 = color.clone();
-
-      expect(color.toString()).toEqual(color2.toString());
-
-      color.a = 0.5;
-      color.normalize();
-      color2 = color.clone();
-      expect(color.toString()).toEqual(color2.toString());
-    });
-  });
 });
 

--- a/js/flotr2/spec/Flotr.js
+++ b/js/flotr2/spec/Flotr.js
@@ -1,77 +1,77 @@
 describe('Flotr', function () {
 
-  describe('Plots', function () {
+    describe('Plots', function () {
 
-    var
-      nodeA, nodeB,
-      a, b;
+        var
+            nodeA, nodeB,
+            a, b;
 
-    beforeEach(function () {
+        beforeEach(function () {
 
-      // Add imagediff matchers
-      this.addMatchers(imagediff.jasmine);
+            // Add imagediff matchers
+            this.addMatchers(imagediff.jasmine);
 
-      nodeA = buildNode();
-      nodeB = buildNode();
+            nodeA = buildNode();
+            nodeB = buildNode();
+        });
+
+        afterEach(function () {
+            destroyNode(nodeA);
+            destroyNode(nodeB);
+            a = null;
+            b = null;
+            Flotr = null;
+        });
+
+        _.each(TestFlotr.ExampleList.examples, function (example, key) {
+
+            it('should draw a `' + example.name + '`line graph', function () {
+
+                executeExampleTest(example, StableFlotr, nodeA);
+                executeExampleTest(example, TestFlotr, nodeB);
+
+                if (example.timeout) {
+                    waits(example.timeout);
+                    runs(function () {
+                        expect(nodeB.graph.ctx).toImageDiffEqual(nodeA.graph.ctx, example.tolerance || 0);
+                    });
+                } else {
+                    expect(nodeB.graph.ctx).toImageDiffEqual(nodeA.graph.ctx, example.tolerance || 0);
+                }
+            });
+        });
+
+        // Helpers
+
+        function executeExampleTest(example, flotr, node) {
+            Math.seedrandom(example.key);
+            Flotr = flotr;
+            example.callback.apply(this, [node].concat(example.args || []));
+        }
+
+        function buildNode() {
+            var node = document.createElement('div');
+            document.body.appendChild(node);
+            node.style.width = '320px';
+            node.style.height = '240px';
+            return node;
+        }
+
+        function destroyNode(node) {
+            document.body.removeChild(node);
+        }
     });
 
-    afterEach(function () {
-      destroyNode(nodeA);
-      destroyNode(nodeB);
-      a = null;
-      b = null;
-      Flotr = null;
+    describe('Main', function () {
+
+        it('gets a tick size', function () {
+            expect(TestFlotr.getTickSize).not.toBeUndefined();
+            expect(TestFlotr.getTickSize(10, 0, 100, 1)).toEqual(10);
+            expect(TestFlotr.getTickSize(20, 0, 100, 1)).toEqual(5);
+            expect(TestFlotr.getTickSize(5, 10, 110, 1)).toEqual(20);
+            expect(TestFlotr.getTickSize(0, 0, 10, 1)).toEqual(Number.POSITIVE_INFINITY);
+            expect(isNaN(TestFlotr.getTickSize(0, 0, -10, 1))).toBeTruthy();
+        });
     });
-
-    _.each(TestFlotr.ExampleList.examples, function (example, key) {
-
-      it('should draw a `' + example.name + '`line graph', function () {
-
-        executeExampleTest(example, StableFlotr, nodeA);
-        executeExampleTest(example, TestFlotr, nodeB);
-
-        if (example.timeout) {
-          waits(example.timeout);
-          runs (function () {
-            expect(nodeB.graph.ctx).toImageDiffEqual(nodeA.graph.ctx, example.tolerance || 0);
-          });
-        } else {
-          expect(nodeB.graph.ctx).toImageDiffEqual(nodeA.graph.ctx, example.tolerance || 0);
-        }
-      });
-    });
-
-    // Helpers
-
-    function executeExampleTest (example, flotr, node) {
-      Math.seedrandom(example.key);
-      Flotr = flotr;
-      example.callback.apply(this, [node].concat(example.args || []));
-    }
-
-    function buildNode () {
-      var node = document.createElement('div');
-      document.body.appendChild(node);
-      node.style.width = '320px';
-      node.style.height = '240px';
-      return node;
-    }
-
-    function destroyNode (node) {
-      document.body.removeChild(node);
-    }
-  });
-
-  describe('Main', function () {
-
-    it('gets a tick size', function () {
-      expect(TestFlotr.getTickSize).not.toBeUndefined();
-      expect(TestFlotr.getTickSize(10, 0, 100, 1)).toEqual(10);
-      expect(TestFlotr.getTickSize(20, 0, 100, 1)).toEqual(5);
-      expect(TestFlotr.getTickSize(5, 10, 110, 1)).toEqual(20);
-      expect(TestFlotr.getTickSize(0, 0, 10, 1)).toEqual(Number.POSITIVE_INFINITY);
-      expect(isNaN(TestFlotr.getTickSize(0, 0, -10, 1))).toBeTruthy();
-    });
-  });
 });
 

--- a/js/flotr2/spec/Graph.js
+++ b/js/flotr2/spec/Graph.js
@@ -1,80 +1,80 @@
 describe('Graph', function () {
 
-  describe('Options', function () {
-    var
-      nodeA, nodeB,
-      a, b, x, i,
-      d1 = [],
-      options = {};
+    describe('Options', function () {
+        var
+            nodeA, nodeB,
+            a, b, x, i,
+            d1 = [],
+            options = {};
 
-      for (i = 0; i < 100; i++) {
-        x = (i*1000*3600*24*36.5);
-        d1.push([x, i+Math.random()*30+Math.sin(i/20+Math.random()*2)*20+Math.sin(i/10+Math.random())*10]);
-      }
+        for (i = 0; i < 100; i++) {
+            x = (i * 1000 * 3600 * 24 * 36.5);
+            d1.push([x, i + Math.random() * 30 + Math.sin(i / 20 + Math.random() * 2) * 20 + Math.sin(i / 10 + Math.random()) * 10]);
+        }
 
-      options = {
-        xaxis : {
-          mode : 'time',
-          labelsAngle : 45
-        },
-        selection : {
-          mode : 'x'
-        },
-        HtmlText : false,
-      };
+        options = {
+            xaxis: {
+                mode: 'time',
+                labelsAngle: 45
+            },
+            selection: {
+                mode: 'x'
+            },
+            HtmlText: false,
+        };
 
-    beforeEach(function () {
-      nodeA = buildNode();
-      Flotr = TestFlotr;
+        beforeEach(function () {
+            nodeA = buildNode();
+            Flotr = TestFlotr;
+        });
+
+        afterEach(function () {
+            destroyNode(nodeA);
+            a = b = null;
+            Flotr = null;
+        });
+
+        it('should override nested default options with user options', function () {
+            a = new TestFlotr.Graph(nodeA, d1, options);
+            expect(a.options.xaxis.mode).toEqual(options.xaxis.mode);
+        });
+
+        it('should retain default options if user option\'s nested object does not define property', function () {
+            a = new TestFlotr.Graph(nodeA, d1, options);
+            expect(a.options.xaxis.tickFormatter).toBeTruthy();
+        });
+
+        it('should not affect default options when modifying graph options (objects)', function () {
+            a = new TestFlotr.Graph(nodeA, d1, options);
+            a.options.x2axis = {
+                titleAlign: 'left'
+            };
+            a.options.xaxis.scaling = 'logarithmic';
+            expect(TestFlotr.defaultOptions.xaxis.scaling).toEqual('linear');
+            expect(TestFlotr.defaultOptions.x2axis.titleAlign).toBeFalsy();
+        });
+
+        /*
+         it('should not affect default options when modifying graph options (arrays)', function() {
+         a = new TestFlotr.Graph(nodeA, d1, options);
+         a.options.colors[1] = '#bada55';
+         expect(TestFlotr.defaultOptions.colors[1]).toNotBe('#bada55');
+         });
+         */
+
     });
 
-    afterEach(function () {
-      destroyNode(nodeA);
-      a = b = null;
-      Flotr = null;
-    });
+    function buildNode() {
+        var node = document.createElement('div');
+        document.body.appendChild(node);
+        node.style.width = '320px';
+        node.style.height = '240px';
+        return node;
+    }
 
-    it('should override nested default options with user options', function() {
-      a = new TestFlotr.Graph(nodeA, d1, options);
-      expect(a.options.xaxis.mode).toEqual(options.xaxis.mode);
-    });
-    
-    it('should retain default options if user option\'s nested object does not define property', function() {
-      a = new TestFlotr.Graph(nodeA, d1, options);
-      expect(a.options.xaxis.tickFormatter).toBeTruthy();
-    });
-
-    it('should not affect default options when modifying graph options (objects)', function() {
-      a = new TestFlotr.Graph(nodeA, d1, options);
-      a.options.x2axis = {  
-        titleAlign : 'left'
-      };
-      a.options.xaxis.scaling = 'logarithmic';
-      expect(TestFlotr.defaultOptions.xaxis.scaling).toEqual('linear');
-      expect(TestFlotr.defaultOptions.x2axis.titleAlign).toBeFalsy();
-    });
-    
-    /*
-    it('should not affect default options when modifying graph options (arrays)', function() {
-      a = new TestFlotr.Graph(nodeA, d1, options);
-      a.options.colors[1] = '#bada55';
-      expect(TestFlotr.defaultOptions.colors[1]).toNotBe('#bada55');
-    });
-    */
-
-  });
-
-  function buildNode () {
-    var node = document.createElement('div');
-    document.body.appendChild(node);
-    node.style.width = '320px';
-    node.style.height = '240px';
-    return node;
-  }
-
-  function destroyNode (node) {
-    document.body.removeChild(node);
-  }
+    function destroyNode(node) {
+        document.body.removeChild(node);
+    }
 
 });
 

--- a/js/flotr2/spec/index.html
+++ b/js/flotr2/spec/index.html
@@ -1,103 +1,103 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
-  "http://www.w3.org/TR/html4/loose.dtd">
+        "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
-  <title>Jasmine Spec Runner</title>
+    <title>Jasmine Spec Runner</title>
 
-  <link rel="shortcut icon" type="image/png" href="../lib/jasmine/jasmine_favicon.png">
+    <link rel="shortcut icon" type="image/png" href="../lib/jasmine/jasmine_favicon.png">
 
-  <link rel="stylesheet" type="text/css" href="../lib/jasmine/jasmine.css">
-  <script type="text/javascript" src="../lib/jasmine/jasmine.js"></script>
-  <script type="text/javascript" src="../lib/jasmine/jasmine-html.js"></script>
-  <script type="text/javascript" src="../lib/imagediff.js"></script>
-  <script type="text/javascript" src="../examples/lib/randomseed.js"></script>
+    <link rel="stylesheet" type="text/css" href="../lib/jasmine/jasmine.css">
+    <script type="text/javascript" src="../lib/jasmine/jasmine.js"></script>
+    <script type="text/javascript" src="../lib/jasmine/jasmine-html.js"></script>
+    <script type="text/javascript" src="../lib/imagediff.js"></script>
+    <script type="text/javascript" src="../examples/lib/randomseed.js"></script>
 
-  <!-- include source files here... -->
-  <script type="text/javascript" src="js/flotr2.stable.js"></script>
-  <script type="text/javascript">
-      var StableFlotr = Flotr.noConflict();
-  </script>
+    <!-- include source files here... -->
+    <script type="text/javascript" src="js/flotr2.stable.js"></script>
+    <script type="text/javascript">
+        var StableFlotr = Flotr.noConflict();
+    </script>
 
-  <script src="../lib/bean.js"></script>
-  <script src="../lib/underscore.js"></script>
-  <script src="../js/Flotr.js"></script>
-  <script src="../js/DefaultOptions.js"></script>
-  <script src="../js/Color.js"></script>
-  <script src="../js/Date.js"></script>
-  <script src="../js/DOM.js"></script>
-  <script src="../js/EventAdapter.js"></script>
-  <script src="../js/Text.js"></script>
-  <script src="../js/Graph.js"></script>
-  <script src="../js/Axis.js"></script>
-  <script src="../js/Series.js"></script>
-  <script src="../js/types/lines.js"></script>
-  <script src="../js/types/bars.js"></script>
-  <script src="../js/types/bubbles.js"></script>
-  <script src="../js/types/candles.js"></script>
-  <script src="../js/types/gantt.js"></script>
-  <script src="../js/types/markers.js"></script>
-  <script src="../js/types/pie.js"></script>
-  <script src="../js/types/points.js"></script>
-  <script src="../js/types/radar.js"></script>
-  <script src="../js/types/timeline.js"></script>
-  <script src="../js/plugins/crosshair.js"></script>
-  <script src="../js/plugins/download.js"></script>
-  <script src="../js/plugins/grid.js"></script>
-  <script src="../js/plugins/hit.js"></script>
-  <script src="../js/plugins/selection.js"></script>
-  <script src="../js/plugins/labels.js"></script>
-  <script src="../js/plugins/legend.js"></script>
-  <script src="../js/plugins/spreadsheet.js"></script>
-  <script src="../js/plugins/titles.js"></script>
-  <script src="../js/charts/lines.js"></script>
+    <script src="../lib/bean.js"></script>
+    <script src="../lib/underscore.js"></script>
+    <script src="../js/Flotr.js"></script>
+    <script src="../js/DefaultOptions.js"></script>
+    <script src="../js/Color.js"></script>
+    <script src="../js/Date.js"></script>
+    <script src="../js/DOM.js"></script>
+    <script src="../js/EventAdapter.js"></script>
+    <script src="../js/Text.js"></script>
+    <script src="../js/Graph.js"></script>
+    <script src="../js/Axis.js"></script>
+    <script src="../js/Series.js"></script>
+    <script src="../js/types/lines.js"></script>
+    <script src="../js/types/bars.js"></script>
+    <script src="../js/types/bubbles.js"></script>
+    <script src="../js/types/candles.js"></script>
+    <script src="../js/types/gantt.js"></script>
+    <script src="../js/types/markers.js"></script>
+    <script src="../js/types/pie.js"></script>
+    <script src="../js/types/points.js"></script>
+    <script src="../js/types/radar.js"></script>
+    <script src="../js/types/timeline.js"></script>
+    <script src="../js/plugins/crosshair.js"></script>
+    <script src="../js/plugins/download.js"></script>
+    <script src="../js/plugins/grid.js"></script>
+    <script src="../js/plugins/hit.js"></script>
+    <script src="../js/plugins/selection.js"></script>
+    <script src="../js/plugins/labels.js"></script>
+    <script src="../js/plugins/legend.js"></script>
+    <script src="../js/plugins/spreadsheet.js"></script>
+    <script src="../js/plugins/titles.js"></script>
+    <script src="../js/charts/lines.js"></script>
 
-  <!-- Test Examples -->
-  <script type="text/javascript" src="../flotr2.examples.types.js"></script>
-  <script type="text/javascript" src="js/test-background.js"></script>
-  <script type="text/javascript" src="js/test-boundaries.js"></script>
-  <script type="text/javascript" src="js/test-mountain-nulls.js"></script>
+    <!-- Test Examples -->
+    <script type="text/javascript" src="../flotr2.examples.types.js"></script>
+    <script type="text/javascript" src="js/test-background.js"></script>
+    <script type="text/javascript" src="js/test-boundaries.js"></script>
+    <script type="text/javascript" src="js/test-mountain-nulls.js"></script>
 
-  <script type="text/javascript">
-    var TestFlotr = Flotr.noConflict();
-  </script>
+    <script type="text/javascript">
+        var TestFlotr = Flotr.noConflict();
+    </script>
 
-  <!-- include spec files here... -->
-  <script type="text/javascript" src="Flotr.js"></script>
-  <script type="text/javascript" src="Color.js"></script>
-  <script type="text/javascript" src="Graph.js"></script>
-  <script type="text/javascript" src="Chart.js"></script>
+    <!-- include spec files here... -->
+    <script type="text/javascript" src="Flotr.js"></script>
+    <script type="text/javascript" src="Color.js"></script>
+    <script type="text/javascript" src="Graph.js"></script>
+    <script type="text/javascript" src="Chart.js"></script>
 
 </head>
 
 <body>
 </body>
 <script type="text/javascript">
-(function() {
-  var jasmineEnv = jasmine.getEnv();
-  jasmineEnv.updateInterval = 1000;
+    (function () {
+        var jasmineEnv = jasmine.getEnv();
+        jasmineEnv.updateInterval = 1000;
 
-  var reporter = new jasmine.HtmlReporter();
+        var reporter = new jasmine.HtmlReporter();
 
-  jasmineEnv.addReporter(reporter);
+        jasmineEnv.addReporter(reporter);
 
-  jasmineEnv.specFilter = function(spec) {
-    return reporter.specFilter(spec);
-  };
+        jasmineEnv.specFilter = function (spec) {
+            return reporter.specFilter(spec);
+        };
 
-  var currentWindowOnload = window.onload;
+        var currentWindowOnload = window.onload;
 
-  window.onload = function() {
-    if (currentWindowOnload) {
-      currentWindowOnload();
-    }
-    execJasmine();
-  };
+        window.onload = function () {
+            if (currentWindowOnload) {
+                currentWindowOnload();
+            }
+            execJasmine();
+        };
 
-  function execJasmine() {
-    jasmineEnv.execute();
-  }
+        function execJasmine() {
+            jasmineEnv.execute();
+        }
 
-})();
+    })();
 </script>
 </html>
 

--- a/js/flotr2/spec/js/flotr2.stable.js
+++ b/js/flotr2/spec/js/flotr2.stable.js
@@ -1,505 +1,500 @@
 /*!
-  * bean.js - copyright Jacob Thornton 2011
-  * https://github.com/fat/bean
-  * MIT License
-  * special thanks to:
-  * dean edwards: http://dean.edwards.name/
-  * dperini: https://github.com/dperini/nwevents
-  * the entire mootools team: github.com/mootools/mootools-core
-  */
+ * bean.js - copyright Jacob Thornton 2011
+ * https://github.com/fat/bean
+ * MIT License
+ * special thanks to:
+ * dean edwards: http://dean.edwards.name/
+ * dperini: https://github.com/dperini/nwevents
+ * the entire mootools team: github.com/mootools/mootools-core
+ */
 /*global module:true, define:true*/
 !function (name, context, definition) {
-  if (typeof module !== 'undefined') module.exports = definition(name, context);
-  else if (typeof define === 'function' && typeof define.amd  === 'object') define(definition);
-  else context[name] = definition(name, context);
+    if (typeof module !== 'undefined') module.exports = definition(name, context);
+    else if (typeof define === 'function' && typeof define.amd === 'object') define(definition);
+    else context[name] = definition(name, context);
 }('bean', this, function (name, context) {
-  var win = window
-    , old = context[name]
-    , overOut = /over|out/
-    , namespaceRegex = /[^\.]*(?=\..*)\.|.*/
-    , nameRegex = /\..*/
-    , addEvent = 'addEventListener'
-    , attachEvent = 'attachEvent'
-    , removeEvent = 'removeEventListener'
-    , detachEvent = 'detachEvent'
-    , doc = document || {}
-    , root = doc.documentElement || {}
-    , W3C_MODEL = root[addEvent]
-    , eventSupport = W3C_MODEL ? addEvent : attachEvent
-    , slice = Array.prototype.slice
-    , mouseTypeRegex = /click|mouse|menu|drag|drop/i
-    , touchTypeRegex = /^touch|^gesture/i
-    , ONE = { one: 1 } // singleton for quick matching making add() do one()
-
-    , nativeEvents = (function (hash, events, i) {
-        for (i = 0; i < events.length; i++)
-          hash[events[i]] = 1
-        return hash
-      })({}, (
-          'click dblclick mouseup mousedown contextmenu ' +                  // mouse buttons
-          'mousewheel DOMMouseScroll ' +                                     // mouse wheel
-          'mouseover mouseout mousemove selectstart selectend ' +            // mouse movement
-          'keydown keypress keyup ' +                                        // keyboard
-          'orientationchange ' +                                             // mobile
-          'focus blur change reset select submit ' +                         // form elements
-          'load unload beforeunload resize move DOMContentLoaded readystatechange ' + // window
-          'error abort scroll ' +                                            // misc
-          (W3C_MODEL ? // element.fireEvent('onXYZ'... is not forgiving if we try to fire an event
-                       // that doesn't actually exist, so make sure we only do these on newer browsers
-            'show ' +                                                          // mouse buttons
-            'input invalid ' +                                                 // form elements
-            'touchstart touchmove touchend touchcancel ' +                     // touch
-            'gesturestart gesturechange gestureend ' +                         // gesture
-            'message readystatechange pageshow pagehide popstate ' +           // window
-            'hashchange offline online ' +                                     // window
-            'afterprint beforeprint ' +                                        // printing
-            'dragstart dragenter dragover dragleave drag drop dragend ' +      // dnd
-            'loadstart progress suspend emptied stalled loadmetadata ' +       // media
-            'loadeddata canplay canplaythrough playing waiting seeking ' +     // media
-            'seeked ended durationchange timeupdate play pause ratechange ' +  // media
-            'volumechange cuechange ' +                                        // media
-            'checking noupdate downloading cached updateready obsolete ' +     // appcache
-            '' : '')
-        ).split(' ')
-      )
-
-    , customEvents = (function () {
-        function isDescendant(parent, node) {
-          while ((node = node.parentNode) !== null) {
-            if (node === parent) return true
-          }
-          return false
-        }
-
-        function check(event) {
-          var related = event.relatedTarget
-          if (!related) return related === null
-          return (related !== this && related.prefix !== 'xul' && !/document/.test(this.toString()) && !isDescendant(this, related))
-        }
-
-        return {
-            mouseenter: { base: 'mouseover', condition: check }
-          , mouseleave: { base: 'mouseout', condition: check }
-          , mousewheel: { base: /Firefox/.test(navigator.userAgent) ? 'DOMMouseScroll' : 'mousewheel' }
-        }
-      })()
-
-    , fixEvent = (function () {
-        var commonProps = 'altKey attrChange attrName bubbles cancelable ctrlKey currentTarget detail eventPhase getModifierState isTrusted metaKey relatedNode relatedTarget shiftKey srcElement target timeStamp type view which'.split(' ')
-          , mouseProps = commonProps.concat('button buttons clientX clientY dataTransfer fromElement offsetX offsetY pageX pageY screenX screenY toElement'.split(' '))
-          , keyProps = commonProps.concat('char charCode key keyCode'.split(' '))
-          , touchProps = commonProps.concat('touches targetTouches changedTouches scale rotation'.split(' '))
-          , preventDefault = 'preventDefault'
-          , createPreventDefault = function (event) {
-              return function () {
-                if (event[preventDefault])
-                  event[preventDefault]()
-                else
-                  event.returnValue = false
-              }
-            }
-          , stopPropagation = 'stopPropagation'
-          , createStopPropagation = function (event) {
-              return function () {
-                if (event[stopPropagation])
-                  event[stopPropagation]()
-                else
-                  event.cancelBubble = true
-              }
-            }
-          , createStop = function (synEvent) {
-              return function () {
-                synEvent[preventDefault]()
-                synEvent[stopPropagation]()
-                synEvent.stopped = true
-              }
-            }
-          , copyProps = function (event, result, props) {
-              var i, p
-              for (i = props.length; i--;) {
-                p = props[i]
-                if (!(p in result) && p in event) result[p] = event[p]
-              }
-            }
-
-        return function (event, isNative) {
-          var result = { originalEvent: event, isNative: isNative }
-          if (!event)
-            return result
-
-          var props
-            , type = event.type
-            , target = event.target || event.srcElement
-
-          result[preventDefault] = createPreventDefault(event)
-          result[stopPropagation] = createStopPropagation(event)
-          result.stop = createStop(result)
-          result.target = target && target.nodeType === 3 ? target.parentNode : target
-
-          if (isNative) { // we only need basic augmentation on custom events, the rest is too expensive
-            if (type.indexOf('key') !== -1) {
-              props = keyProps
-              result.keyCode = event.which || event.keyCode
-            } else if (mouseTypeRegex.test(type)) {
-              props = mouseProps
-              result.rightClick = event.which === 3 || event.button === 2
-              result.pos = { x: 0, y: 0 }
-              if (event.pageX || event.pageY) {
-                result.clientX = event.pageX
-                result.clientY = event.pageY
-              } else if (event.clientX || event.clientY) {
-                result.clientX = event.clientX + doc.body.scrollLeft + root.scrollLeft
-                result.clientY = event.clientY + doc.body.scrollTop + root.scrollTop
-              }
-              if (overOut.test(type))
-                result.relatedTarget = event.relatedTarget || event[(type === 'mouseover' ? 'from' : 'to') + 'Element']
-            } else if (touchTypeRegex.test(type)) {
-              props = touchProps
-            }
-            copyProps(event, result, props || commonProps)
-          }
-          return result
-        }
-      })()
-
-      // if we're in old IE we can't do onpropertychange on doc or win so we use doc.documentElement for both
-    , targetElement = function (element, isNative) {
-        return !W3C_MODEL && !isNative && (element === doc || element === win) ? root : element
-      }
-
-      // we use one of these per listener, of any type
-    , RegEntry = (function () {
-        function entry(element, type, handler, original, namespaces) {
-          this.element = element
-          this.type = type
-          this.handler = handler
-          this.original = original
-          this.namespaces = namespaces
-          this.custom = customEvents[type]
-          this.isNative = nativeEvents[type] && element[eventSupport]
-          this.eventType = W3C_MODEL || this.isNative ? type : 'propertychange'
-          this.customType = !W3C_MODEL && !this.isNative && type
-          this.target = targetElement(element, this.isNative)
-          this.eventSupport = this.target[eventSupport]
-        }
-
-        entry.prototype = {
-            // given a list of namespaces, is our entry in any of them?
-            inNamespaces: function (checkNamespaces) {
-              var i, j
-              if (!checkNamespaces)
-                return true
-              if (!this.namespaces)
+    var win = window
+        , old = context[name]
+        , overOut = /over|out/
+        , namespaceRegex = /[^\.]*(?=\..*)\.|.*/
+        , nameRegex = /\..*/
+        , addEvent = 'addEventListener'
+        , attachEvent = 'attachEvent'
+        , removeEvent = 'removeEventListener'
+        , detachEvent = 'detachEvent'
+        , doc = document || {}
+        , root = doc.documentElement || {}
+        , W3C_MODEL = root[addEvent]
+        , eventSupport = W3C_MODEL ? addEvent : attachEvent
+        , slice = Array.prototype.slice
+        , mouseTypeRegex = /click|mouse|menu|drag|drop/i
+        , touchTypeRegex = /^touch|^gesture/i
+        , ONE = { one: 1 } // singleton for quick matching making add() do one()
+
+        , nativeEvents = (function (hash, events, i) {
+            for (i = 0; i < events.length; i++)
+                hash[events[i]] = 1
+            return hash
+        })({}, (
+            'click dblclick mouseup mousedown contextmenu ' +                  // mouse buttons
+                'mousewheel DOMMouseScroll ' +                                     // mouse wheel
+                'mouseover mouseout mousemove selectstart selectend ' +            // mouse movement
+                'keydown keypress keyup ' +                                        // keyboard
+                'orientationchange ' +                                             // mobile
+                'focus blur change reset select submit ' +                         // form elements
+                'load unload beforeunload resize move DOMContentLoaded readystatechange ' + // window
+                'error abort scroll ' +                                            // misc
+                (W3C_MODEL ? // element.fireEvent('onXYZ'... is not forgiving if we try to fire an event
+                    // that doesn't actually exist, so make sure we only do these on newer browsers
+                    'show ' +                                                          // mouse buttons
+                        'input invalid ' +                                                 // form elements
+                        'touchstart touchmove touchend touchcancel ' +                     // touch
+                        'gesturestart gesturechange gestureend ' +                         // gesture
+                        'message readystatechange pageshow pagehide popstate ' +           // window
+                        'hashchange offline online ' +                                     // window
+                        'afterprint beforeprint ' +                                        // printing
+                        'dragstart dragenter dragover dragleave drag drop dragend ' +      // dnd
+                        'loadstart progress suspend emptied stalled loadmetadata ' +       // media
+                        'loadeddata canplay canplaythrough playing waiting seeking ' +     // media
+                        'seeked ended durationchange timeupdate play pause ratechange ' +  // media
+                        'volumechange cuechange ' +                                        // media
+                        'checking noupdate downloading cached updateready obsolete ' +     // appcache
+                        '' : '')
+            ).split(' ')
+        )
+
+        , customEvents = (function () {
+            function isDescendant(parent, node) {
+                while ((node = node.parentNode) !== null) {
+                    if (node === parent) return true
+                }
                 return false
-              for (i = checkNamespaces.length; i--;) {
-                for (j = this.namespaces.length; j--;) {
-                  if (checkNamespaces[i] === this.namespaces[j])
-                    return true
-                }
-              }
-              return false
-            }
-
-            // match by element, original fn (opt), handler fn (opt)
-          , matches: function (checkElement, checkOriginal, checkHandler) {
-              return this.element === checkElement &&
-                (!checkOriginal || this.original === checkOriginal) &&
-                (!checkHandler || this.handler === checkHandler)
-            }
-        }
-
-        return entry
-      })()
-
-    , registry = (function () {
-        // our map stores arrays by event type, just because it's better than storing
-        // everything in a single array. uses '$' as a prefix for the keys for safety
-        var map = {}
-
-          // generic functional search of our registry for matching listeners,
-          // `fn` returns false to break out of the loop
-          , forAll = function (element, type, original, handler, fn) {
-              if (!type || type === '*') {
-                // search the whole registry
-                for (var t in map) {
-                  if (t.charAt(0) === '$')
-                    forAll(element, t.substr(1), original, handler, fn)
-                }
-              } else {
-                var i = 0, l, list = map['$' + type], all = element === '*'
-                if (!list)
-                  return
-                for (l = list.length; i < l; i++) {
-                  if (all || list[i].matches(element, original, handler))
-                    if (!fn(list[i], list, i, type))
-                      return
-                }
-              }
-            }
-
-          , has = function (element, type, original) {
-              // we're not using forAll here simply because it's a bit slower and this
-              // needs to be fast
-              var i, list = map['$' + type]
-              if (list) {
-                for (i = list.length; i--;) {
-                  if (list[i].matches(element, original, null))
-                    return true
-                }
-              }
-              return false
-            }
-
-          , get = function (element, type, original) {
-              var entries = []
-              forAll(element, type, original, null, function (entry) { return entries.push(entry) })
-              return entries
-            }
-
-          , put = function (entry) {
-              (map['$' + entry.type] || (map['$' + entry.type] = [])).push(entry)
-              return entry
-            }
-
-          , del = function (entry) {
-              forAll(entry.element, entry.type, null, entry.handler, function (entry, list, i) {
-                list.splice(i, 1)
-                if (list.length === 0)
-                  delete map['$' + entry.type]
-                return false
-              })
-            }
+            }
+
+            function check(event) {
+                var related = event.relatedTarget
+                if (!related) return related === null
+                return (related !== this && related.prefix !== 'xul' && !/document/.test(this.toString()) && !isDescendant(this, related))
+            }
+
+            return {
+                mouseenter: { base: 'mouseover', condition: check }, mouseleave: { base: 'mouseout', condition: check }, mousewheel: { base: /Firefox/.test(navigator.userAgent) ? 'DOMMouseScroll' : 'mousewheel' }
+            }
+        })()
+
+        , fixEvent = (function () {
+            var commonProps = 'altKey attrChange attrName bubbles cancelable ctrlKey currentTarget detail eventPhase getModifierState isTrusted metaKey relatedNode relatedTarget shiftKey srcElement target timeStamp type view which'.split(' ')
+                , mouseProps = commonProps.concat('button buttons clientX clientY dataTransfer fromElement offsetX offsetY pageX pageY screenX screenY toElement'.split(' '))
+                , keyProps = commonProps.concat('char charCode key keyCode'.split(' '))
+                , touchProps = commonProps.concat('touches targetTouches changedTouches scale rotation'.split(' '))
+                , preventDefault = 'preventDefault'
+                , createPreventDefault = function (event) {
+                    return function () {
+                        if (event[preventDefault])
+                            event[preventDefault]()
+                        else
+                            event.returnValue = false
+                    }
+                }
+                , stopPropagation = 'stopPropagation'
+                , createStopPropagation = function (event) {
+                    return function () {
+                        if (event[stopPropagation])
+                            event[stopPropagation]()
+                        else
+                            event.cancelBubble = true
+                    }
+                }
+                , createStop = function (synEvent) {
+                    return function () {
+                        synEvent[preventDefault]()
+                        synEvent[stopPropagation]()
+                        synEvent.stopped = true
+                    }
+                }
+                , copyProps = function (event, result, props) {
+                    var i, p
+                    for (i = props.length; i--;) {
+                        p = props[i]
+                        if (!(p in result) && p in event) result[p] = event[p]
+                    }
+                }
+
+            return function (event, isNative) {
+                var result = { originalEvent: event, isNative: isNative }
+                if (!event)
+                    return result
+
+                var props
+                    , type = event.type
+                    , target = event.target || event.srcElement
+
+                result[preventDefault] = createPreventDefault(event)
+                result[stopPropagation] = createStopPropagation(event)
+                result.stop = createStop(result)
+                result.target = target && target.nodeType === 3 ? target.parentNode : target
+
+                if (isNative) { // we only need basic augmentation on custom events, the rest is too expensive
+                    if (type.indexOf('key') !== -1) {
+                        props = keyProps
+                        result.keyCode = event.which || event.keyCode
+                    } else if (mouseTypeRegex.test(type)) {
+                        props = mouseProps
+                        result.rightClick = event.which === 3 || event.button === 2
+                        result.pos = { x: 0, y: 0 }
+                        if (event.pageX || event.pageY) {
+                            result.clientX = event.pageX
+                            result.clientY = event.pageY
+                        } else if (event.clientX || event.clientY) {
+                            result.clientX = event.clientX + doc.body.scrollLeft + root.scrollLeft
+                            result.clientY = event.clientY + doc.body.scrollTop + root.scrollTop
+                        }
+                        if (overOut.test(type))
+                            result.relatedTarget = event.relatedTarget || event[(type === 'mouseover' ? 'from' : 'to') + 'Element']
+                    } else if (touchTypeRegex.test(type)) {
+                        props = touchProps
+                    }
+                    copyProps(event, result, props || commonProps)
+                }
+                return result
+            }
+        })()
+
+    // if we're in old IE we can't do onpropertychange on doc or win so we use doc.documentElement for both
+        , targetElement = function (element, isNative) {
+            return !W3C_MODEL && !isNative && (element === doc || element === win) ? root : element
+        }
+
+    // we use one of these per listener, of any type
+        , RegEntry = (function () {
+            function entry(element, type, handler, original, namespaces) {
+                this.element = element
+                this.type = type
+                this.handler = handler
+                this.original = original
+                this.namespaces = namespaces
+                this.custom = customEvents[type]
+                this.isNative = nativeEvents[type] && element[eventSupport]
+                this.eventType = W3C_MODEL || this.isNative ? type : 'propertychange'
+                this.customType = !W3C_MODEL && !this.isNative && type
+                this.target = targetElement(element, this.isNative)
+                this.eventSupport = this.target[eventSupport]
+            }
+
+            entry.prototype = {
+                // given a list of namespaces, is our entry in any of them?
+                inNamespaces: function (checkNamespaces) {
+                    var i, j
+                    if (!checkNamespaces)
+                        return true
+                    if (!this.namespaces)
+                        return false
+                    for (i = checkNamespaces.length; i--;) {
+                        for (j = this.namespaces.length; j--;) {
+                            if (checkNamespaces[i] === this.namespaces[j])
+                                return true
+                        }
+                    }
+                    return false
+                }
+
+                // match by element, original fn (opt), handler fn (opt)
+                , matches: function (checkElement, checkOriginal, checkHandler) {
+                    return this.element === checkElement &&
+                        (!checkOriginal || this.original === checkOriginal) &&
+                        (!checkHandler || this.handler === checkHandler)
+                }
+            }
+
+            return entry
+        })()
+
+        , registry = (function () {
+            // our map stores arrays by event type, just because it's better than storing
+            // everything in a single array. uses '$' as a prefix for the keys for safety
+            var map = {}
+
+            // generic functional search of our registry for matching listeners,
+            // `fn` returns false to break out of the loop
+                , forAll = function (element, type, original, handler, fn) {
+                    if (!type || type === '*') {
+                        // search the whole registry
+                        for (var t in map) {
+                            if (t.charAt(0) === '$')
+                                forAll(element, t.substr(1), original, handler, fn)
+                        }
+                    } else {
+                        var i = 0, l, list = map['$' + type], all = element === '*'
+                        if (!list)
+                            return
+                        for (l = list.length; i < l; i++) {
+                            if (all || list[i].matches(element, original, handler))
+                                if (!fn(list[i], list, i, type))
+                                    return
+                        }
+                    }
+                }
+
+                , has = function (element, type, original) {
+                    // we're not using forAll here simply because it's a bit slower and this
+                    // needs to be fast
+                    var i, list = map['$' + type]
+                    if (list) {
+                        for (i = list.length; i--;) {
+                            if (list[i].matches(element, original, null))
+                                return true
+                        }
+                    }
+                    return false
+                }
+
+                , get = function (element, type, original) {
+                    var entries = []
+                    forAll(element, type, original, null, function (entry) {
+                        return entries.push(entry)
+                    })
+                    return entries
+                }
+
+                , put = function (entry) {
+                    (map['$' + entry.type] || (map['$' + entry.type] = [])).push(entry)
+                    return entry
+                }
+
+                , del = function (entry) {
+                    forAll(entry.element, entry.type, null, entry.handler, function (entry, list, i) {
+                        list.splice(i, 1)
+                        if (list.length === 0)
+                            delete map['$' + entry.type]
+                        return false
+                    })
+                }
 
             // dump all entries, used for onunload
-          , entries = function () {
-              var t, entries = []
-              for (t in map) {
-                if (t.charAt(0) === '$')
-                  entries = entries.concat(map[t])
-              }
-              return entries
-            }
-
-        return { has: has, get: get, put: put, del: del, entries: entries }
-      })()
-
-      // add and remove listeners to DOM elements
-    , listener = W3C_MODEL ? function (element, type, fn, add) {
-        element[add ? addEvent : removeEvent](type, fn, false)
-      } : function (element, type, fn, add, custom) {
-        if (custom && add && element['_on' + custom] === null)
-          element['_on' + custom] = 0
-        element[add ? attachEvent : detachEvent]('on' + type, fn)
-      }
-
-    , nativeHandler = function (element, fn, args) {
-        return function (event) {
-          event = fixEvent(event || ((this.ownerDocument || this.document || this).parentWindow || win).event, true)
-          return fn.apply(element, [event].concat(args))
-        }
-      }
-
-    , customHandler = function (element, fn, type, condition, args, isNative) {
-        return function (event) {
-          if (condition ? condition.apply(this, arguments) : W3C_MODEL ? true : event && event.propertyName === '_on' + type || !event) {
-            if (event)
-              event = fixEvent(event || ((this.ownerDocument || this.document || this).parentWindow || win).event, isNative)
-            fn.apply(element, event && (!args || args.length === 0) ? arguments : slice.call(arguments, event ? 0 : 1).concat(args))
-          }
-        }
-      }
-
-    , once = function (rm, element, type, fn, originalFn) {
-        // wrap the handler in a handler that does a remove as well
-        return function () {
-          rm(element, type, originalFn)
-          fn.apply(this, arguments)
-        }
-      }
-
-    , removeListener = function (element, orgType, handler, namespaces) {
-        var i, l, entry
-          , type = (orgType && orgType.replace(nameRegex, ''))
-          , handlers = registry.get(element, type, handler)
-
-        for (i = 0, l = handlers.length; i < l; i++) {
-          if (handlers[i].inNamespaces(namespaces)) {
-            if ((entry = handlers[i]).eventSupport)
-              listener(entry.target, entry.eventType, entry.handler, false, entry.type)
-            // TODO: this is problematic, we have a registry.get() and registry.del() that
-            // both do registry searches so we waste cycles doing this. Needs to be rolled into
-            // a single registry.forAll(fn) that removes while finding, but the catch is that
-            // we'll be splicing the arrays that we're iterating over. Needs extra tests to
-            // make sure we don't screw it up. @rvagg
-            registry.del(entry)
-          }
-        }
-      }
-
-    , addListener = function (element, orgType, fn, originalFn, args) {
-        var entry
-          , type = orgType.replace(nameRegex, '')
-          , namespaces = orgType.replace(namespaceRegex, '').split('.')
-
-        if (registry.has(element, type, fn))
-          return element // no dupe
-        if (type === 'unload')
-          fn = once(removeListener, element, type, fn, originalFn) // self clean-up
-        if (customEvents[type]) {
-          if (customEvents[type].condition)
-            fn = customHandler(element, fn, type, customEvents[type].condition, true)
-          type = customEvents[type].base || type
-        }
-        entry = registry.put(new RegEntry(element, type, fn, originalFn, namespaces[0] && namespaces))
-        entry.handler = entry.isNative ?
-          nativeHandler(element, entry.handler, args) :
-          customHandler(element, entry.handler, type, false, args, false)
-        if (entry.eventSupport)
-          listener(entry.target, entry.eventType, entry.handler, true, entry.customType)
-      }
-
-    , del = function (selector, fn, $) {
-        return function (e) {
-          var target, i, array = typeof selector === 'string' ? $(selector, this) : selector
-          for (target = e.target; target && target !== this; target = target.parentNode) {
-            for (i = array.length; i--;) {
-              if (array[i] === target) {
-                return fn.apply(target, arguments)
-              }
-            }
-          }
-        }
-      }
-
-    , remove = function (element, typeSpec, fn) {
-        var k, m, type, namespaces, i
-          , rm = removeListener
-          , isString = typeSpec && typeof typeSpec === 'string'
-
-        if (isString && typeSpec.indexOf(' ') > 0) {
-          // remove(el, 't1 t2 t3', fn) or remove(el, 't1 t2 t3')
-          typeSpec = typeSpec.split(' ')
-          for (i = typeSpec.length; i--;)
-            remove(element, typeSpec[i], fn)
-          return element
-        }
-        type = isString && typeSpec.replace(nameRegex, '')
-        if (type && customEvents[type])
-          type = customEvents[type].type
-        if (!typeSpec || isString) {
-          // remove(el) or remove(el, t1.ns) or remove(el, .ns) or remove(el, .ns1.ns2.ns3)
-          if (namespaces = isString && typeSpec.replace(namespaceRegex, ''))
-            namespaces = namespaces.split('.')
-          rm(element, type, fn, namespaces)
-        } else if (typeof typeSpec === 'function') {
-          // remove(el, fn)
-          rm(element, null, typeSpec)
-        } else {
-          // remove(el, { t1: fn1, t2, fn2 })
-          for (k in typeSpec) {
-            if (typeSpec.hasOwnProperty(k))
-              remove(element, k, typeSpec[k])
-          }
-        }
-        return element
-      }
-
-    , add = function (element, events, fn, delfn, $) {
-        var type, types, i, args
-          , originalFn = fn
-          , isDel = fn && typeof fn === 'string'
-
-        if (events && !fn && typeof events === 'object') {
-          for (type in events) {
-            if (events.hasOwnProperty(type))
-              add.apply(this, [ element, type, events[type] ])
-          }
-        } else {
-          args = arguments.length > 3 ? slice.call(arguments, 3) : []
-          types = (isDel ? fn : events).split(' ')
-          isDel && (fn = del(events, (originalFn = delfn), $)) && (args = slice.call(args, 1))
-          // special case for one()
-          this === ONE && (fn = once(remove, element, events, fn, originalFn))
-          for (i = types.length; i--;) addListener(element, types[i], fn, originalFn, args)
-        }
-        return element
-      }
-
-    , one = function () {
-        return add.apply(ONE, arguments)
-      }
-
-    , fireListener = W3C_MODEL ? function (isNative, type, element) {
-        var evt = doc.createEvent(isNative ? 'HTMLEvents' : 'UIEvents')
-        evt[isNative ? 'initEvent' : 'initUIEvent'](type, true, true, win, 1)
-        element.dispatchEvent(evt)
-      } : function (isNative, type, element) {
-        element = targetElement(element, isNative)
-        // if not-native then we're using onpropertychange so we just increment a custom property
-        isNative ? element.fireEvent('on' + type, doc.createEventObject()) : element['_on' + type]++
-      }
-
-    , fire = function (element, type, args) {
-        var i, j, l, names, handlers
-          , types = type.split(' ')
-
-        for (i = types.length; i--;) {
-          type = types[i].replace(nameRegex, '')
-          if (names = types[i].replace(namespaceRegex, ''))
-            names = names.split('.')
-          if (!names && !args && element[eventSupport]) {
-            fireListener(nativeEvents[type], type, element)
-          } else {
-            // non-native event, either because of a namespace, arguments or a non DOM element
-            // iterate over all listeners and manually 'fire'
-            handlers = registry.get(element, type)
-            args = [false].concat(args)
-            for (j = 0, l = handlers.length; j < l; j++) {
-              if (handlers[j].inNamespaces(names))
-                handlers[j].handler.apply(element, args)
-            }
-          }
-        }
-        return element
-      }
-
-    , clone = function (element, from, type) {
-        var i = 0
-          , handlers = registry.get(from, type)
-          , l = handlers.length
-
-        for (;i < l; i++)
-          handlers[i].original && add(element, handlers[i].type, handlers[i].original)
-        return element
-      }
-
-    , bean = {
-          add: add
-        , one: one
-        , remove: remove
-        , clone: clone
-        , fire: fire
-        , noConflict: function () {
-            context[name] = old
-            return this
-          }
-      }
-
-  if (win[attachEvent]) {
-    // for IE, clean up on unload to avoid leaks
-    var cleanup = function () {
-      var i, entries = registry.entries()
-      for (i in entries) {
-        if (entries[i].type && entries[i].type !== 'unload')
-          remove(entries[i].element, entries[i].type)
-      }
-      win[detachEvent]('onunload', cleanup)
-      win.CollectGarbage && win.CollectGarbage()
+                , entries = function () {
+                    var t, entries = []
+                    for (t in map) {
+                        if (t.charAt(0) === '$')
+                            entries = entries.concat(map[t])
+                    }
+                    return entries
+                }
+
+            return { has: has, get: get, put: put, del: del, entries: entries }
+        })()
+
+    // add and remove listeners to DOM elements
+        , listener = W3C_MODEL ? function (element, type, fn, add) {
+            element[add ? addEvent : removeEvent](type, fn, false)
+        } : function (element, type, fn, add, custom) {
+            if (custom && add && element['_on' + custom] === null)
+                element['_on' + custom] = 0
+            element[add ? attachEvent : detachEvent]('on' + type, fn)
+        }
+
+        , nativeHandler = function (element, fn, args) {
+            return function (event) {
+                event = fixEvent(event || ((this.ownerDocument || this.document || this).parentWindow || win).event, true)
+                return fn.apply(element, [event].concat(args))
+            }
+        }
+
+        , customHandler = function (element, fn, type, condition, args, isNative) {
+            return function (event) {
+                if (condition ? condition.apply(this, arguments) : W3C_MODEL ? true : event && event.propertyName === '_on' + type || !event) {
+                    if (event)
+                        event = fixEvent(event || ((this.ownerDocument || this.document || this).parentWindow || win).event, isNative)
+                    fn.apply(element, event && (!args || args.length === 0) ? arguments : slice.call(arguments, event ? 0 : 1).concat(args))
+                }
+            }
+        }
+
+        , once = function (rm, element, type, fn, originalFn) {
+            // wrap the handler in a handler that does a remove as well
+            return function () {
+                rm(element, type, originalFn)
+                fn.apply(this, arguments)
+            }
+        }
+
+        , removeListener = function (element, orgType, handler, namespaces) {
+            var i, l, entry
+                , type = (orgType && orgType.replace(nameRegex, ''))
+                , handlers = registry.get(element, type, handler)
+
+            for (i = 0, l = handlers.length; i < l; i++) {
+                if (handlers[i].inNamespaces(namespaces)) {
+                    if ((entry = handlers[i]).eventSupport)
+                        listener(entry.target, entry.eventType, entry.handler, false, entry.type)
+                    // TODO: this is problematic, we have a registry.get() and registry.del() that
+                    // both do registry searches so we waste cycles doing this. Needs to be rolled into
+                    // a single registry.forAll(fn) that removes while finding, but the catch is that
+                    // we'll be splicing the arrays that we're iterating over. Needs extra tests to
+                    // make sure we don't screw it up. @rvagg
+                    registry.del(entry)
+                }
+            }
+        }
+
+        , addListener = function (element, orgType, fn, originalFn, args) {
+            var entry
+                , type = orgType.replace(nameRegex, '')
+                , namespaces = orgType.replace(namespaceRegex, '').split('.')
+
+            if (registry.has(element, type, fn))
+                return element // no dupe
+            if (type === 'unload')
+                fn = once(removeListener, element, type, fn, originalFn) // self clean-up
+            if (customEvents[type]) {
+                if (customEvents[type].condition)
+                    fn = customHandler(element, fn, type, customEvents[type].condition, true)
+                type = customEvents[type].base || type
+            }
+            entry = registry.put(new RegEntry(element, type, fn, originalFn, namespaces[0] && namespaces))
+            entry.handler = entry.isNative ?
+                nativeHandler(element, entry.handler, args) :
+                customHandler(element, entry.handler, type, false, args, false)
+            if (entry.eventSupport)
+                listener(entry.target, entry.eventType, entry.handler, true, entry.customType)
+        }
+
+        , del = function (selector, fn, $) {
+            return function (e) {
+                var target, i, array = typeof selector === 'string' ? $(selector, this) : selector
+                for (target = e.target; target && target !== this; target = target.parentNode) {
+                    for (i = array.length; i--;) {
+                        if (array[i] === target) {
+                            return fn.apply(target, arguments)
+                        }
+                    }
+                }
+            }
+        }
+
+        , remove = function (element, typeSpec, fn) {
+            var k, m, type, namespaces, i
+                , rm = removeListener
+                , isString = typeSpec && typeof typeSpec === 'string'
+
+            if (isString && typeSpec.indexOf(' ') > 0) {
+                // remove(el, 't1 t2 t3', fn) or remove(el, 't1 t2 t3')
+                typeSpec = typeSpec.split(' ')
+                for (i = typeSpec.length; i--;)
+                    remove(element, typeSpec[i], fn)
+                return element
+            }
+            type = isString && typeSpec.replace(nameRegex, '')
+            if (type && customEvents[type])
+                type = customEvents[type].type
+            if (!typeSpec || isString) {
+                // remove(el) or remove(el, t1.ns) or remove(el, .ns) or remove(el, .ns1.ns2.ns3)
+                if (namespaces = isString && typeSpec.replace(namespaceRegex, ''))
+                    namespaces = namespaces.split('.')
+                rm(element, type, fn, namespaces)
+            } else if (typeof typeSpec === 'function') {
+                // remove(el, fn)
+                rm(element, null, typeSpec)
+            } else {
+                // remove(el, { t1: fn1, t2, fn2 })
+                for (k in typeSpec) {
+                    if (typeSpec.hasOwnProperty(k))
+                        remove(element, k, typeSpec[k])
+                }
+            }
+            return element
+        }
+
+        , add = function (element, events, fn, delfn, $) {
+            var type, types, i, args
+                , originalFn = fn
+                , isDel = fn && typeof fn === 'string'
+
+            if (events && !fn && typeof events === 'object') {
+                for (type in events) {
+                    if (events.hasOwnProperty(type))
+                        add.apply(this, [ element, type, events[type] ])
+                }
+            } else {
+                args = arguments.length > 3 ? slice.call(arguments, 3) : []
+                types = (isDel ? fn : events).split(' ')
+                isDel && (fn = del(events, (originalFn = delfn), $)) && (args = slice.call(args, 1))
+                // special case for one()
+                this === ONE && (fn = once(remove, element, events, fn, originalFn))
+                for (i = types.length; i--;) addListener(element, types[i], fn, originalFn, args)
+            }
+            return element
+        }
+
+        , one = function () {
+            return add.apply(ONE, arguments)
+        }
+
+        , fireListener = W3C_MODEL ? function (isNative, type, element) {
+            var evt = doc.createEvent(isNative ? 'HTMLEvents' : 'UIEvents')
+            evt[isNative ? 'initEvent' : 'initUIEvent'](type, true, true, win, 1)
+            element.dispatchEvent(evt)
+        } : function (isNative, type, element) {
+            element = targetElement(element, isNative)
+            // if not-native then we're using onpropertychange so we just increment a custom property
+            isNative ? element.fireEvent('on' + type, doc.createEventObject()) : element['_on' + type]++
+        }
+
+        , fire = function (element, type, args) {
+            var i, j, l, names, handlers
+                , types = type.split(' ')
+
+            for (i = types.length; i--;) {
+                type = types[i].replace(nameRegex, '')
+                if (names = types[i].replace(namespaceRegex, ''))
+                    names = names.split('.')
+                if (!names && !args && element[eventSupport]) {
+                    fireListener(nativeEvents[type], type, element)
+                } else {
+                    // non-native event, either because of a namespace, arguments or a non DOM element
+                    // iterate over all listeners and manually 'fire'
+                    handlers = registry.get(element, type)
+                    args = [false].concat(args)
+                    for (j = 0, l = handlers.length; j < l; j++) {
+                        if (handlers[j].inNamespaces(names))
+                            handlers[j].handler.apply(element, args)
+                    }
+                }
+            }
+            return element
+        }
+
+        , clone = function (element, from, type) {
+            var i = 0
+                , handlers = registry.get(from, type)
+                , l = handlers.length
+
+            for (; i < l; i++)
+                handlers[i].original && add(element, handlers[i].type, handlers[i].original)
+            return element
+        }
+
+        , bean = {
+            add: add, one: one, remove: remove, clone: clone, fire: fire, noConflict: function () {
+                context[name] = old
+                return this
+            }
+        }
+
+    if (win[attachEvent]) {
+        // for IE, clean up on unload to avoid leaks
+        var cleanup = function () {
+            var i, entries = registry.entries()
+            for (i in entries) {
+                if (entries[i].type && entries[i].type !== 'unload')
+                    remove(entries[i].element, entries[i].type)
+            }
+            win[detachEvent]('onunload', cleanup)
+            win.CollectGarbage && win.CollectGarbage()
+        }
+        win[attachEvent]('onunload', cleanup)
     }
-    win[attachEvent]('onunload', cleanup)
-  }
-
-  return bean
+
+    return bean
 });
 //     Underscore.js 1.1.7
 //     (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.
@@ -509,835 +504,851 @@
 //     For all details and documentation:
 //     http://documentcloud.github.com/underscore
 
-(function() {
-
-  // Baseline setup
-  // --------------
-
-  // Establish the root object, `window` in the browser, or `global` on the server.
-  var root = this;
-
-  // Save the previous value of the `_` variable.
-  var previousUnderscore = root._;
-
-  // Establish the object that gets returned to break out of a loop iteration.
-  var breaker = {};
-
-  // Save bytes in the minified (but not gzipped) version:
-  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
-
-  // Create quick reference variables for speed access to core prototypes.
-  var slice            = ArrayProto.slice,
-      unshift          = ArrayProto.unshift,
-      toString         = ObjProto.toString,
-      hasOwnProperty   = ObjProto.hasOwnProperty;
-
-  // All **ECMAScript 5** native function implementations that we hope to use
-  // are declared here.
-  var
-    nativeForEach      = ArrayProto.forEach,
-    nativeMap          = ArrayProto.map,
-    nativeReduce       = ArrayProto.reduce,
-    nativeReduceRight  = ArrayProto.reduceRight,
-    nativeFilter       = ArrayProto.filter,
-    nativeEvery        = ArrayProto.every,
-    nativeSome         = ArrayProto.some,
-    nativeIndexOf      = ArrayProto.indexOf,
-    nativeLastIndexOf  = ArrayProto.lastIndexOf,
-    nativeIsArray      = Array.isArray,
-    nativeKeys         = Object.keys,
-    nativeBind         = FuncProto.bind;
-
-  // Create a safe reference to the Underscore object for use below.
-  var _ = function(obj) { return new wrapper(obj); };
-
-  // Export the Underscore object for **CommonJS**, with backwards-compatibility
-  // for the old `require()` API. If we're not in CommonJS, add `_` to the
-  // global object.
-  if (typeof module !== 'undefined' && module.exports) {
-    module.exports = _;
-    _._ = _;
-  } else {
-    // Exported as a string, for Closure Compiler "advanced" mode.
-    root['_'] = _;
-  }
-
-  // Current version.
-  _.VERSION = '1.1.7';
-
-  // Collection Functions
-  // --------------------
-
-  // The cornerstone, an `each` implementation, aka `forEach`.
-  // Handles objects with the built-in `forEach`, arrays, and raw objects.
-  // Delegates to **ECMAScript 5**'s native `forEach` if available.
-  var each = _.each = _.forEach = function(obj, iterator, context) {
-    if (obj == null) return;
-    if (nativeForEach && obj.forEach === nativeForEach) {
-      obj.forEach(iterator, context);
-    } else if (obj.length === +obj.length) {
-      for (var i = 0, l = obj.length; i < l; i++) {
-        if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
-      }
+(function () {
+
+    // Baseline setup
+    // --------------
+
+    // Establish the root object, `window` in the browser, or `global` on the server.
+    var root = this;
+
+    // Save the previous value of the `_` variable.
+    var previousUnderscore = root._;
+
+    // Establish the object that gets returned to break out of a loop iteration.
+    var breaker = {};
+
+    // Save bytes in the minified (but not gzipped) version:
+    var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
+
+    // Create quick reference variables for speed access to core prototypes.
+    var slice = ArrayProto.slice,
+        unshift = ArrayProto.unshift,
+        toString = ObjProto.toString,
+        hasOwnProperty = ObjProto.hasOwnProperty;
+
+    // All **ECMAScript 5** native function implementations that we hope to use
+    // are declared here.
+    var
+        nativeForEach = ArrayProto.forEach,
+        nativeMap = ArrayProto.map,
+        nativeReduce = ArrayProto.reduce,
+        nativeReduceRight = ArrayProto.reduceRight,
+        nativeFilter = ArrayProto.filter,
+        nativeEvery = ArrayProto.every,
+        nativeSome = ArrayProto.some,
+        nativeIndexOf = ArrayProto.indexOf,
+        nativeLastIndexOf = ArrayProto.lastIndexOf,
+        nativeIsArray = Array.isArray,
+        nativeKeys = Object.keys,
+        nativeBind = FuncProto.bind;
+
+    // Create a safe reference to the Underscore object for use below.
+    var _ = function (obj) {
+        return new wrapper(obj);
+    };
+
+    // Export the Underscore object for **CommonJS**, with backwards-compatibility
+    // for the old `require()` API. If we're not in CommonJS, add `_` to the
+    // global object.
+    if (typeof module !== 'undefined' && module.exports) {
+        module.exports = _;
+        _._ = _;
     } else {
-      for (var key in obj) {
-        if (hasOwnProperty.call(obj, key)) {
-          if (iterator.call(context, obj[key], key, obj) === breaker) return;
-        }
-      }
+        // Exported as a string, for Closure Compiler "advanced" mode.
+        root['_'] = _;
     }
-  };
-
-  // Return the results of applying the iterator to each element.
-  // Delegates to **ECMAScript 5**'s native `map` if available.
-  _.map = function(obj, iterator, context) {
-    var results = [];
-    if (obj == null) return results;
-    if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
-    each(obj, function(value, index, list) {
-      results[results.length] = iterator.call(context, value, index, list);
+
+    // Current version.
+    _.VERSION = '1.1.7';
+
+    // Collection Functions
+    // --------------------
+
+    // The cornerstone, an `each` implementation, aka `forEach`.
+    // Handles objects with the built-in `forEach`, arrays, and raw objects.
+    // Delegates to **ECMAScript 5**'s native `forEach` if available.
+    var each = _.each = _.forEach = function (obj, iterator, context) {
+        if (obj == null) return;
+        if (nativeForEach && obj.forEach === nativeForEach) {
+            obj.forEach(iterator, context);
+        } else if (obj.length === +obj.length) {
+            for (var i = 0, l = obj.length; i < l; i++) {
+                if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
+            }
+        } else {
+            for (var key in obj) {
+                if (hasOwnProperty.call(obj, key)) {
+                    if (iterator.call(context, obj[key], key, obj) === breaker) return;
+                }
+            }
+        }
+    };
+
+    // Return the results of applying the iterator to each element.
+    // Delegates to **ECMAScript 5**'s native `map` if available.
+    _.map = function (obj, iterator, context) {
+        var results = [];
+        if (obj == null) return results;
+        if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
+        each(obj, function (value, index, list) {
+            results[results.length] = iterator.call(context, value, index, list);
+        });
+        return results;
+    };
+
+    // **Reduce** builds up a single result from a list of values, aka `inject`,
+    // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
+    _.reduce = _.foldl = _.inject = function (obj, iterator, memo, context) {
+        var initial = memo !== void 0;
+        if (obj == null) obj = [];
+        if (nativeReduce && obj.reduce === nativeReduce) {
+            if (context) iterator = _.bind(iterator, context);
+            return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
+        }
+        each(obj, function (value, index, list) {
+            if (!initial) {
+                memo = value;
+                initial = true;
+            } else {
+                memo = iterator.call(context, memo, value, index, list);
+            }
+        });
+        if (!initial) throw new TypeError("Reduce of empty array with no initial value");
+        return memo;
+    };
+
+    // The right-associative version of reduce, also known as `foldr`.
+    // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
+    _.reduceRight = _.foldr = function (obj, iterator, memo, context) {
+        if (obj == null) obj = [];
+        if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
+            if (context) iterator = _.bind(iterator, context);
+            return memo !== void 0 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
+        }
+        var reversed = (_.isArray(obj) ? obj.slice() : _.toArray(obj)).reverse();
+        return _.reduce(reversed, iterator, memo, context);
+    };
+
+    // Return the first value which passes a truth test. Aliased as `detect`.
+    _.find = _.detect = function (obj, iterator, context) {
+        var result;
+        any(obj, function (value, index, list) {
+            if (iterator.call(context, value, index, list)) {
+                result = value;
+                return true;
+            }
+        });
+        return result;
+    };
+
+    // Return all the elements that pass a truth test.
+    // Delegates to **ECMAScript 5**'s native `filter` if available.
+    // Aliased as `select`.
+    _.filter = _.select = function (obj, iterator, context) {
+        var results = [];
+        if (obj == null) return results;
+        if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
+        each(obj, function (value, index, list) {
+            if (iterator.call(context, value, index, list)) results[results.length] = value;
+        });
+        return results;
+    };
+
+    // Return all the elements for which a truth test fails.
+    _.reject = function (obj, iterator, context) {
+        var results = [];
+        if (obj == null) return results;
+        each(obj, function (value, index, list) {
+            if (!iterator.call(context, value, index, list)) results[results.length] = value;
+        });
+        return results;
+    };
+
+    // Determine whether all of the elements match a truth test.
+    // Delegates to **ECMAScript 5**'s native `every` if available.
+    // Aliased as `all`.
+    _.every = _.all = function (obj, iterator, context) {
+        var result = true;
+        if (obj == null) return result;
+        if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
+        each(obj, function (value, index, list) {
+            if (!(result = result && iterator.call(context, value, index, list))) return breaker;
+        });
+        return result;
+    };
+
+    // Determine if at least one element in the object matches a truth test.
+    // Delegates to **ECMAScript 5**'s native `some` if available.
+    // Aliased as `any`.
+    var any = _.some = _.any = function (obj, iterator, context) {
+        iterator = iterator || _.identity;
+        var result = false;
+        if (obj == null) return result;
+        if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
+        each(obj, function (value, index, list) {
+            if (result |= iterator.call(context, value, index, list)) return breaker;
+        });
+        return !!result;
+    };
+
+    // Determine if a given value is included in the array or object using `===`.
+    // Aliased as `contains`.
+    _.include = _.contains = function (obj, target) {
+        var found = false;
+        if (obj == null) return found;
+        if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
+        any(obj, function (value) {
+            if (found = value === target) return true;
+        });
+        return found;
+    };
+
+    // Invoke a method (with arguments) on every item in a collection.
+    _.invoke = function (obj, method) {
+        var args = slice.call(arguments, 2);
+        return _.map(obj, function (value) {
+            return (method.call ? method || value : value[method]).apply(value, args);
+        });
+    };
+
+    // Convenience version of a common use case of `map`: fetching a property.
+    _.pluck = function (obj, key) {
+        return _.map(obj, function (value) {
+            return value[key];
+        });
+    };
+
+    // Return the maximum element or (element-based computation).
+    _.max = function (obj, iterator, context) {
+        if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
+        var result = {computed: -Infinity};
+        each(obj, function (value, index, list) {
+            var computed = iterator ? iterator.call(context, value, index, list) : value;
+            computed >= result.computed && (result = {value: value, computed: computed});
+        });
+        return result.value;
+    };
+
+    // Return the minimum element (or element-based computation).
+    _.min = function (obj, iterator, context) {
+        if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
+        var result = {computed: Infinity};
+        each(obj, function (value, index, list) {
+            var computed = iterator ? iterator.call(context, value, index, list) : value;
+            computed < result.computed && (result = {value: value, computed: computed});
+        });
+        return result.value;
+    };
+
+    // Sort the object's values by a criterion produced by an iterator.
+    _.sortBy = function (obj, iterator, context) {
+        return _.pluck(_.map(obj,function (value, index, list) {
+            return {
+                value: value,
+                criteria: iterator.call(context, value, index, list)
+            };
+        }).sort(function (left, right) {
+                var a = left.criteria, b = right.criteria;
+                return a < b ? -1 : a > b ? 1 : 0;
+            }), 'value');
+    };
+
+    // Groups the object's values by a criterion produced by an iterator
+    _.groupBy = function (obj, iterator) {
+        var result = {};
+        each(obj, function (value, index) {
+            var key = iterator(value, index);
+            (result[key] || (result[key] = [])).push(value);
+        });
+        return result;
+    };
+
+    // Use a comparator function to figure out at what index an object should
+    // be inserted so as to maintain order. Uses binary search.
+    _.sortedIndex = function (array, obj, iterator) {
+        iterator || (iterator = _.identity);
+        var low = 0, high = array.length;
+        while (low < high) {
+            var mid = (low + high) >> 1;
+            iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
+        }
+        return low;
+    };
+
+    // Safely convert anything iterable into a real, live array.
+    _.toArray = function (iterable) {
+        if (!iterable)                return [];
+        if (iterable.toArray)         return iterable.toArray();
+        if (_.isArray(iterable))      return slice.call(iterable);
+        if (_.isArguments(iterable))  return slice.call(iterable);
+        return _.values(iterable);
+    };
+
+    // Return the number of elements in an object.
+    _.size = function (obj) {
+        return _.toArray(obj).length;
+    };
+
+    // Array Functions
+    // ---------------
+
+    // Get the first element of an array. Passing **n** will return the first N
+    // values in the array. Aliased as `head`. The **guard** check allows it to work
+    // with `_.map`.
+    _.first = _.head = function (array, n, guard) {
+        return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
+    };
+
+    // Returns everything but the first entry of the array. Aliased as `tail`.
+    // Especially useful on the arguments object. Passing an **index** will return
+    // the rest of the values in the array from that index onward. The **guard**
+    // check allows it to work with `_.map`.
+    _.rest = _.tail = function (array, index, guard) {
+        return slice.call(array, (index == null) || guard ? 1 : index);
+    };
+
+    // Get the last element of an array.
+    _.last = function (array) {
+        return array[array.length - 1];
+    };
+
+    // Trim out all falsy values from an array.
+    _.compact = function (array) {
+        return _.filter(array, function (value) {
+            return !!value;
+        });
+    };
+
+    // Return a completely flattened version of an array.
+    _.flatten = function (array) {
+        return _.reduce(array, function (memo, value) {
+            if (_.isArray(value)) return memo.concat(_.flatten(value));
+            memo[memo.length] = value;
+            return memo;
+        }, []);
+    };
+
+    // Return a version of the array that does not contain the specified value(s).
+    _.without = function (array) {
+        return _.difference(array, slice.call(arguments, 1));
+    };
+
+    // Produce a duplicate-free version of the array. If the array has already
+    // been sorted, you have the option of using a faster algorithm.
+    // Aliased as `unique`.
+    _.uniq = _.unique = function (array, isSorted) {
+        return _.reduce(array, function (memo, el, i) {
+            if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo[memo.length] = el;
+            return memo;
+        }, []);
+    };
+
+    // Produce an array that contains the union: each distinct element from all of
+    // the passed-in arrays.
+    _.union = function () {
+        return _.uniq(_.flatten(arguments));
+    };
+
+    // Produce an array that contains every item shared between all the
+    // passed-in arrays. (Aliased as "intersect" for back-compat.)
+    _.intersection = _.intersect = function (array) {
+        var rest = slice.call(arguments, 1);
+        return _.filter(_.uniq(array), function (item) {
+            return _.every(rest, function (other) {
+                return _.indexOf(other, item) >= 0;
+            });
+        });
+    };
+
+    // Take the difference between one array and another.
+    // Only the elements present in just the first array will remain.
+    _.difference = function (array, other) {
+        return _.filter(array, function (value) {
+            return !_.include(other, value);
+        });
+    };
+
+    // Zip together multiple lists into a single array -- elements that share
+    // an index go together.
+    _.zip = function () {
+        var args = slice.call(arguments);
+        var length = _.max(_.pluck(args, 'length'));
+        var results = new Array(length);
+        for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i);
+        return results;
+    };
+
+    // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
+    // we need this function. Return the position of the first occurrence of an
+    // item in an array, or -1 if the item is not included in the array.
+    // Delegates to **ECMAScript 5**'s native `indexOf` if available.
+    // If the array is large and already in sort order, pass `true`
+    // for **isSorted** to use binary search.
+    _.indexOf = function (array, item, isSorted) {
+        if (array == null) return -1;
+        var i, l;
+        if (isSorted) {
+            i = _.sortedIndex(array, item);
+            return array[i] === item ? i : -1;
+        }
+        if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
+        for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
+        return -1;
+    };
+
+
+    // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
+    _.lastIndexOf = function (array, item) {
+        if (array == null) return -1;
+        if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
+        var i = array.length;
+        while (i--) if (array[i] === item) return i;
+        return -1;
+    };
+
+    // Generate an integer Array containing an arithmetic progression. A port of
+    // the native Python `range()` function. See
+    // [the Python documentation](http://docs.python.org/library/functions.html#range).
+    _.range = function (start, stop, step) {
+        if (arguments.length <= 1) {
+            stop = start || 0;
+            start = 0;
+        }
+        step = arguments[2] || 1;
+
+        var len = Math.max(Math.ceil((stop - start) / step), 0);
+        var idx = 0;
+        var range = new Array(len);
+
+        while (idx < len) {
+            range[idx++] = start;
+            start += step;
+        }
+
+        return range;
+    };
+
+    // Function (ahem) Functions
+    // ------------------
+
+    // Create a function bound to a given object (assigning `this`, and arguments,
+    // optionally). Binding with arguments is also known as `curry`.
+    // Delegates to **ECMAScript 5**'s native `Function.bind` if available.
+    // We check for `func.bind` first, to fail fast when `func` is undefined.
+    _.bind = function (func, obj) {
+        if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
+        var args = slice.call(arguments, 2);
+        return function () {
+            return func.apply(obj, args.concat(slice.call(arguments)));
+        };
+    };
+
+    // Bind all of an object's methods to that object. Useful for ensuring that
+    // all callbacks defined on an object belong to it.
+    _.bindAll = function (obj) {
+        var funcs = slice.call(arguments, 1);
+        if (funcs.length == 0) funcs = _.functions(obj);
+        each(funcs, function (f) {
+            obj[f] = _.bind(obj[f], obj);
+        });
+        return obj;
+    };
+
+    // Memoize an expensive function by storing its results.
+    _.memoize = function (func, hasher) {
+        var memo = {};
+        hasher || (hasher = _.identity);
+        return function () {
+            var key = hasher.apply(this, arguments);
+            return hasOwnProperty.call(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
+        };
+    };
+
+    // Delays a function for the given number of milliseconds, and then calls
+    // it with the arguments supplied.
+    _.delay = function (func, wait) {
+        var args = slice.call(arguments, 2);
+        return setTimeout(function () {
+            return func.apply(func, args);
+        }, wait);
+    };
+
+    // Defers a function, scheduling it to run after the current call stack has
+    // cleared.
+    _.defer = function (func) {
+        return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
+    };
+
+    // Internal function used to implement `_.throttle` and `_.debounce`.
+    var limit = function (func, wait, debounce) {
+        var timeout;
+        return function () {
+            var context = this, args = arguments;
+            var throttler = function () {
+                timeout = null;
+                func.apply(context, args);
+            };
+            if (debounce) clearTimeout(timeout);
+            if (debounce || !timeout) timeout = setTimeout(throttler, wait);
+        };
+    };
+
+    // Returns a function, that, when invoked, will only be triggered at most once
+    // during a given window of time.
+    _.throttle = function (func, wait) {
+        return limit(func, wait, false);
+    };
+
+    // Returns a function, that, as long as it continues to be invoked, will not
+    // be triggered. The function will be called after it stops being called for
+    // N milliseconds.
+    _.debounce = function (func, wait) {
+        return limit(func, wait, true);
+    };
+
+    // Returns a function that will be executed at most one time, no matter how
+    // often you call it. Useful for lazy initialization.
+    _.once = function (func) {
+        var ran = false, memo;
+        return function () {
+            if (ran) return memo;
+            ran = true;
+            return memo = func.apply(this, arguments);
+        };
+    };
+
+    // Returns the first function passed as an argument to the second,
+    // allowing you to adjust arguments, run code before and after, and
+    // conditionally execute the original function.
+    _.wrap = function (func, wrapper) {
+        return function () {
+            var args = [func].concat(slice.call(arguments));
+            return wrapper.apply(this, args);
+        };
+    };
+
+    // Returns a function that is the composition of a list of functions, each
+    // consuming the return value of the function that follows.
+    _.compose = function () {
+        var funcs = slice.call(arguments);
+        return function () {
+            var args = slice.call(arguments);
+            for (var i = funcs.length - 1; i >= 0; i--) {
+                args = [funcs[i].apply(this, args)];
+            }
+            return args[0];
+        };
+    };
+
+    // Returns a function that will only be executed after being called N times.
+    _.after = function (times, func) {
+        return function () {
+            if (--times < 1) {
+                return func.apply(this, arguments);
+            }
+        };
+    };
+
+
+    // Object Functions
+    // ----------------
+
+    // Retrieve the names of an object's properties.
+    // Delegates to **ECMAScript 5**'s native `Object.keys`
+    _.keys = nativeKeys || function (obj) {
+        if (obj !== Object(obj)) throw new TypeError('Invalid object');
+        var keys = [];
+        for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key;
+        return keys;
+    };
+
+    // Retrieve the values of an object's properties.
+    _.values = function (obj) {
+        return _.map(obj, _.identity);
+    };
+
+    // Return a sorted list of the function names available on the object.
+    // Aliased as `methods`
+    _.functions = _.methods = function (obj) {
+        var names = [];
+        for (var key in obj) {
+            if (_.isFunction(obj[key])) names.push(key);
+        }
+        return names.sort();
+    };
+
+    // Extend a given object with all the properties in passed-in object(s).
+    _.extend = function (obj) {
+        each(slice.call(arguments, 1), function (source) {
+            for (var prop in source) {
+                if (source[prop] !== void 0) obj[prop] = source[prop];
+            }
+        });
+        return obj;
+    };
+
+    // Fill in a given object with default properties.
+    _.defaults = function (obj) {
+        each(slice.call(arguments, 1), function (source) {
+            for (var prop in source) {
+                if (obj[prop] == null) obj[prop] = source[prop];
+            }
+        });
+        return obj;
+    };
+
+    // Create a (shallow-cloned) duplicate of an object.
+    _.clone = function (obj) {
+        return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
+    };
+
+    // Invokes interceptor with the obj, and then returns obj.
+    // The primary purpose of this method is to "tap into" a method chain, in
+    // order to perform operations on intermediate results within the chain.
+    _.tap = function (obj, interceptor) {
+        interceptor(obj);
+        return obj;
+    };
+
+    // Perform a deep comparison to check if two objects are equal.
+    _.isEqual = function (a, b) {
+        // Check object identity.
+        if (a === b) return true;
+        // Different types?
+        var atype = typeof(a), btype = typeof(b);
+        if (atype != btype) return false;
+        // Basic equality test (watch out for coercions).
+        if (a == b) return true;
+        // One is falsy and the other truthy.
+        if ((!a && b) || (a && !b)) return false;
+        // Unwrap any wrapped objects.
+        if (a._chain) a = a._wrapped;
+        if (b._chain) b = b._wrapped;
+        // One of them implements an isEqual()?
+        if (a.isEqual) return a.isEqual(b);
+        if (b.isEqual) return b.isEqual(a);
+        // Check dates' integer values.
+        if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();
+        // Both are NaN?
+        if (_.isNaN(a) && _.isNaN(b)) return false;
+        // Compare regular expressions.
+        if (_.isRegExp(a) && _.isRegExp(b))
+            return a.source === b.source &&
+                a.global === b.global &&
+                a.ignoreCase === b.ignoreCase &&
+                a.multiline === b.multiline;
+        // If a is not an object by this point, we can't handle it.
+        if (atype !== 'object') return false;
+        // Check for different array lengths before comparing contents.
+        if (a.length && (a.length !== b.length)) return false;
+        // Nothing else worked, deep compare the contents.
+        var aKeys = _.keys(a), bKeys = _.keys(b);
+        // Different object sizes?
+        if (aKeys.length != bKeys.length) return false;
+        // Recursive comparison of contents.
+        for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false;
+        return true;
+    };
+
+    // Is a given array or object empty?
+    _.isEmpty = function (obj) {
+        if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
+        for (var key in obj) if (hasOwnProperty.call(obj, key)) return false;
+        return true;
+    };
+
+    // Is a given value a DOM element?
+    _.isElement = function (obj) {
+        return !!(obj && obj.nodeType == 1);
+    };
+
+    // Is a given value an array?
+    // Delegates to ECMA5's native Array.isArray
+    _.isArray = nativeIsArray || function (obj) {
+        return toString.call(obj) === '[object Array]';
+    };
+
+    // Is a given variable an object?
+    _.isObject = function (obj) {
+        return obj === Object(obj);
+    };
+
+    // Is a given variable an arguments object?
+    _.isArguments = function (obj) {
+        return !!(obj && hasOwnProperty.call(obj, 'callee'));
+    };
+
+    // Is a given value a function?
+    _.isFunction = function (obj) {
+        return !!(obj && obj.constructor && obj.call && obj.apply);
+    };
+
+    // Is a given value a string?
+    _.isString = function (obj) {
+        return !!(obj === '' || (obj && obj.charCodeAt && obj.substr));
+    };
+
+    // Is a given value a number?
+    _.isNumber = function (obj) {
+        return !!(obj === 0 || (obj && obj.toExponential && obj.toFixed));
+    };
+
+    // Is the given value `NaN`? `NaN` happens to be the only value in JavaScript
+    // that does not equal itself.
+    _.isNaN = function (obj) {
+        return obj !== obj;
+    };
+
+    // Is a given value a boolean?
+    _.isBoolean = function (obj) {
+        return obj === true || obj === false;
+    };
+
+    // Is a given value a date?
+    _.isDate = function (obj) {
+        return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear);
+    };
+
+    // Is the given value a regular expression?
+    _.isRegExp = function (obj) {
+        return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false));
+    };
+
+    // Is a given value equal to null?
+    _.isNull = function (obj) {
+        return obj === null;
+    };
+
+    // Is a given variable undefined?
+    _.isUndefined = function (obj) {
+        return obj === void 0;
+    };
+
+    // Utility Functions
+    // -----------------
+
+    // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
+    // previous owner. Returns a reference to the Underscore object.
+    _.noConflict = function () {
+        root._ = previousUnderscore;
+        return this;
+    };
+
+    // Keep the identity function around for default iterators.
+    _.identity = function (value) {
+        return value;
+    };
+
+    // Run a function **n** times.
+    _.times = function (n, iterator, context) {
+        for (var i = 0; i < n; i++) iterator.call(context, i);
+    };
+
+    // Add your own custom functions to the Underscore object, ensuring that
+    // they're correctly added to the OOP wrapper as well.
+    _.mixin = function (obj) {
+        each(_.functions(obj), function (name) {
+            addToWrapper(name, _[name] = obj[name]);
+        });
+    };
+
+    // Generate a unique integer id (unique within the entire client session).
+    // Useful for temporary DOM ids.
+    var idCounter = 0;
+    _.uniqueId = function (prefix) {
+        var id = idCounter++;
+        return prefix ? prefix + id : id;
+    };
+
+    // By default, Underscore uses ERB-style template delimiters, change the
+    // following template settings to use alternative delimiters.
+    _.templateSettings = {
+        evaluate: /<%([\s\S]+?)%>/g,
+        interpolate: /<%=([\s\S]+?)%>/g
+    };
+
+    // JavaScript micro-templating, similar to John Resig's implementation.
+    // Underscore templating handles arbitrary delimiters, preserves whitespace,
+    // and correctly escapes quotes within interpolated code.
+    _.template = function (str, data) {
+        var c = _.templateSettings;
+        var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
+            'with(obj||{}){__p.push(\'' +
+            str.replace(/\\/g, '\\\\')
+                .replace(/'/g, "\\'")
+                .replace(c.interpolate, function (match, code) {
+                    return "'," + code.replace(/\\'/g, "'") + ",'";
+                })
+                .replace(c.evaluate || null, function (match, code) {
+                    return "');" + code.replace(/\\'/g, "'")
+                        .replace(/[\r\n\t]/g, ' ') + "__p.push('";
+                })
+                .replace(/\r/g, '\\r')
+                .replace(/\n/g, '\\n')
+                .replace(/\t/g, '\\t')
+            + "');}return __p.join('');";
+        var func = new Function('obj', tmpl);
+        return data ? func(data) : func;
+    };
+
+    // The OOP Wrapper
+    // ---------------
+
+    // If Underscore is called as a function, it returns a wrapped object that
+    // can be used OO-style. This wrapper holds altered versions of all the
+    // underscore functions. Wrapped objects may be chained.
+    var wrapper = function (obj) {
+        this._wrapped = obj;
+    };
+
+    // Expose `wrapper.prototype` as `_.prototype`
+    _.prototype = wrapper.prototype;
+
+    // Helper function to continue chaining intermediate results.
+    var result = function (obj, chain) {
+        return chain ? _(obj).chain() : obj;
+    };
+
+    // A method to easily add functions to the OOP wrapper.
+    var addToWrapper = function (name, func) {
+        wrapper.prototype[name] = function () {
+            var args = slice.call(arguments);
+            unshift.call(args, this._wrapped);
+            return result(func.apply(_, args), this._chain);
+        };
+    };
+
+    // Add all of the Underscore functions to the wrapper object.
+    _.mixin(_);
+
+    // Add all mutator Array functions to the wrapper.
+    each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function (name) {
+        var method = ArrayProto[name];
+        wrapper.prototype[name] = function () {
+            method.apply(this._wrapped, arguments);
+            return result(this._wrapped, this._chain);
+        };
     });
-    return results;
-  };
-
-  // **Reduce** builds up a single result from a list of values, aka `inject`,
-  // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
-  _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
-    var initial = memo !== void 0;
-    if (obj == null) obj = [];
-    if (nativeReduce && obj.reduce === nativeReduce) {
-      if (context) iterator = _.bind(iterator, context);
-      return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
-    }
-    each(obj, function(value, index, list) {
-      if (!initial) {
-        memo = value;
-        initial = true;
-      } else {
-        memo = iterator.call(context, memo, value, index, list);
-      }
+
+    // Add all accessor Array functions to the wrapper.
+    each(['concat', 'join', 'slice'], function (name) {
+        var method = ArrayProto[name];
+        wrapper.prototype[name] = function () {
+            return result(method.apply(this._wrapped, arguments), this._chain);
+        };
     });
-    if (!initial) throw new TypeError("Reduce of empty array with no initial value");
-    return memo;
-  };
-
-  // The right-associative version of reduce, also known as `foldr`.
-  // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
-  _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
-    if (obj == null) obj = [];
-    if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
-      if (context) iterator = _.bind(iterator, context);
-      return memo !== void 0 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
-    }
-    var reversed = (_.isArray(obj) ? obj.slice() : _.toArray(obj)).reverse();
-    return _.reduce(reversed, iterator, memo, context);
-  };
-
-  // Return the first value which passes a truth test. Aliased as `detect`.
-  _.find = _.detect = function(obj, iterator, context) {
-    var result;
-    any(obj, function(value, index, list) {
-      if (iterator.call(context, value, index, list)) {
-        result = value;
-        return true;
-      }
-    });
-    return result;
-  };
-
-  // Return all the elements that pass a truth test.
-  // Delegates to **ECMAScript 5**'s native `filter` if available.
-  // Aliased as `select`.
-  _.filter = _.select = function(obj, iterator, context) {
-    var results = [];
-    if (obj == null) return results;
-    if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
-    each(obj, function(value, index, list) {
-      if (iterator.call(context, value, index, list)) results[results.length] = value;
-    });
-    return results;
-  };
-
-  // Return all the elements for which a truth test fails.
-  _.reject = function(obj, iterator, context) {
-    var results = [];
-    if (obj == null) return results;
-    each(obj, function(value, index, list) {
-      if (!iterator.call(context, value, index, list)) results[results.length] = value;
-    });
-    return results;
-  };
-
-  // Determine whether all of the elements match a truth test.
-  // Delegates to **ECMAScript 5**'s native `every` if available.
-  // Aliased as `all`.
-  _.every = _.all = function(obj, iterator, context) {
-    var result = true;
-    if (obj == null) return result;
-    if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
-    each(obj, function(value, index, list) {
-      if (!(result = result && iterator.call(context, value, index, list))) return breaker;
-    });
-    return result;
-  };
-
-  // Determine if at least one element in the object matches a truth test.
-  // Delegates to **ECMAScript 5**'s native `some` if available.
-  // Aliased as `any`.
-  var any = _.some = _.any = function(obj, iterator, context) {
-    iterator = iterator || _.identity;
-    var result = false;
-    if (obj == null) return result;
-    if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
-    each(obj, function(value, index, list) {
-      if (result |= iterator.call(context, value, index, list)) return breaker;
-    });
-    return !!result;
-  };
-
-  // Determine if a given value is included in the array or object using `===`.
-  // Aliased as `contains`.
-  _.include = _.contains = function(obj, target) {
-    var found = false;
-    if (obj == null) return found;
-    if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
-    any(obj, function(value) {
-      if (found = value === target) return true;
-    });
-    return found;
-  };
-
-  // Invoke a method (with arguments) on every item in a collection.
-  _.invoke = function(obj, method) {
-    var args = slice.call(arguments, 2);
-    return _.map(obj, function(value) {
-      return (method.call ? method || value : value[method]).apply(value, args);
-    });
-  };
-
-  // Convenience version of a common use case of `map`: fetching a property.
-  _.pluck = function(obj, key) {
-    return _.map(obj, function(value){ return value[key]; });
-  };
-
-  // Return the maximum element or (element-based computation).
-  _.max = function(obj, iterator, context) {
-    if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
-    var result = {computed : -Infinity};
-    each(obj, function(value, index, list) {
-      var computed = iterator ? iterator.call(context, value, index, list) : value;
-      computed >= result.computed && (result = {value : value, computed : computed});
-    });
-    return result.value;
-  };
-
-  // Return the minimum element (or element-based computation).
-  _.min = function(obj, iterator, context) {
-    if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
-    var result = {computed : Infinity};
-    each(obj, function(value, index, list) {
-      var computed = iterator ? iterator.call(context, value, index, list) : value;
-      computed < result.computed && (result = {value : value, computed : computed});
-    });
-    return result.value;
-  };
-
-  // Sort the object's values by a criterion produced by an iterator.
-  _.sortBy = function(obj, iterator, context) {
-    return _.pluck(_.map(obj, function(value, index, list) {
-      return {
-        value : value,
-        criteria : iterator.call(context, value, index, list)
-      };
-    }).sort(function(left, right) {
-      var a = left.criteria, b = right.criteria;
-      return a < b ? -1 : a > b ? 1 : 0;
-    }), 'value');
-  };
-
-  // Groups the object's values by a criterion produced by an iterator
-  _.groupBy = function(obj, iterator) {
-    var result = {};
-    each(obj, function(value, index) {
-      var key = iterator(value, index);
-      (result[key] || (result[key] = [])).push(value);
-    });
-    return result;
-  };
-
-  // Use a comparator function to figure out at what index an object should
-  // be inserted so as to maintain order. Uses binary search.
-  _.sortedIndex = function(array, obj, iterator) {
-    iterator || (iterator = _.identity);
-    var low = 0, high = array.length;
-    while (low < high) {
-      var mid = (low + high) >> 1;
-      iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
-    }
-    return low;
-  };
-
-  // Safely convert anything iterable into a real, live array.
-  _.toArray = function(iterable) {
-    if (!iterable)                return [];
-    if (iterable.toArray)         return iterable.toArray();
-    if (_.isArray(iterable))      return slice.call(iterable);
-    if (_.isArguments(iterable))  return slice.call(iterable);
-    return _.values(iterable);
-  };
-
-  // Return the number of elements in an object.
-  _.size = function(obj) {
-    return _.toArray(obj).length;
-  };
-
-  // Array Functions
-  // ---------------
-
-  // Get the first element of an array. Passing **n** will return the first N
-  // values in the array. Aliased as `head`. The **guard** check allows it to work
-  // with `_.map`.
-  _.first = _.head = function(array, n, guard) {
-    return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
-  };
-
-  // Returns everything but the first entry of the array. Aliased as `tail`.
-  // Especially useful on the arguments object. Passing an **index** will return
-  // the rest of the values in the array from that index onward. The **guard**
-  // check allows it to work with `_.map`.
-  _.rest = _.tail = function(array, index, guard) {
-    return slice.call(array, (index == null) || guard ? 1 : index);
-  };
-
-  // Get the last element of an array.
-  _.last = function(array) {
-    return array[array.length - 1];
-  };
-
-  // Trim out all falsy values from an array.
-  _.compact = function(array) {
-    return _.filter(array, function(value){ return !!value; });
-  };
-
-  // Return a completely flattened version of an array.
-  _.flatten = function(array) {
-    return _.reduce(array, function(memo, value) {
-      if (_.isArray(value)) return memo.concat(_.flatten(value));
-      memo[memo.length] = value;
-      return memo;
-    }, []);
-  };
-
-  // Return a version of the array that does not contain the specified value(s).
-  _.without = function(array) {
-    return _.difference(array, slice.call(arguments, 1));
-  };
-
-  // Produce a duplicate-free version of the array. If the array has already
-  // been sorted, you have the option of using a faster algorithm.
-  // Aliased as `unique`.
-  _.uniq = _.unique = function(array, isSorted) {
-    return _.reduce(array, function(memo, el, i) {
-      if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo[memo.length] = el;
-      return memo;
-    }, []);
-  };
-
-  // Produce an array that contains the union: each distinct element from all of
-  // the passed-in arrays.
-  _.union = function() {
-    return _.uniq(_.flatten(arguments));
-  };
-
-  // Produce an array that contains every item shared between all the
-  // passed-in arrays. (Aliased as "intersect" for back-compat.)
-  _.intersection = _.intersect = function(array) {
-    var rest = slice.call(arguments, 1);
-    return _.filter(_.uniq(array), function(item) {
-      return _.every(rest, function(other) {
-        return _.indexOf(other, item) >= 0;
-      });
-    });
-  };
-
-  // Take the difference between one array and another.
-  // Only the elements present in just the first array will remain.
-  _.difference = function(array, other) {
-    return _.filter(array, function(value){ return !_.include(other, value); });
-  };
-
-  // Zip together multiple lists into a single array -- elements that share
-  // an index go together.
-  _.zip = function() {
-    var args = slice.call(arguments);
-    var length = _.max(_.pluck(args, 'length'));
-    var results = new Array(length);
-    for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i);
-    return results;
-  };
-
-  // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
-  // we need this function. Return the position of the first occurrence of an
-  // item in an array, or -1 if the item is not included in the array.
-  // Delegates to **ECMAScript 5**'s native `indexOf` if available.
-  // If the array is large and already in sort order, pass `true`
-  // for **isSorted** to use binary search.
-  _.indexOf = function(array, item, isSorted) {
-    if (array == null) return -1;
-    var i, l;
-    if (isSorted) {
-      i = _.sortedIndex(array, item);
-      return array[i] === item ? i : -1;
-    }
-    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
-    for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
-    return -1;
-  };
-
-
-  // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
-  _.lastIndexOf = function(array, item) {
-    if (array == null) return -1;
-    if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
-    var i = array.length;
-    while (i--) if (array[i] === item) return i;
-    return -1;
-  };
-
-  // Generate an integer Array containing an arithmetic progression. A port of
-  // the native Python `range()` function. See
-  // [the Python documentation](http://docs.python.org/library/functions.html#range).
-  _.range = function(start, stop, step) {
-    if (arguments.length <= 1) {
-      stop = start || 0;
-      start = 0;
-    }
-    step = arguments[2] || 1;
-
-    var len = Math.max(Math.ceil((stop - start) / step), 0);
-    var idx = 0;
-    var range = new Array(len);
-
-    while(idx < len) {
-      range[idx++] = start;
-      start += step;
-    }
-
-    return range;
-  };
-
-  // Function (ahem) Functions
-  // ------------------
-
-  // Create a function bound to a given object (assigning `this`, and arguments,
-  // optionally). Binding with arguments is also known as `curry`.
-  // Delegates to **ECMAScript 5**'s native `Function.bind` if available.
-  // We check for `func.bind` first, to fail fast when `func` is undefined.
-  _.bind = function(func, obj) {
-    if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
-    var args = slice.call(arguments, 2);
-    return function() {
-      return func.apply(obj, args.concat(slice.call(arguments)));
-    };
-  };
-
-  // Bind all of an object's methods to that object. Useful for ensuring that
-  // all callbacks defined on an object belong to it.
-  _.bindAll = function(obj) {
-    var funcs = slice.call(arguments, 1);
-    if (funcs.length == 0) funcs = _.functions(obj);
-    each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
-    return obj;
-  };
-
-  // Memoize an expensive function by storing its results.
-  _.memoize = function(func, hasher) {
-    var memo = {};
-    hasher || (hasher = _.identity);
-    return function() {
-      var key = hasher.apply(this, arguments);
-      return hasOwnProperty.call(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
-    };
-  };
-
-  // Delays a function for the given number of milliseconds, and then calls
-  // it with the arguments supplied.
-  _.delay = function(func, wait) {
-    var args = slice.call(arguments, 2);
-    return setTimeout(function(){ return func.apply(func, args); }, wait);
-  };
-
-  // Defers a function, scheduling it to run after the current call stack has
-  // cleared.
-  _.defer = function(func) {
-    return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
-  };
-
-  // Internal function used to implement `_.throttle` and `_.debounce`.
-  var limit = function(func, wait, debounce) {
-    var timeout;
-    return function() {
-      var context = this, args = arguments;
-      var throttler = function() {
-        timeout = null;
-        func.apply(context, args);
-      };
-      if (debounce) clearTimeout(timeout);
-      if (debounce || !timeout) timeout = setTimeout(throttler, wait);
-    };
-  };
-
-  // Returns a function, that, when invoked, will only be triggered at most once
-  // during a given window of time.
-  _.throttle = function(func, wait) {
-    return limit(func, wait, false);
-  };
-
-  // Returns a function, that, as long as it continues to be invoked, will not
-  // be triggered. The function will be called after it stops being called for
-  // N milliseconds.
-  _.debounce = function(func, wait) {
-    return limit(func, wait, true);
-  };
-
-  // Returns a function that will be executed at most one time, no matter how
-  // often you call it. Useful for lazy initialization.
-  _.once = function(func) {
-    var ran = false, memo;
-    return function() {
-      if (ran) return memo;
-      ran = true;
-      return memo = func.apply(this, arguments);
-    };
-  };
-
-  // Returns the first function passed as an argument to the second,
-  // allowing you to adjust arguments, run code before and after, and
-  // conditionally execute the original function.
-  _.wrap = function(func, wrapper) {
-    return function() {
-      var args = [func].concat(slice.call(arguments));
-      return wrapper.apply(this, args);
-    };
-  };
-
-  // Returns a function that is the composition of a list of functions, each
-  // consuming the return value of the function that follows.
-  _.compose = function() {
-    var funcs = slice.call(arguments);
-    return function() {
-      var args = slice.call(arguments);
-      for (var i = funcs.length - 1; i >= 0; i--) {
-        args = [funcs[i].apply(this, args)];
-      }
-      return args[0];
-    };
-  };
-
-  // Returns a function that will only be executed after being called N times.
-  _.after = function(times, func) {
-    return function() {
-      if (--times < 1) { return func.apply(this, arguments); }
-    };
-  };
-
-
-  // Object Functions
-  // ----------------
-
-  // Retrieve the names of an object's properties.
-  // Delegates to **ECMAScript 5**'s native `Object.keys`
-  _.keys = nativeKeys || function(obj) {
-    if (obj !== Object(obj)) throw new TypeError('Invalid object');
-    var keys = [];
-    for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key;
-    return keys;
-  };
-
-  // Retrieve the values of an object's properties.
-  _.values = function(obj) {
-    return _.map(obj, _.identity);
-  };
-
-  // Return a sorted list of the function names available on the object.
-  // Aliased as `methods`
-  _.functions = _.methods = function(obj) {
-    var names = [];
-    for (var key in obj) {
-      if (_.isFunction(obj[key])) names.push(key);
-    }
-    return names.sort();
-  };
-
-  // Extend a given object with all the properties in passed-in object(s).
-  _.extend = function(obj) {
-    each(slice.call(arguments, 1), function(source) {
-      for (var prop in source) {
-        if (source[prop] !== void 0) obj[prop] = source[prop];
-      }
-    });
-    return obj;
-  };
-
-  // Fill in a given object with default properties.
-  _.defaults = function(obj) {
-    each(slice.call(arguments, 1), function(source) {
-      for (var prop in source) {
-        if (obj[prop] == null) obj[prop] = source[prop];
-      }
-    });
-    return obj;
-  };
-
-  // Create a (shallow-cloned) duplicate of an object.
-  _.clone = function(obj) {
-    return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
-  };
-
-  // Invokes interceptor with the obj, and then returns obj.
-  // The primary purpose of this method is to "tap into" a method chain, in
-  // order to perform operations on intermediate results within the chain.
-  _.tap = function(obj, interceptor) {
-    interceptor(obj);
-    return obj;
-  };
-
-  // Perform a deep comparison to check if two objects are equal.
-  _.isEqual = function(a, b) {
-    // Check object identity.
-    if (a === b) return true;
-    // Different types?
-    var atype = typeof(a), btype = typeof(b);
-    if (atype != btype) return false;
-    // Basic equality test (watch out for coercions).
-    if (a == b) return true;
-    // One is falsy and the other truthy.
-    if ((!a && b) || (a && !b)) return false;
-    // Unwrap any wrapped objects.
-    if (a._chain) a = a._wrapped;
-    if (b._chain) b = b._wrapped;
-    // One of them implements an isEqual()?
-    if (a.isEqual) return a.isEqual(b);
-    if (b.isEqual) return b.isEqual(a);
-    // Check dates' integer values.
-    if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();
-    // Both are NaN?
-    if (_.isNaN(a) && _.isNaN(b)) return false;
-    // Compare regular expressions.
-    if (_.isRegExp(a) && _.isRegExp(b))
-      return a.source     === b.source &&
-             a.global     === b.global &&
-             a.ignoreCase === b.ignoreCase &&
-             a.multiline  === b.multiline;
-    // If a is not an object by this point, we can't handle it.
-    if (atype !== 'object') return false;
-    // Check for different array lengths before comparing contents.
-    if (a.length && (a.length !== b.length)) return false;
-    // Nothing else worked, deep compare the contents.
-    var aKeys = _.keys(a), bKeys = _.keys(b);
-    // Different object sizes?
-    if (aKeys.length != bKeys.length) return false;
-    // Recursive comparison of contents.
-    for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false;
-    return true;
-  };
-
-  // Is a given array or object empty?
-  _.isEmpty = function(obj) {
-    if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
-    for (var key in obj) if (hasOwnProperty.call(obj, key)) return false;
-    return true;
-  };
-
-  // Is a given value a DOM element?
-  _.isElement = function(obj) {
-    return !!(obj && obj.nodeType == 1);
-  };
-
-  // Is a given value an array?
-  // Delegates to ECMA5's native Array.isArray
-  _.isArray = nativeIsArray || function(obj) {
-    return toString.call(obj) === '[object Array]';
-  };
-
-  // Is a given variable an object?
-  _.isObject = function(obj) {
-    return obj === Object(obj);
-  };
-
-  // Is a given variable an arguments object?
-  _.isArguments = function(obj) {
-    return !!(obj && hasOwnProperty.call(obj, 'callee'));
-  };
-
-  // Is a given value a function?
-  _.isFunction = function(obj) {
-    return !!(obj && obj.constructor && obj.call && obj.apply);
-  };
-
-  // Is a given value a string?
-  _.isString = function(obj) {
-    return !!(obj === '' || (obj && obj.charCodeAt && obj.substr));
-  };
-
-  // Is a given value a number?
-  _.isNumber = function(obj) {
-    return !!(obj === 0 || (obj && obj.toExponential && obj.toFixed));
-  };
-
-  // Is the given value `NaN`? `NaN` happens to be the only value in JavaScript
-  // that does not equal itself.
-  _.isNaN = function(obj) {
-    return obj !== obj;
-  };
-
-  // Is a given value a boolean?
-  _.isBoolean = function(obj) {
-    return obj === true || obj === false;
-  };
-
-  // Is a given value a date?
-  _.isDate = function(obj) {
-    return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear);
-  };
-
-  // Is the given value a regular expression?
-  _.isRegExp = function(obj) {
-    return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false));
-  };
-
-  // Is a given value equal to null?
-  _.isNull = function(obj) {
-    return obj === null;
-  };
-
-  // Is a given variable undefined?
-  _.isUndefined = function(obj) {
-    return obj === void 0;
-  };
-
-  // Utility Functions
-  // -----------------
-
-  // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
-  // previous owner. Returns a reference to the Underscore object.
-  _.noConflict = function() {
-    root._ = previousUnderscore;
-    return this;
-  };
-
-  // Keep the identity function around for default iterators.
-  _.identity = function(value) {
-    return value;
-  };
-
-  // Run a function **n** times.
-  _.times = function (n, iterator, context) {
-    for (var i = 0; i < n; i++) iterator.call(context, i);
-  };
-
-  // Add your own custom functions to the Underscore object, ensuring that
-  // they're correctly added to the OOP wrapper as well.
-  _.mixin = function(obj) {
-    each(_.functions(obj), function(name){
-      addToWrapper(name, _[name] = obj[name]);
-    });
-  };
-
-  // Generate a unique integer id (unique within the entire client session).
-  // Useful for temporary DOM ids.
-  var idCounter = 0;
-  _.uniqueId = function(prefix) {
-    var id = idCounter++;
-    return prefix ? prefix + id : id;
-  };
-
-  // By default, Underscore uses ERB-style template delimiters, change the
-  // following template settings to use alternative delimiters.
-  _.templateSettings = {
-    evaluate    : /<%([\s\S]+?)%>/g,
-    interpolate : /<%=([\s\S]+?)%>/g
-  };
-
-  // JavaScript micro-templating, similar to John Resig's implementation.
-  // Underscore templating handles arbitrary delimiters, preserves whitespace,
-  // and correctly escapes quotes within interpolated code.
-  _.template = function(str, data) {
-    var c  = _.templateSettings;
-    var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
-      'with(obj||{}){__p.push(\'' +
-      str.replace(/\\/g, '\\\\')
-         .replace(/'/g, "\\'")
-         .replace(c.interpolate, function(match, code) {
-           return "'," + code.replace(/\\'/g, "'") + ",'";
-         })
-         .replace(c.evaluate || null, function(match, code) {
-           return "');" + code.replace(/\\'/g, "'")
-                              .replace(/[\r\n\t]/g, ' ') + "__p.push('";
-         })
-         .replace(/\r/g, '\\r')
-         .replace(/\n/g, '\\n')
-         .replace(/\t/g, '\\t')
-         + "');}return __p.join('');";
-    var func = new Function('obj', tmpl);
-    return data ? func(data) : func;
-  };
-
-  // The OOP Wrapper
-  // ---------------
-
-  // If Underscore is called as a function, it returns a wrapped object that
-  // can be used OO-style. This wrapper holds altered versions of all the
-  // underscore functions. Wrapped objects may be chained.
-  var wrapper = function(obj) { this._wrapped = obj; };
-
-  // Expose `wrapper.prototype` as `_.prototype`
-  _.prototype = wrapper.prototype;
-
-  // Helper function to continue chaining intermediate results.
-  var result = function(obj, chain) {
-    return chain ? _(obj).chain() : obj;
-  };
-
-  // A method to easily add functions to the OOP wrapper.
-  var addToWrapper = function(name, func) {
-    wrapper.prototype[name] = function() {
-      var args = slice.call(arguments);
-      unshift.call(args, this._wrapped);
-      return result(func.apply(_, args), this._chain);
-    };
-  };
-
-  // Add all of the Underscore functions to the wrapper object.
-  _.mixin(_);
-
-  // Add all mutator Array functions to the wrapper.
-  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
-    var method = ArrayProto[name];
-    wrapper.prototype[name] = function() {
-      method.apply(this._wrapped, arguments);
-      return result(this._wrapped, this._chain);
-    };
-  });
-
-  // Add all accessor Array functions to the wrapper.
-  each(['concat', 'join', 'slice'], function(name) {
-    var method = ArrayProto[name];
-    wrapper.prototype[name] = function() {
-      return result(method.apply(this._wrapped, arguments), this._chain);
-    };
-  });
-
-  // Start chaining a wrapped Underscore object.
-  wrapper.prototype.chain = function() {
-    this._chain = true;
-    return this;
-  };
-
-  // Extracts the result from a wrapped and chained object.
-  wrapper.prototype.value = function() {
-    return this._wrapped;
-  };
+
+    // Start chaining a wrapped Underscore object.
+    wrapper.prototype.chain = function () {
+        this._chain = true;
+        return this;
+    };
+
+    // Extracts the result from a wrapped and chained object.
+    wrapper.prototype.value = function () {
+        return this._wrapped;
+    };
 
 })();
 /**
@@ -1349,245 +1360,245 @@
  */
 (function () {
 
-var
-  global = this,
-  previousFlotr = this.Flotr,
-  Flotr;
-
-Flotr = {
-  _: _,
-  bean: bean,
-  isIphone: /iphone/i.test(navigator.userAgent),
-  isIE: (navigator.appVersion.indexOf("MSIE") != -1 ? parseFloat(navigator.appVersion.split("MSIE")[1]) : false),
-  
-  /**
-   * An object of the registered graph types. Use Flotr.addType(type, object)
-   * to add your own type.
-   */
-  graphTypes: {},
-  
-  /**
-   * The list of the registered plugins
-   */
-  plugins: {},
-  
-  /**
-   * Can be used to add your own chart type. 
-   * @param {String} name - Type of chart, like 'pies', 'bars' etc.
-   * @param {String} graphType - The object containing the basic drawing functions (draw, etc)
-   */
-  addType: function(name, graphType){
-    Flotr.graphTypes[name] = graphType;
-    Flotr.defaultOptions[name] = graphType.options || {};
-    Flotr.defaultOptions.defaultType = Flotr.defaultOptions.defaultType || name;
-  },
-  
-  /**
-   * Can be used to add a plugin
-   * @param {String} name - The name of the plugin
-   * @param {String} plugin - The object containing the plugin's data (callbacks, options, function1, function2, ...)
-   */
-  addPlugin: function(name, plugin){
-    Flotr.plugins[name] = plugin;
-    Flotr.defaultOptions[name] = plugin.options || {};
-  },
-  
-  /**
-   * Draws the graph. This function is here for backwards compatibility with Flotr version 0.1.0alpha.
-   * You could also draw graphs by directly calling Flotr.Graph(element, data, options).
-   * @param {Element} el - element to insert the graph into
-   * @param {Object} data - an array or object of dataseries
-   * @param {Object} options - an object containing options
-   * @param {Class} _GraphKlass_ - (optional) Class to pass the arguments to, defaults to Flotr.Graph
-   * @return {Object} returns a new graph object and of course draws the graph.
-   */
-  draw: function(el, data, options, GraphKlass){  
-    GraphKlass = GraphKlass || Flotr.Graph;
-    return new GraphKlass(el, data, options);
-  },
-  
-  /**
-   * Recursively merges two objects.
-   * @param {Object} src - source object (likely the object with the least properties)
-   * @param {Object} dest - destination object (optional, object with the most properties)
-   * @return {Object} recursively merged Object
-   * @TODO See if we can't remove this.
-   */
-  merge: function(src, dest){
-    var i, v, result = dest || {};
-
-    for (i in src) {
-      v = src[i];
-      if (v && typeof(v) === 'object') {
-        if (v.constructor === Array) {
-          result[i] = this._.clone(v);
-        } else if (v.constructor !== RegExp && !this._.isElement(v)) {
-          result[i] = Flotr.merge(v, (dest ? dest[i] : undefined));
-        } else {
-          result[i] = v;
-        }
-      } else {
-        result[i] = v;
-      }
-    }
-
-    return result;
-  },
-  
-  /**
-   * Recursively clones an object.
-   * @param {Object} object - The object to clone
-   * @return {Object} the clone
-   * @TODO See if we can't remove this.
-   */
-  clone: function(object){
-    return Flotr.merge(object, {});
-  },
-  
-  /**
-   * Function calculates the ticksize and returns it.
-   * @param {Integer} noTicks - number of ticks
-   * @param {Integer} min - lower bound integer value for the current axis
-   * @param {Integer} max - upper bound integer value for the current axis
-   * @param {Integer} decimals - number of decimals for the ticks
-   * @return {Integer} returns the ticksize in pixels
-   */
-  getTickSize: function(noTicks, min, max, decimals){
-    var delta = (max - min) / noTicks,
-        magn = Flotr.getMagnitude(delta),
-        tickSize = 10,
-        norm = delta / magn; // Norm is between 1.0 and 10.0.
-        
-    if(norm < 1.5) tickSize = 1;
-    else if(norm < 2.25) tickSize = 2;
-    else if(norm < 3) tickSize = ((decimals === 0) ? 2 : 2.5);
-    else if(norm < 7.5) tickSize = 5;
-    
-    return tickSize * magn;
-  },
-  
-  /**
-   * Default tick formatter.
-   * @param {String, Integer} val - tick value integer
-   * @param {Object} axisOpts - the axis' options
-   * @return {String} formatted tick string
-   */
-  defaultTickFormatter: function(val, axisOpts){
-    return val+'';
-  },
-  
-  /**
-   * Formats the mouse tracker values.
-   * @param {Object} obj - Track value Object {x:..,y:..}
-   * @return {String} Formatted track string
-   */
-  defaultTrackFormatter: function(obj){
-    return '('+obj.x+', '+obj.y+')';
-  }, 
-  
-  /**
-   * Utility function to convert file size values in bytes to kB, MB, ...
-   * @param value {Number} - The value to convert
-   * @param precision {Number} - The number of digits after the comma (default: 2)
-   * @param base {Number} - The base (default: 1000)
-   */
-  engineeringNotation: function(value, precision, base){
-    var sizes =         ['Y','Z','E','P','T','G','M','k',''],
-        fractionSizes = ['y','z','a','f','p','n','µ','m',''],
-        total = sizes.length;
-
-    base = base || 1000;
-    precision = Math.pow(10, precision || 2);
-
-    if (value === 0) return 0;
-
-    if (value > 1) {
-      while (total-- && (value >= base)) value /= base;
-    }
-    else {
-      sizes = fractionSizes;
-      total = sizes.length;
-      while (total-- && (value < 1)) value *= base;
-    }
-
-    return (Math.round(value * precision) / precision) + sizes[total];
-  },
-  
-  /**
-   * Returns the magnitude of the input value.
-   * @param {Integer, Float} x - integer or float value
-   * @return {Integer, Float} returns the magnitude of the input value
-   */
-  getMagnitude: function(x){
-    return Math.pow(10, Math.floor(Math.log(x) / Math.LN10));
-  },
-  toPixel: function(val){
-    return Math.floor(val)+0.5;//((val-Math.round(val) < 0.4) ? (Math.floor(val)-0.5) : val);
-  },
-  toRad: function(angle){
-    return -angle * (Math.PI/180);
-  },
-  floorInBase: function(n, base) {
-    return base * Math.floor(n / base);
-  },
-  drawText: function(ctx, text, x, y, style) {
-    if (!ctx.fillText) {
-      ctx.drawText(text, x, y, style);
-      return;
-    }
-    
-    style = this._.extend({
-      size: Flotr.defaultOptions.fontSize,
-      color: '#000000',
-      textAlign: 'left',
-      textBaseline: 'bottom',
-      weight: 1,
-      angle: 0
-    }, style);
-    
-    ctx.save();
-    ctx.translate(x, y);
-    ctx.rotate(style.angle);
-    ctx.fillStyle = style.color;
-    ctx.font = (style.weight > 1 ? "bold " : "") + (style.size*1.3) + "px sans-serif";
-    ctx.textAlign = style.textAlign;
-    ctx.textBaseline = style.textBaseline;
-    ctx.fillText(text, 0, 0);
-    ctx.restore();
-  },
-  getBestTextAlign: function(angle, style) {
-    style = style || {textAlign: 'center', textBaseline: 'middle'};
-    angle += Flotr.getTextAngleFromAlign(style);
-    
-    if (Math.abs(Math.cos(angle)) > 10e-3) 
-      style.textAlign    = (Math.cos(angle) > 0 ? 'right' : 'left');
-    
-    if (Math.abs(Math.sin(angle)) > 10e-3) 
-      style.textBaseline = (Math.sin(angle) > 0 ? 'top' : 'bottom');
-    
-    return style;
-  },
-  alignTable: {
-    'right middle' : 0,
-    'right top'    : Math.PI/4,
-    'center top'   : Math.PI/2,
-    'left top'     : 3*(Math.PI/4),
-    'left middle'  : Math.PI,
-    'left bottom'  : -3*(Math.PI/4),
-    'center bottom': -Math.PI/2,
-    'right bottom' : -Math.PI/4,
-    'center middle': 0
-  },
-  getTextAngleFromAlign: function(style) {
-    return Flotr.alignTable[style.textAlign+' '+style.textBaseline] || 0;
-  },
-  noConflict : function () {
-    global.Flotr = previousFlotr;
-    return this;
-  }
-};
-
-global.Flotr = Flotr;
+    var
+        global = this,
+        previousFlotr = this.Flotr,
+        Flotr;
+
+    Flotr = {
+        _: _,
+        bean: bean,
+        isIphone: /iphone/i.test(navigator.userAgent),
+        isIE: (navigator.appVersion.indexOf("MSIE") != -1 ? parseFloat(navigator.appVersion.split("MSIE")[1]) : false),
+
+        /**
+         * An object of the registered graph types. Use Flotr.addType(type, object)
+         * to add your own type.
+         */
+        graphTypes: {},
+
+        /**
+         * The list of the registered plugins
+         */
+        plugins: {},
+
+        /**
+         * Can be used to add your own chart type.
+         * @param {String} name - Type of chart, like 'pies', 'bars' etc.
+         * @param {String} graphType - The object containing the basic drawing functions (draw, etc)
+         */
+        addType: function (name, graphType) {
+            Flotr.graphTypes[name] = graphType;
+            Flotr.defaultOptions[name] = graphType.options || {};
+            Flotr.defaultOptions.defaultType = Flotr.defaultOptions.defaultType || name;
+        },
+
+        /**
+         * Can be used to add a plugin
+         * @param {String} name - The name of the plugin
+         * @param {String} plugin - The object containing the plugin's data (callbacks, options, function1, function2, ...)
+         */
+        addPlugin: function (name, plugin) {
+            Flotr.plugins[name] = plugin;
+            Flotr.defaultOptions[name] = plugin.options || {};
+        },
+
+        /**
+         * Draws the graph. This function is here for backwards compatibility with Flotr version 0.1.0alpha.
+         * You could also draw graphs by directly calling Flotr.Graph(element, data, options).
+         * @param {Element} el - element to insert the graph into
+         * @param {Object} data - an array or object of dataseries
+         * @param {Object} options - an object containing options
+         * @param {Class} _GraphKlass_ - (optional) Class to pass the arguments to, defaults to Flotr.Graph
+         * @return {Object} returns a new graph object and of course draws the graph.
+         */
+        draw: function (el, data, options, GraphKlass) {
+            GraphKlass = GraphKlass || Flotr.Graph;
+            return new GraphKlass(el, data, options);
+        },
+
+        /**
+         * Recursively merges two objects.
+         * @param {Object} src - source object (likely the object with the least properties)
+         * @param {Object} dest - destination object (optional, object with the most properties)
+         * @return {Object} recursively merged Object
+         * @TODO See if we can't remove this.
+         */
+        merge: function (src, dest) {
+            var i, v, result = dest || {};
+
+            for (i in src) {
+                v = src[i];
+                if (v && typeof(v) === 'object') {
+                    if (v.constructor === Array) {
+                        result[i] = this._.clone(v);
+                    } else if (v.constructor !== RegExp && !this._.isElement(v)) {
+                        result[i] = Flotr.merge(v, (dest ? dest[i] : undefined));
+                    } else {
+                        result[i] = v;
+                    }
+                } else {
+                    result[i] = v;
+                }
+            }
+
+            return result;
+        },
+
+        /**
+         * Recursively clones an object.
+         * @param {Object} object - The object to clone
+         * @return {Object} the clone
+         * @TODO See if we can't remove this.
+         */
+        clone: function (object) {
+            return Flotr.merge(object, {});
+        },
+
+        /**
+         * Function calculates the ticksize and returns it.
+         * @param {Integer} noTicks - number of ticks
+         * @param {Integer} min - lower bound integer value for the current axis
+         * @param {Integer} max - upper bound integer value for the current axis
+         * @param {Integer} decimals - number of decimals for the ticks
+         * @return {Integer} returns the ticksize in pixels
+         */
+        getTickSize: function (noTicks, min, max, decimals) {
+            var delta = (max - min) / noTicks,
+                magn = Flotr.getMagnitude(delta),
+                tickSize = 10,
+                norm = delta / magn; // Norm is between 1.0 and 10.0.
+
+            if (norm < 1.5) tickSize = 1;
+            else if (norm < 2.25) tickSize = 2;
+            else if (norm < 3) tickSize = ((decimals === 0) ? 2 : 2.5);
+            else if (norm < 7.5) tickSize = 5;
+
+            return tickSize * magn;
+        },
+
+        /**
+         * Default tick formatter.
+         * @param {String, Integer} val - tick value integer
+         * @param {Object} axisOpts - the axis' options
+         * @return {String} formatted tick string
+         */
+        defaultTickFormatter: function (val, axisOpts) {
+            return val + '';
+        },
+
+        /**
+         * Formats the mouse tracker values.
+         * @param {Object} obj - Track value Object {x:..,y:..}
+         * @return {String} Formatted track string
+         */
+        defaultTrackFormatter: function (obj) {
+            return '(' + obj.x + ', ' + obj.y + ')';
+        },
+
+        /**
+         * Utility function to convert file size values in bytes to kB, MB, ...
+         * @param value {Number} - The value to convert
+         * @param precision {Number} - The number of digits after the comma (default: 2)
+         * @param base {Number} - The base (default: 1000)
+         */
+        engineeringNotation: function (value, precision, base) {
+            var sizes = ['Y', 'Z', 'E', 'P', 'T', 'G', 'M', 'k', ''],
+                fractionSizes = ['y', 'z', 'a', 'f', 'p', 'n', 'µ', 'm', ''],
+                total = sizes.length;
+
+            base = base || 1000;
+            precision = Math.pow(10, precision || 2);
+
+            if (value === 0) return 0;
+
+            if (value > 1) {
+                while (total-- && (value >= base)) value /= base;
+            }
+            else {
+                sizes = fractionSizes;
+                total = sizes.length;
+                while (total-- && (value < 1)) value *= base;
+            }
+
+            return (Math.round(value * precision) / precision) + sizes[total];
+        },
+
+        /**
+         * Returns the magnitude of the input value.
+         * @param {Integer, Float} x - integer or float value
+         * @return {Integer, Float} returns the magnitude of the input value
+         */
+        getMagnitude: function (x) {
+            return Math.pow(10, Math.floor(Math.log(x) / Math.LN10));
+        },
+        toPixel: function (val) {
+            return Math.floor(val) + 0.5;//((val-Math.round(val) < 0.4) ? (Math.floor(val)-0.5) : val);
+        },
+        toRad: function (angle) {
+            return -angle * (Math.PI / 180);
+        },
+        floorInBase: function (n, base) {
+            return base * Math.floor(n / base);
+        },
+        drawText: function (ctx, text, x, y, style) {
+            if (!ctx.fillText) {
+                ctx.drawText(text, x, y, style);
+                return;
+            }
+
+            style = this._.extend({
+                size: Flotr.defaultOptions.fontSize,
+                color: '#000000',
+                textAlign: 'left',
+                textBaseline: 'bottom',
+                weight: 1,
+                angle: 0
+            }, style);
+
+            ctx.save();
+            ctx.translate(x, y);
+            ctx.rotate(style.angle);
+            ctx.fillStyle = style.color;
+            ctx.font = (style.weight > 1 ? "bold " : "") + (style.size * 1.3) + "px sans-serif";
+            ctx.textAlign = style.textAlign;
+            ctx.textBaseline = style.textBaseline;
+            ctx.fillText(text, 0, 0);
+            ctx.restore();
+        },
+        getBestTextAlign: function (angle, style) {
+            style = style || {textAlign: 'center', textBaseline: 'middle'};
+            angle += Flotr.getTextAngleFromAlign(style);
+
+            if (Math.abs(Math.cos(angle)) > 10e-3)
+                style.textAlign = (Math.cos(angle) > 0 ? 'right' : 'left');
+
+            if (Math.abs(Math.sin(angle)) > 10e-3)
+                style.textBaseline = (Math.sin(angle) > 0 ? 'top' : 'bottom');
+
+            return style;
+        },
+        alignTable: {
+            'right middle': 0,
+            'right top': Math.PI / 4,
+            'center top': Math.PI / 2,
+            'left top': 3 * (Math.PI / 4),
+            'left middle': Math.PI,
+            'left bottom': -3 * (Math.PI / 4),
+            'center bottom': -Math.PI / 2,
+            'right bottom': -Math.PI / 4,
+            'center middle': 0
+        },
+        getTextAngleFromAlign: function (style) {
+            return Flotr.alignTable[style.textAlign + ' ' + style.textBaseline] || 0;
+        },
+        noConflict: function () {
+            global.Flotr = previousFlotr;
+            return this;
+        }
+    };
+
+    global.Flotr = Flotr;
 
 })();
 
@@ -1595,99 +1606,99 @@
  * Flotr Defaults
  */
 Flotr.defaultOptions = {
-  colors: ['#00A8F0', '#C0D800', '#CB4B4B', '#4DA74D', '#9440ED'], //=> The default colorscheme. When there are > 5 series, additional colors are generated.
-  ieBackgroundColor: '#FFFFFF', // Background color for excanvas clipping
-  title: null,             // => The graph's title
-  subtitle: null,          // => The graph's subtitle
-  shadowSize: 4,           // => size of the 'fake' shadow
-  defaultType: null,       // => default series type
-  HtmlText: true,          // => wether to draw the text using HTML or on the canvas
-  fontColor: '#545454',    // => default font color
-  fontSize: 7.5,           // => canvas' text font size
-  resolution: 1,           // => resolution of the graph, to have printer-friendly graphs !
-  parseFloat: true,        // => whether to preprocess data for floats (ie. if input is string)
-  xaxis: {
-    ticks: null,           // => format: either [1, 3] or [[1, 'a'], 3]
-    minorTicks: null,      // => format: either [1, 3] or [[1, 'a'], 3]
-    showLabels: true,      // => setting to true will show the axis ticks labels, hide otherwise
-    showMinorLabels: false,// => true to show the axis minor ticks labels, false to hide
-    labelsAngle: 0,        // => labels' angle, in degrees
-    title: null,           // => axis title
-    titleAngle: 0,         // => axis title's angle, in degrees
-    noTicks: 5,            // => number of ticks for automagically generated ticks
-    minorTickFreq: null,   // => number of minor ticks between major ticks for autogenerated ticks
-    tickFormatter: Flotr.defaultTickFormatter, // => fn: number, Object -> string
-    tickDecimals: null,    // => no. of decimals, null means auto
-    min: null,             // => min. value to show, null means set automatically
-    max: null,             // => max. value to show, null means set automatically
-    autoscale: false,      // => Turns autoscaling on with true
-    autoscaleMargin: 0,    // => margin in % to add if auto-setting min/max
-    color: null,           // => color of the ticks
-    mode: 'normal',        // => can be 'time' or 'normal'
-    timeFormat: null,
-    timeMode:'UTC',        // => For UTC time ('local' for local time).
-    timeUnit:'millisecond',// => Unit for time (millisecond, second, minute, hour, day, month, year)
-    scaling: 'linear',     // => Scaling, can be 'linear' or 'logarithmic'
-    base: Math.E,
-    titleAlign: 'center',
-    margin: true           // => Turn off margins with false
-  },
-  x2axis: {},
-  yaxis: {
-    ticks: null,           // => format: either [1, 3] or [[1, 'a'], 3]
-    minorTicks: null,      // => format: either [1, 3] or [[1, 'a'], 3]
-    showLabels: true,      // => setting to true will show the axis ticks labels, hide otherwise
-    showMinorLabels: false,// => true to show the axis minor ticks labels, false to hide
-    labelsAngle: 0,        // => labels' angle, in degrees
-    title: null,           // => axis title
-    titleAngle: 90,        // => axis title's angle, in degrees
-    noTicks: 5,            // => number of ticks for automagically generated ticks
-    minorTickFreq: null,   // => number of minor ticks between major ticks for autogenerated ticks
-    tickFormatter: Flotr.defaultTickFormatter, // => fn: number, Object -> string
-    tickDecimals: null,    // => no. of decimals, null means auto
-    min: null,             // => min. value to show, null means set automatically
-    max: null,             // => max. value to show, null means set automatically
-    autoscale: false,      // => Turns autoscaling on with true
-    autoscaleMargin: 0,    // => margin in % to add if auto-setting min/max
-    color: null,           // => The color of the ticks
-    scaling: 'linear',     // => Scaling, can be 'linear' or 'logarithmic'
-    base: Math.E,
-    titleAlign: 'center',
-    margin: true           // => Turn off margins with false
-  },
-  y2axis: {
-    titleAngle: 270
-  },
-  grid: {
-    color: '#545454',      // => primary color used for outline and labels
-    backgroundColor: null, // => null for transparent, else color
-    backgroundImage: null, // => background image. String or object with src, left and top
-    watermarkAlpha: 0.4,   // => 
-    tickColor: '#DDDDDD',  // => color used for the ticks
-    labelMargin: 3,        // => margin in pixels
-    verticalLines: true,   // => whether to show gridlines in vertical direction
-    minorVerticalLines: null, // => whether to show gridlines for minor ticks in vertical dir.
-    horizontalLines: true, // => whether to show gridlines in horizontal direction
-    minorHorizontalLines: null, // => whether to show gridlines for minor ticks in horizontal dir.
-    outlineWidth: 1,       // => width of the grid outline/border in pixels
-    outline : 'nsew',      // => walls of the outline to display
-    circular: false        // => if set to true, the grid will be circular, must be used when radars are drawn
-  },
-  mouse: {
-    track: false,          // => true to track the mouse, no tracking otherwise
-    trackAll: false,
-    position: 'se',        // => position of the value box (default south-east)
-    relative: false,       // => next to the mouse cursor
-    trackFormatter: Flotr.defaultTrackFormatter, // => formats the values in the value box
-    margin: 5,             // => margin in pixels of the valuebox
-    lineColor: '#FF3F19',  // => line color of points that are drawn when mouse comes near a value of a series
-    trackDecimals: 1,      // => decimals for the track values
-    sensibility: 2,        // => the lower this number, the more precise you have to aim to show a value
-    trackY: true,          // => whether or not to track the mouse in the y axis
-    radius: 3,             // => radius of the track point
-    fillColor: null,       // => color to fill our select bar with only applies to bar and similar graphs (only bars for now)
-    fillOpacity: 0.4       // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill 
-  }
+    colors: ['#00A8F0', '#C0D800', '#CB4B4B', '#4DA74D', '#9440ED'], //=> The default colorscheme. When there are > 5 series, additional colors are generated.
+    ieBackgroundColor: '#FFFFFF', // Background color for excanvas clipping
+    title: null,             // => The graph's title
+    subtitle: null,          // => The graph's subtitle
+    shadowSize: 4,           // => size of the 'fake' shadow
+    defaultType: null,       // => default series type
+    HtmlText: true,          // => wether to draw the text using HTML or on the canvas
+    fontColor: '#545454',    // => default font color
+    fontSize: 7.5,           // => canvas' text font size
+    resolution: 1,           // => resolution of the graph, to have printer-friendly graphs !
+    parseFloat: true,        // => whether to preprocess data for floats (ie. if input is string)
+    xaxis: {
+        ticks: null,           // => format: either [1, 3] or [[1, 'a'], 3]
+        minorTicks: null,      // => format: either [1, 3] or [[1, 'a'], 3]
+        showLabels: true,      // => setting to true will show the axis ticks labels, hide otherwise
+        showMinorLabels: false,// => true to show the axis minor ticks labels, false to hide
+        labelsAngle: 0,        // => labels' angle, in degrees
+        title: null,           // => axis title
+        titleAngle: 0,         // => axis title's angle, in degrees
+        noTicks: 5,            // => number of ticks for automagically generated ticks
+        minorTickFreq: null,   // => number of minor ticks between major ticks for autogenerated ticks
+        tickFormatter: Flotr.defaultTickFormatter, // => fn: number, Object -> string
+        tickDecimals: null,    // => no. of decimals, null means auto
+        min: null,             // => min. value to show, null means set automatically
+        max: null,             // => max. value to show, null means set automatically
+        autoscale: false,      // => Turns autoscaling on with true
+        autoscaleMargin: 0,    // => margin in % to add if auto-setting min/max
+        color: null,           // => color of the ticks
+        mode: 'normal',        // => can be 'time' or 'normal'
+        timeFormat: null,
+        timeMode: 'UTC',        // => For UTC time ('local' for local time).
+        timeUnit: 'millisecond',// => Unit for time (millisecond, second, minute, hour, day, month, year)
+        scaling: 'linear',     // => Scaling, can be 'linear' or 'logarithmic'
+        base: Math.E,
+        titleAlign: 'center',
+        margin: true           // => Turn off margins with false
+    },
+    x2axis: {},
+    yaxis: {
+        ticks: null,           // => format: either [1, 3] or [[1, 'a'], 3]
+        minorTicks: null,      // => format: either [1, 3] or [[1, 'a'], 3]
+        showLabels: true,      // => setting to true will show the axis ticks labels, hide otherwise
+        showMinorLabels: false,// => true to show the axis minor ticks labels, false to hide
+        labelsAngle: 0,        // => labels' angle, in degrees
+        title: null,           // => axis title
+        titleAngle: 90,        // => axis title's angle, in degrees
+        noTicks: 5,            // => number of ticks for automagically generated ticks
+        minorTickFreq: null,   // => number of minor ticks between major ticks for autogenerated ticks
+        tickFormatter: Flotr.defaultTickFormatter, // => fn: number, Object -> string
+        tickDecimals: null,    // => no. of decimals, null means auto
+        min: null,             // => min. value to show, null means set automatically
+        max: null,             // => max. value to show, null means set automatically
+        autoscale: false,      // => Turns autoscaling on with true
+        autoscaleMargin: 0,    // => margin in % to add if auto-setting min/max
+        color: null,           // => The color of the ticks
+        scaling: 'linear',     // => Scaling, can be 'linear' or 'logarithmic'
+        base: Math.E,
+        titleAlign: 'center',
+        margin: true           // => Turn off margins with false
+    },
+    y2axis: {
+        titleAngle: 270
+    },
+    grid: {
+        color: '#545454',      // => primary color used for outline and labels
+        backgroundColor: null, // => null for transparent, else color
+        backgroundImage: null, // => background image. String or object with src, left and top
+        watermarkAlpha: 0.4,   // => 
+        tickColor: '#DDDDDD',  // => color used for the ticks
+        labelMargin: 3,        // => margin in pixels
+        verticalLines: true,   // => whether to show gridlines in vertical direction
+        minorVerticalLines: null, // => whether to show gridlines for minor ticks in vertical dir.
+        horizontalLines: true, // => whether to show gridlines in horizontal direction
+        minorHorizontalLines: null, // => whether to show gridlines for minor ticks in horizontal dir.
+        outlineWidth: 1,       // => width of the grid outline/border in pixels
+        outline: 'nsew',      // => walls of the outline to display
+        circular: false        // => if set to true, the grid will be circular, must be used when radars are drawn
+    },
+    mouse: {
+        track: false,          // => true to track the mouse, no tracking otherwise
+        trackAll: false,
+        position: 'se',        // => position of the value box (default south-east)
+        relative: false,       // => next to the mouse cursor
+        trackFormatter: Flotr.defaultTrackFormatter, // => formats the values in the value box
+        margin: 5,             // => margin in pixels of the valuebox
+        lineColor: '#FF3F19',  // => line color of points that are drawn when mouse comes near a value of a series
+        trackDecimals: 1,      // => decimals for the track values
+        sensibility: 2,        // => the lower this number, the more precise you have to aim to show a value
+        trackY: true,          // => whether or not to track the mouse in the y axis
+        radius: 3,             // => radius of the track point
+        fillColor: null,       // => color to fill our select bar with only applies to bar and similar graphs (only bars for now)
+        fillOpacity: 0.4       // => opacity of the fill color, set to 1 for a solid fill, 0 hides the fill 
+    }
 };
 
 /**
@@ -1696,161 +1707,161 @@
 
 (function () {
 
-var
-  _ = Flotr._;
+    var
+        _ = Flotr._;
 
 // Constructor
-function Color (r, g, b, a) {
-  this.rgba = ['r','g','b','a'];
-  var x = 4;
-  while(-1<--x){
-    this[this.rgba[x]] = arguments[x] || ((x==3) ? 1.0 : 0);
-  }
-  this.normalize();
-}
+    function Color(r, g, b, a) {
+        this.rgba = ['r', 'g', 'b', 'a'];
+        var x = 4;
+        while (-1 < --x) {
+            this[this.rgba[x]] = arguments[x] || ((x == 3) ? 1.0 : 0);
+        }
+        this.normalize();
+    }
 
 // Constants
-var COLOR_NAMES = {
-  aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],
-  brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],
-  darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],
-  darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],
-  darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],
-  khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],
-  lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],
-  maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],
-  violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]
-};
-
-Color.prototype = {
-  scale: function(rf, gf, bf, af){
-    var x = 4;
-    while (-1 < --x) {
-      if (!_.isUndefined(arguments[x])) this[this.rgba[x]] *= arguments[x];
-    }
-    return this.normalize();
-  },
-  alpha: function(alpha) {
-    if (!_.isUndefined(alpha) && !_.isNull(alpha)) {
-      this.a = alpha;
-    }
-    return this.normalize();
-  },
-  clone: function(){
-    return new Color(this.r, this.b, this.g, this.a);
-  },
-  limit: function(val,minVal,maxVal){
-    return Math.max(Math.min(val, maxVal), minVal);
-  },
-  normalize: function(){
-    var limit = this.limit;
-    this.r = limit(parseInt(this.r, 10), 0, 255);
-    this.g = limit(parseInt(this.g, 10), 0, 255);
-    this.b = limit(parseInt(this.b, 10), 0, 255);
-    this.a = limit(this.a, 0, 1);
-    return this;
-  },
-  distance: function(color){
-    if (!color) return;
-    color = new Color.parse(color);
-    var dist = 0, x = 3;
-    while(-1<--x){
-      dist += Math.abs(this[this.rgba[x]] - color[this.rgba[x]]);
-    }
-    return dist;
-  },
-  toString: function(){
-    return (this.a >= 1.0) ? 'rgb('+[this.r,this.g,this.b].join(',')+')' : 'rgba('+[this.r,this.g,this.b,this.a].join(',')+')';
-  },
-  contrast: function () {
-    var
-      test = 1 - ( 0.299 * this.r + 0.587 * this.g + 0.114 * this.b) / 255;
-    return (test < 0.5 ? '#000000' : '#ffffff');
-  }
-};
-
-_.extend(Color, {
-  /**
-   * Parses a color string and returns a corresponding Color.
-   * The different tests are in order of probability to improve speed.
-   * @param {String, Color} str - string thats representing a color
-   * @return {Color} returns a Color object or false
-   */
-  parse: function(color){
-    if (color instanceof Color) return color;
-
-    var result;
-
-    // #a0b1c2
-    if((result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color)))
-      return new Color(parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16));
-
-    // rgb(num,num,num)
-    if((result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color)))
-      return new Color(parseInt(result[1], 10), parseInt(result[2], 10), parseInt(result[3], 10));
-  
-    // #fff
-    if((result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color)))
-      return new Color(parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16));
-  
-    // rgba(num,num,num,num)
-    if((result = /rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(color)))
-      return new Color(parseInt(result[1], 10), parseInt(result[2], 10), parseInt(result[3], 10), parseFloat(result[4]));
-      
-    // rgb(num%,num%,num%)
-    if((result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color)))
-      return new Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55);
-  
-    // rgba(num%,num%,num%,num)
-    if((result = /rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(color)))
-      return new Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55, parseFloat(result[4]));
-
-    // Otherwise, we're most likely dealing with a named color.
-    var name = (color+'').replace(/^\s*([\S\s]*?)\s*$/, '$1').toLowerCase();
-    if(name == 'transparent'){
-      return new Color(255, 255, 255, 0);
-    }
-    return (result = COLOR_NAMES[name]) ? new Color(result[0], result[1], result[2]) : new Color(0, 0, 0, 0);
-  },
-
-  /**
-   * Process color and options into color style.
-   */
-  processColor: function(color, options) {
-
-    var opacity = options.opacity;
-    if (!color) return 'rgba(0, 0, 0, 0)';
-    if (color instanceof Color) return color.alpha(opacity).toString();
-    if (_.isString(color)) return Color.parse(color).alpha(opacity).toString();
-    
-    var grad = color.colors ? color : {colors: color};
-    
-    if (!options.ctx) {
-      if (!_.isArray(grad.colors)) return 'rgba(0, 0, 0, 0)';
-      return Color.parse(_.isArray(grad.colors[0]) ? grad.colors[0][1] : grad.colors[0]).alpha(opacity).toString();
-    }
-    grad = _.extend({start: 'top', end: 'bottom'}, grad); 
-    
-    if (/top/i.test(grad.start))  options.x1 = 0;
-    if (/left/i.test(grad.start)) options.y1 = 0;
-    if (/bottom/i.test(grad.end)) options.x2 = 0;
-    if (/right/i.test(grad.end))  options.y2 = 0;
-
-    var i, c, stop, gradient = options.ctx.createLinearGradient(options.x1, options.y1, options.x2, options.y2);
-    for (i = 0; i < grad.colors.length; i++) {
-      c = grad.colors[i];
-      if (_.isArray(c)) {
-        stop = c[0];
-        c = c[1];
-      }
-      else stop = i / (grad.colors.length-1);
-      gradient.addColorStop(stop, Color.parse(c).alpha(opacity));
-    }
-    return gradient;
-  }
-});
-
-Flotr.Color = Color;
+    var COLOR_NAMES = {
+        aqua: [0, 255, 255], azure: [240, 255, 255], beige: [245, 245, 220], black: [0, 0, 0], blue: [0, 0, 255],
+        brown: [165, 42, 42], cyan: [0, 255, 255], darkblue: [0, 0, 139], darkcyan: [0, 139, 139], darkgrey: [169, 169, 169],
+        darkgreen: [0, 100, 0], darkkhaki: [189, 183, 107], darkmagenta: [139, 0, 139], darkolivegreen: [85, 107, 47],
+        darkorange: [255, 140, 0], darkorchid: [153, 50, 204], darkred: [139, 0, 0], darksalmon: [233, 150, 122],
+        darkviolet: [148, 0, 211], fuchsia: [255, 0, 255], gold: [255, 215, 0], green: [0, 128, 0], indigo: [75, 0, 130],
+        khaki: [240, 230, 140], lightblue: [173, 216, 230], lightcyan: [224, 255, 255], lightgreen: [144, 238, 144],
+        lightgrey: [211, 211, 211], lightpink: [255, 182, 193], lightyellow: [255, 255, 224], lime: [0, 255, 0], magenta: [255, 0, 255],
+        maroon: [128, 0, 0], navy: [0, 0, 128], olive: [128, 128, 0], orange: [255, 165, 0], pink: [255, 192, 203], purple: [128, 0, 128],
+        violet: [128, 0, 128], red: [255, 0, 0], silver: [192, 192, 192], white: [255, 255, 255], yellow: [255, 255, 0]
+    };
+
+    Color.prototype = {
+        scale: function (rf, gf, bf, af) {
+            var x = 4;
+            while (-1 < --x) {
+                if (!_.isUndefined(arguments[x])) this[this.rgba[x]] *= arguments[x];
+            }
+            return this.normalize();
+        },
+        alpha: function (alpha) {
+            if (!_.isUndefined(alpha) && !_.isNull(alpha)) {
+                this.a = alpha;
+            }
+            return this.normalize();
+        },
+        clone: function () {
+            return new Color(this.r, this.b, this.g, this.a);
+        },
+        limit: function (val, minVal, maxVal) {
+            return Math.max(Math.min(val, maxVal), minVal);
+        },
+        normalize: function () {
+            var limit = this.limit;
+            this.r = limit(parseInt(this.r, 10), 0, 255);
+            this.g = limit(parseInt(this.g, 10), 0, 255);
+            this.b = limit(parseInt(this.b, 10), 0, 255);
+            this.a = limit(this.a, 0, 1);
+            return this;
+        },
+        distance: function (color) {
+            if (!color) return;
+            color = new Color.parse(color);
+            var dist = 0, x = 3;
+            while (-1 < --x) {
+                dist += Math.abs(this[this.rgba[x]] - color[this.rgba[x]]);
+            }
+            return dist;
+        },
+        toString: function () {
+            return (this.a >= 1.0) ? 'rgb(' + [this.r, this.g, this.b].join(',') + ')' : 'rgba(' + [this.r, this.g, this.b, this.a].join(',') + ')';
+        },
+        contrast: function () {
+            var
+                test = 1 - ( 0.299 * this.r + 0.587 * this.g + 0.114 * this.b) / 255;
+            return (test < 0.5 ? '#000000' : '#ffffff');
+        }
+    };
+
+    _.extend(Color, {
+        /**
+         * Parses a color string and returns a corresponding Color.
+         * The different tests are in order of probability to improve speed.
+         * @param {String, Color} str - string thats representing a color
+         * @return {Color} returns a Color object or false
+         */
+        parse: function (color) {
+            if (color instanceof Color) return color;
+
+            var result;
+
+            // #a0b1c2
+            if ((result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color)))
+                return new Color(parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16));
+
+            // rgb(num,num,num)
+            if ((result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color)))
+                return new Color(parseInt(result[1], 10), parseInt(result[2], 10), parseInt(result[3], 10));
+
+            // #fff
+            if ((result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color)))
+                return new Color(parseInt(result[1] + result[1], 16), parseInt(result[2] + result[2], 16), parseInt(result[3] + result[3], 16));
+
+            // rgba(num,num,num,num)
+            if ((result = /rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(color)))
+                return new Color(parseInt(result[1], 10), parseInt(result[2], 10), parseInt(result[3], 10), parseFloat(result[4]));
+
+            // rgb(num%,num%,num%)
+            if ((result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color)))
+                return new Color(parseFloat(result[1]) * 2.55, parseFloat(result[2]) * 2.55, parseFloat(result[3]) * 2.55);
+
+            // rgba(num%,num%,num%,num)
+            if ((result = /rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(color)))
+                return new Color(parseFloat(result[1]) * 2.55, parseFloat(result[2]) * 2.55, parseFloat(result[3]) * 2.55, parseFloat(result[4]));
+
+            // Otherwise, we're most likely dealing with a named color.
+            var name = (color + '').replace(/^\s*([\S\s]*?)\s*$/, '$1').toLowerCase();
+            if (name == 'transparent') {
+                return new Color(255, 255, 255, 0);
+            }
+            return (result = COLOR_NAMES[name]) ? new Color(result[0], result[1], result[2]) : new Color(0, 0, 0, 0);
+        },
+
+        /**
+         * Process color and options into color style.
+         */
+        processColor: function (color, options) {
+
+            var opacity = options.opacity;
+            if (!color) return 'rgba(0, 0, 0, 0)';
+            if (color instanceof Color) return color.alpha(opacity).toString();
+            if (_.isString(color)) return Color.parse(color).alpha(opacity).toString();
+
+            var grad = color.colors ? color : {colors: color};
+
+            if (!options.ctx) {
+                if (!_.isArray(grad.colors)) return 'rgba(0, 0, 0, 0)';
+                return Color.parse(_.isArray(grad.colors[0]) ? grad.colors[0][1] : grad.colors[0]).alpha(opacity).toString();
+            }
+            grad = _.extend({start: 'top', end: 'bottom'}, grad);
+
+            if (/top/i.test(grad.start))  options.x1 = 0;
+            if (/left/i.test(grad.start)) options.y1 = 0;
+            if (/bottom/i.test(grad.end)) options.x2 = 0;
+            if (/right/i.test(grad.end))  options.y2 = 0;
+
+            var i, c, stop, gradient = options.ctx.createLinearGradient(options.x1, options.y1, options.x2, options.y2);
+            for (i = 0; i < grad.colors.length; i++) {
+                c = grad.colors[i];
+                if (_.isArray(c)) {
+                    stop = c[0];
+                    c = c[1];
+                }
+                else stop = i / (grad.colors.length - 1);
+                gradient.addColorStop(stop, Color.parse(c).alpha(opacity));
+            }
+            return gradient;
+        }
+    });
+
+    Flotr.Color = Color;
 
 })();
 
@@ -1859,295 +1870,332 @@
  */
 Flotr.Date = {
 
-  set : function (date, name, mode, value) {
-    mode = mode || 'UTC';
-    name = 'set' + (mode === 'UTC' ? 'UTC' : '') + name;
-    date[name](value);
-  },
-
-  get : function (date, name, mode) {
-    mode = mode || 'UTC';
-    name = 'get' + (mode === 'UTC' ? 'UTC' : '') + name;
-    return date[name]();
-  },
-
-  format: function(d, format, mode) {
-    if (!d) return;
-
-    // We should maybe use an "official" date format spec, like PHP date() or ColdFusion 
-    // http://fr.php.net/manual/en/function.date.php
-    // http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=functions_c-d_29.html
-    var
-      get = this.get,
-      tokens = {
-        h: get(d, 'Hours', mode).toString(),
-        H: leftPad(get(d, 'Hours', mode)),
-        M: leftPad(get(d, 'Minutes', mode)),
-        S: leftPad(get(d, 'Seconds', mode)),
-        s: get(d, 'Milliseconds', mode),
-        d: get(d, 'Date', mode).toString(),
-        m: (get(d, 'Month') + 1).toString(),
-        y: get(d, 'FullYear').toString(),
-        b: Flotr.Date.monthNames[get(d, 'Month', mode)]
-      };
-
-    function leftPad(n){
-      n += '';
-      return n.length == 1 ? "0" + n : n;
-    }
-    
-    var r = [], c,
-        escape = false;
-    
-    for (var i = 0; i < format.length; ++i) {
-      c = format.charAt(i);
-      
-      if (escape) {
-        r.push(tokens[c] || c);
-        escape = false;
-      }
-      else if (c == "%")
-        escape = true;
-      else
-        r.push(c);
-    }
-    return r.join('');
-  },
-  getFormat: function(time, span) {
-    var tu = Flotr.Date.timeUnits;
-         if (time < tu.second) return "%h:%M:%S.%s";
-    else if (time < tu.minute) return "%h:%M:%S";
-    else if (time < tu.day)    return (span < 2 * tu.day) ? "%h:%M" : "%b %d %h:%M";
-    else if (time < tu.month)  return "%b %d";
-    else if (time < tu.year)   return (span < tu.year) ? "%b" : "%b %y";
-    else                       return "%y";
-  },
-  formatter: function (v, axis) {
-    var
-      options = axis.options,
-      scale = Flotr.Date.timeUnits[options.timeUnit],
-      d = new Date(v * scale);
-
-    // first check global format
-    if (axis.options.timeFormat)
-      return Flotr.Date.format(d, options.timeFormat, options.timeMode);
-    
-    var span = (axis.max - axis.min) * scale,
-        t = axis.tickSize * Flotr.Date.timeUnits[axis.tickUnit];
-
-    return Flotr.Date.format(d, Flotr.Date.getFormat(t, span), options.timeMode);
-  },
-  generator: function(axis) {
-
-     var
-      set       = this.set,
-      get       = this.get,
-      timeUnits = this.timeUnits,
-      spec      = this.spec,
-      options   = axis.options,
-      mode      = options.timeMode,
-      scale     = timeUnits[options.timeUnit],
-      min       = axis.min * scale,
-      max       = axis.max * scale,
-      delta     = (max - min) / options.noTicks,
-      ticks     = [],
-      tickSize  = axis.tickSize,
-      tickUnit,
-      formatter, i;
-
-    // Use custom formatter or time tick formatter
-    formatter = (options.tickFormatter === Flotr.defaultTickFormatter ?
-      this.formatter : options.tickFormatter
-    );
-
-    for (i = 0; i < spec.length - 1; ++i) {
-      var d = spec[i][0] * timeUnits[spec[i][1]];
-      if (delta < (d + spec[i+1][0] * timeUnits[spec[i+1][1]]) / 2 && d >= tickSize)
-        break;
-    }
-    tickSize = spec[i][0];
-    tickUnit = spec[i][1];
-
-    // special-case the possibility of several years
-    if (tickUnit == "year") {
-      tickSize = Flotr.getTickSize(options.noTicks*timeUnits.year, min, max, 0);
-
-      // Fix for 0.5 year case
-      if (tickSize == 0.5) {
-        tickUnit = "month";
-        tickSize = 6;
-      }
-    }
-
-    axis.tickUnit = tickUnit;
-    axis.tickSize = tickSize;
-
-    var
-      d = new Date(min);
-
-    var step = tickSize * timeUnits[tickUnit];
-
-    function setTick (name) {
-      set(d, name, mode, Flotr.floorInBase(
-        get(d, name, mode), tickSize
-      ));
-    }
-
-    switch (tickUnit) {
-      case "millisecond": setTick('Milliseconds'); break;
-      case "second": setTick('Seconds'); break;
-      case "minute": setTick('Minutes'); break;
-      case "hour": setTick('Hours'); break;
-      case "month": setTick('Month'); break;
-      case "year": setTick('FullYear'); break;
-    }
-    
-    // reset smaller components
-    if (step >= timeUnits.second)  set(d, 'Milliseconds', mode, 0);
-    if (step >= timeUnits.minute)  set(d, 'Seconds', mode, 0);
-    if (step >= timeUnits.hour)    set(d, 'Minutes', mode, 0);
-    if (step >= timeUnits.day)     set(d, 'Hours', mode, 0);
-    if (step >= timeUnits.day * 4) set(d, 'Date', mode, 1);
-    if (step >= timeUnits.year)    set(d, 'Month', mode, 0);
-
-    var carry = 0, v = NaN, prev;
-    do {
-      prev = v;
-      v = d.getTime();
-      ticks.push({ v: v / scale, label: formatter(v / scale, axis) });
-      if (tickUnit == "month") {
-        if (tickSize < 1) {
-          /* a bit complicated - we'll divide the month up but we need to take care of fractions
-           so we don't end up in the middle of a day */
-          set(d, 'Date', mode, 1);
-          var start = d.getTime();
-          set(d, 'Month', mode, get(d, 'Month', mode) + 1)
-          var end = d.getTime();
-          d.setTime(v + carry * timeUnits.hour + (end - start) * tickSize);
-          carry = get(d, 'Hours', mode)
-          set(d, 'Hours', mode, 0);
-        }
-        else
-          set(d, 'Month', mode, get(d, 'Month', mode) + tickSize);
-      }
-      else if (tickUnit == "year") {
-        set(d, 'FullYear', mode, get(d, 'FullYear', mode) + tickSize);
-      }
-      else
-        d.setTime(v + step);
-
-    } while (v < max && v != prev);
-
-    return ticks;
-  },
-  timeUnits: {
-    millisecond: 1,
-    second: 1000,
-    minute: 1000 * 60,
-    hour:   1000 * 60 * 60,
-    day:    1000 * 60 * 60 * 24,
-    month:  1000 * 60 * 60 * 24 * 30,
-    year:   1000 * 60 * 60 * 24 * 365.2425
-  },
-  // the allowed tick sizes, after 1 year we use an integer algorithm
-  spec: [
-    [1, "millisecond"], [20, "millisecond"], [50, "millisecond"], [100, "millisecond"], [200, "millisecond"], [500, "millisecond"], 
-    [1, "second"],   [2, "second"],  [5, "second"], [10, "second"], [30, "second"], 
-    [1, "minute"],   [2, "minute"],  [5, "minute"], [10, "minute"], [30, "minute"], 
-    [1, "hour"],     [2, "hour"],    [4, "hour"],   [8, "hour"],    [12, "hour"],
-    [1, "day"],      [2, "day"],     [3, "day"],
-    [0.25, "month"], [0.5, "month"], [1, "month"],  [2, "month"],   [3, "month"], [6, "month"],
-    [1, "year"]
-  ],
-  monthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
+    set: function (date, name, mode, value) {
+        mode = mode || 'UTC';
+        name = 'set' + (mode === 'UTC' ? 'UTC' : '') + name;
+        date[name](value);
+    },
+
+    get: function (date, name, mode) {
+        mode = mode || 'UTC';
+        name = 'get' + (mode === 'UTC' ? 'UTC' : '') + name;
+        return date[name]();
+    },
+
+    format: function (d, format, mode) {
+        if (!d) return;
+
+        // We should maybe use an "official" date format spec, like PHP date() or ColdFusion 
+        // http://fr.php.net/manual/en/function.date.php
+        // http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=functions_c-d_29.html
+        var
+            get = this.get,
+            tokens = {
+                h: get(d, 'Hours', mode).toString(),
+                H: leftPad(get(d, 'Hours', mode)),
+                M: leftPad(get(d, 'Minutes', mode)),
+                S: leftPad(get(d, 'Seconds', mode)),
+                s: get(d, 'Milliseconds', mode),
+                d: get(d, 'Date', mode).toString(),
+                m: (get(d, 'Month') + 1).toString(),
+                y: get(d, 'FullYear').toString(),
+                b: Flotr.Date.monthNames[get(d, 'Month', mode)]
+            };
+
+        function leftPad(n) {
+            n += '';
+            return n.length == 1 ? "0" + n : n;
+        }
+
+        var r = [], c,
+            escape = false;
+
+        for (var i = 0; i < format.length; ++i) {
+            c = format.charAt(i);
+
+            if (escape) {
+                r.push(tokens[c] || c);
+                escape = false;
+            }
+            else if (c == "%")
+                escape = true;
+            else
+                r.push(c);
+        }
+        return r.join('');
+    },
+    getFormat: function (time, span) {
+        var tu = Flotr.Date.timeUnits;
+        if (time < tu.second) return "%h:%M:%S.%s";
+        else if (time < tu.minute) return "%h:%M:%S";
+        else if (time < tu.day)    return (span < 2 * tu.day) ? "%h:%M" : "%b %d %h:%M";
+        else if (time < tu.month)  return "%b %d";
+        else if (time < tu.year)   return (span < tu.year) ? "%b" : "%b %y";
+        else                       return "%y";
+    },
+    formatter: function (v, axis) {
+        var
+            options = axis.options,
+            scale = Flotr.Date.timeUnits[options.timeUnit],
+            d = new Date(v * scale);
+
+        // first check global format
+        if (axis.options.timeFormat)
+            return Flotr.Date.format(d, options.timeFormat, options.timeMode);
+
+        var span = (axis.max - axis.min) * scale,
+            t = axis.tickSize * Flotr.Date.timeUnits[axis.tickUnit];
+
+        return Flotr.Date.format(d, Flotr.Date.getFormat(t, span), options.timeMode);
+    },
+    generator: function (axis) {
+
+        var
+            set = this.set,
+            get = this.get,
+            timeUnits = this.timeUnits,
+            spec = this.spec,
+            options = axis.options,
+            mode = options.timeMode,
+            scale = timeUnits[options.timeUnit],
+            min = axis.min * scale,
+            max = axis.max * scale,
+            delta = (max - min) / options.noTicks,
+            ticks = [],
+            tickSize = axis.tickSize,
+            tickUnit,
+            formatter, i;
+
+        // Use custom formatter or time tick formatter
+        formatter = (options.tickFormatter === Flotr.defaultTickFormatter ?
+            this.formatter : options.tickFormatter
+            );
+
+        for (i = 0; i < spec.length - 1; ++i) {
+            var d = spec[i][0] * timeUnits[spec[i][1]];
+            if (delta < (d + spec[i + 1][0] * timeUnits[spec[i + 1][1]]) / 2 && d >= tickSize)
+                break;
+        }
+        tickSize = spec[i][0];
+        tickUnit = spec[i][1];
+
+        // special-case the possibility of several years
+        if (tickUnit == "year") {
+            tickSize = Flotr.getTickSize(options.noTicks * timeUnits.year, min, max, 0);
+
+            // Fix for 0.5 year case
+            if (tickSize == 0.5) {
+                tickUnit = "month";
+                tickSize = 6;
+            }
+        }
+
+        axis.tickUnit = tickUnit;
+        axis.tickSize = tickSize;
+
+        var
+            d = new Date(min);
+
+        var step = tickSize * timeUnits[tickUnit];
+
+        function setTick(name) {
+            set(d, name, mode, Flotr.floorInBase(
+                get(d, name, mode), tickSize
+            ));
+        }
+
+        switch (tickUnit) {
+            case "millisecond":
+                setTick('Milliseconds');
+                break;
+            case "second":
+                setTick('Seconds');
+                break;
+            case "minute":
+                setTick('Minutes');
+                break;
+            case "hour":
+                setTick('Hours');
+                break;
+            case "month":
+                setTick('Month');
+                break;
+            case "year":
+                setTick('FullYear');
+                break;
+        }
+
+        // reset smaller components
+        if (step >= timeUnits.second)  set(d, 'Milliseconds', mode, 0);
+        if (step >= timeUnits.minute)  set(d, 'Seconds', mode, 0);
+        if (step >= timeUnits.hour)    set(d, 'Minutes', mode, 0);
+        if (step >= timeUnits.day)     set(d, 'Hours', mode, 0);
+        if (step >= timeUnits.day * 4) set(d, 'Date', mode, 1);
+        if (step >= timeUnits.year)    set(d, 'Month', mode, 0);
+
+        var carry = 0, v = NaN, prev;
+        do {
+            prev = v;
+            v = d.getTime();
+            ticks.push({ v: v / scale, label: formatter(v / scale, axis) });
+            if (tickUnit == "month") {
+                if (tickSize < 1) {
+                    /* a bit complicated - we'll divide the month up but we need to take care of fractions
+                     so we don't end up in the middle of a day */
+                    set(d, 'Date', mode, 1);
+                    var start = d.getTime();
+                    set(d, 'Month', mode, get(d, 'Month', mode) + 1)
+                    var end = d.getTime();
+                    d.setTime(v + carry * timeUnits.hour + (end - start) * tickSize);
+                    carry = get(d, 'Hours', mode)
+                    set(d, 'Hours', mode, 0);
+                }
+                else
+                    set(d, 'Month', mode, get(d, 'Month', mode) + tickSize);
+            }
+            else if (tickUnit == "year") {
+                set(d, 'FullYear', mode, get(d, 'FullYear', mode) + tickSize);
+            }
+            else
+                d.setTime(v + step);
+
+        } while (v < max && v != prev);
+
+        return ticks;
+    },
+    timeUnits: {
+        millisecond: 1,
+        second: 1000,
+        minute: 1000 * 60,
+        hour: 1000 * 60 * 60,
+        day: 1000 * 60 * 60 * 24,
+        month: 1000 * 60 * 60 * 24 * 30,
+        year: 1000 * 60 * 60 * 24 * 365.2425
+    },
+    // the allowed tick sizes, after 1 year we use an integer algorithm
+    spec: [
+        [1, "millisecond"],
+        [20, "millisecond"],
+        [50, "millisecond"],
+        [100, "millisecond"],
+        [200, "millisecond"],
+        [500, "millisecond"],
+        [1, "second"],
+        [2, "second"],
+        [5, "second"],
+        [10, "second"],
+        [30, "second"],
+        [1, "minute"],
+        [2, "minute"],
+        [5, "minute"],
+        [10, "minute"],
+        [30, "minute"],
+        [1, "hour"],
+        [2, "hour"],
+        [4, "hour"],
+        [8, "hour"],
+        [12, "hour"],
+        [1, "day"],
+        [2, "day"],
+        [3, "day"],
+        [0.25, "month"],
+        [0.5, "month"],
+        [1, "month"],
+        [2, "month"],
+        [3, "month"],
+        [6, "month"],
+        [1, "year"]
+    ],
+    monthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
 };
 
 (function () {
 
-var _ = Flotr._;
-
-Flotr.DOM = {
-  addClass: function(element, name){
-    var classList = (element.className ? element.className : '');
-      if (_.include(classList.split(/\s+/g), name)) return;
-    element.className = (classList ? classList + ' ' : '') + name;
-  },
-  /**
-   * Create an element.
-   */
-  create: function(tag){
-    return document.createElement(tag);
-  },
-  node: function(html) {
-    var div = Flotr.DOM.create('div'), n;
-    div.innerHTML = html;
-    n = div.children[0];
-    div.innerHTML = '';
-    return n;
-  },
-  /**
-   * Remove all children.
-   */
-  empty: function(element){
-    element.innerHTML = '';
-    /*
-    if (!element) return;
-    _.each(element.childNodes, function (e) {
-      Flotr.DOM.empty(e);
-      element.removeChild(e);
-    });
-    */
-  },
-  hide: function(element){
-    Flotr.DOM.setStyles(element, {display:'none'});
-  },
-  /**
-   * Insert a child.
-   * @param {Element} element
-   * @param {Element|String} Element or string to be appended.
-   */
-  insert: function(element, child){
-    if(_.isString(child))
-      element.innerHTML += child;
-    else if (_.isElement(child))
-      element.appendChild(child);
-  },
-  // @TODO find xbrowser implementation
-  opacity: function(element, opacity) {
-    element.style.opacity = opacity;
-  },
-  position: function(element, p){
-    if (!element.offsetParent)
-      return {left: (element.offsetLeft || 0), top: (element.offsetTop || 0)};
-
-    p = this.position(element.offsetParent);
-    p.left  += element.offsetLeft;
-    p.top   += element.offsetTop;
-    return p;
-  },
-  removeClass: function(element, name) {
-    var classList = (element.className ? element.className : '');
-    element.className = _.filter(classList.split(/\s+/g), function (c) {
-      if (c != name) return true; }
-    ).join(' ');
-  },
-  setStyles: function(element, o) {
-    _.each(o, function (value, key) {
-      element.style[key] = value;
-    });
-  },
-  show: function(element){
-    Flotr.DOM.setStyles(element, {display:''});
-  },
-  /**
-   * Return element size.
-   */
-  size: function(element){
-    return {
-      height : element.offsetHeight,
-      width : element.offsetWidth };
-  }
-};
+    var _ = Flotr._;
+
+    Flotr.DOM = {
+        addClass: function (element, name) {
+            var classList = (element.className ? element.className : '');
+            if (_.include(classList.split(/\s+/g), name)) return;
+            element.className = (classList ? classList + ' ' : '') + name;
+        },
+        /**
+         * Create an element.
+         */
+        create: function (tag) {
+            return document.createElement(tag);
+        },
+        node: function (html) {
+            var div = Flotr.DOM.create('div'), n;
+            div.innerHTML = html;
+            n = div.children[0];
+            div.innerHTML = '';
+            return n;
+        },
+        /**
+         * Remove all children.
+         */
+        empty: function (element) {
+            element.innerHTML = '';
+            /*
+             if (!element) return;
+             _.each(element.childNodes, function (e) {
+             Flotr.DOM.empty(e);
+             element.removeChild(e);
+             });
+             */
+        },
+        hide: function (element) {
+            Flotr.DOM.setStyles(element, {display: 'none'});
+        },
+        /**
+         * Insert a child.
+         * @param {Element} element
+         * @param {Element|String} Element or string to be appended.
+         */
+        insert: function (element, child) {
+            if (_.isString(child))
+                element.innerHTML += child;
+            else if (_.isElement(child))
+                element.appendChild(child);
+        },
+        // @TODO find xbrowser implementation
+        opacity: function (element, opacity) {
+            element.style.opacity = opacity;
+        },
+        position: function (element, p) {
+            if (!element.offsetParent)
+                return {left: (element.offsetLeft || 0), top: (element.offsetTop || 0)};
+
+            p = this.position(element.offsetParent);
+            p.left += element.offsetLeft;
+            p.top += element.offsetTop;
+            return p;
+        },
+        removeClass: function (element, name) {
+            var classList = (element.className ? element.className : '');
+            element.className = _.filter(classList.split(/\s+/g),function (c) {
+                    if (c != name) return true;
+                }
+            ).join(' ');
+        },
+        setStyles: function (element, o) {
+            _.each(o, function (value, key) {
+                element.style[key] = value;
+            });
+        },
+        show: function (element) {
+            Flotr.DOM.setStyles(element, {display: ''});
+        },
+        /**
+         * Return element size.
+         */
+        size: function (element) {
+            return {
+                height: element.offsetHeight,
+                width: element.offsetWidth };
+        }
+    };
 
 })();
 
@@ -2155,53 +2203,53 @@
  * Flotr Event Adapter
  */
 (function () {
-var
-  F = Flotr,
-  bean = F.bean;
-F.EventAdapter = {
-  observe: function(object, name, callback) {
-    bean.add(object, name, callback);
-    return this;
-  },
-  fire: function(object, name, args) {
-    bean.fire(object, name, args);
-    if (typeof(Prototype) != 'undefined')
-      Event.fire(object, name, args);
-    // @TODO Someone who uses mootools, add mootools adapter for existing applciations.
-    return this;
-  },
-  stopObserving: function(object, name, callback) {
-    bean.remove(object, name, callback);
-    return this;
-  },
-  eventPointer: function(e) {
-    if (!F._.isUndefined(e.touches) && e.touches.length > 0) {
-      return {
-        x : e.touches[0].pageX,
-        y : e.touches[0].pageY
-      };
-    } else if (!F._.isUndefined(e.changedTouches) && e.changedTouches.length > 0) {
-      return {
-        x : e.changedTouches[0].pageX,
-        y : e.changedTouches[0].pageY
-      };
-    } else if (e.pageX || e.pageY) {
-      return {
-        x : e.pageX,
-        y : e.pageY
-      };
-    } else if (e.clientX || e.clientY) {
-      var
-        d = document,
-        b = d.body,
-        de = d.documentElement;
-      return {
-        x: e.clientX + b.scrollLeft + de.scrollLeft,
-        y: e.clientY + b.scrollTop + de.scrollTop
-      };
-    }
-  }
-};
+    var
+        F = Flotr,
+        bean = F.bean;
+    F.EventAdapter = {
+        observe: function (object, name, callback) {
+            bean.add(object, name, callback);
+            return this;
+        },
+        fire: function (object, name, args) {
+            bean.fire(object, name, args);
+            if (typeof(Prototype) != 'undefined')
+                Event.fire(object, name, args);
+            // @TODO Someone who uses mootools, add mootools adapter for existing applciations.
+            return this;
+        },
+        stopObserving: function (object, name, callback) {
+            bean.remove(object, name, callback);
+            return this;
+        },
+        eventPointer: function (e) {
+            if (!F._.isUndefined(e.touches) && e.touches.length > 0) {
+                return {
+                    x: e.touches[0].pageX,
+                    y: e.touches[0].pageY
+                };
+            } else if (!F._.isUndefined(e.changedTouches) && e.changedTouches.length > 0) {
+                return {
+                    x: e.changedTouches[0].pageX,
+                    y: e.changedTouches[0].pageY
+                };
+            } else if (e.pageX || e.pageY) {
+                return {
+                    x: e.pageX,
+                    y: e.pageY
+                };
+            } else if (e.clientX || e.clientY) {
+                var
+                    d = document,
+                    b = d.body,
+                    de = d.documentElement;
+                return {
+                    x: e.clientX + b.scrollLeft + de.scrollLeft,
+                    y: e.clientY + b.scrollTop + de.scrollTop
+                };
+            }
+        }
+    };
 })();
 
 /**
@@ -2209,87 +2257,87 @@
  */
 (function () {
 
-var
-  F = Flotr,
-  D = F.DOM,
-  _ = F._,
-
-Text = function (o) {
-  this.o = o;
-};
-
-Text.prototype = {
-
-  dimensions : function (text, canvasStyle, htmlStyle, className) {
-
-    if (!text) return { width : 0, height : 0 };
-    
-    return (this.o.html) ?
-      this.html(text, this.o.element, htmlStyle, className) : 
-      this.canvas(text, canvasStyle);
-  },
-
-  canvas : function (text, style) {
-
-    if (!this.o.textEnabled) return;
-    style = style || {};
-
     var
-      metrics = this.measureText(text, style),
-      width = metrics.width,
-      height = style.size || F.defaultOptions.fontSize,
-      angle = style.angle || 0,
-      cosAngle = Math.cos(angle),
-      sinAngle = Math.sin(angle),
-      widthPadding = 2,
-      heightPadding = 6,
-      bounds;
-
-    bounds = {
-      width: Math.abs(cosAngle * width) + Math.abs(sinAngle * height) + widthPadding,
-      height: Math.abs(sinAngle * width) + Math.abs(cosAngle * height) + heightPadding
-    };
-
-    return bounds;
-  },
-
-  html : function (text, element, style, className) {
-
-    var div = D.create('div');
-
-    D.setStyles(div, { 'position' : 'absolute', 'top' : '-10000px' });
-    D.insert(div, '<div style="'+style+'" class="'+className+' flotr-dummy-div">' + text + '</div>');
-    D.insert(this.o.element, div);
-
-    return D.size(div);
-  },
-
-  measureText : function (text, style) {
-
-    var
-      context = this.o.ctx,
-      metrics;
-
-    if (!context.fillText || (F.isIphone && context.measure)) {
-      return { width : context.measure(text, style)};
-    }
-
-    style = _.extend({
-      size: F.defaultOptions.fontSize,
-      weight: 1,
-      angle: 0
-    }, style);
-
-    context.save();
-    context.font = (style.weight > 1 ? "bold " : "") + (style.size*1.3) + "px sans-serif";
-    metrics = context.measureText(text);
-    context.restore();
-
-    return metrics;
-  }
-};
-
-Flotr.Text = Text;
+        F = Flotr,
+        D = F.DOM,
+        _ = F._,
+
+        Text = function (o) {
+            this.o = o;
+        };
+
+    Text.prototype = {
+
+        dimensions: function (text, canvasStyle, htmlStyle, className) {
+
+            if (!text) return { width: 0, height: 0 };
+
+            return (this.o.html) ?
+                this.html(text, this.o.element, htmlStyle, className) :
+                this.canvas(text, canvasStyle);
+        },
+
+        canvas: function (text, style) {
+
+            if (!this.o.textEnabled) return;
+            style = style || {};
+
+            var
+                metrics = this.measureText(text, style),
+                width = metrics.width,
+                height = style.size || F.defaultOptions.fontSize,
+                angle = style.angle || 0,
+                cosAngle = Math.cos(angle),
+                sinAngle = Math.sin(angle),
+                widthPadding = 2,
+                heightPadding = 6,
+                bounds;
+
+            bounds = {
+                width: Math.abs(cosAngle * width) + Math.abs(sinAngle * height) + widthPadding,
+                height: Math.abs(sinAngle * width) + Math.abs(cosAngle * height) + heightPadding
+            };
+
+            return bounds;
+        },
+
+        html: function (text, element, style, className) {
+
+            var div = D.create('div');
+
+            D.setStyles(div, { 'position': 'absolute', 'top': '-10000px' });
+            D.insert(div, '<div style="' + style + '" class="' + className + ' flotr-dummy-div">' + text + '</div>');
+            D.insert(this.o.element, div);
+
+            return D.size(div);
+        },
+
+        measureText: function (text, style) {
+
+            var
+                context = this.o.ctx,
+                metrics;
+
+            if (!context.fillText || (F.isIphone && context.measure)) {
+                return { width: context.measure(text, style)};
+            }
+
+            style = _.extend({
+                size: F.defaultOptions.fontSize,
+                weight: 1,
+                angle: 0
+            }, style);
+
+            context.save();
+            context.font = (style.weight > 1 ? "bold " : "") + (style.size * 1.3) + "px sans-serif";
+            metrics = context.measureText(text);
+            context.restore();
+
+            return metrics;
+        }
+    };
+
+    Flotr.Text = Text;
 
 })();
 
@@ -2298,745 +2346,745 @@
  */
 (function () {
 
-var
-  D     = Flotr.DOM,
-  E     = Flotr.EventAdapter,
-  _     = Flotr._,
-  flotr = Flotr;
-/**
- * Flotr Graph constructor.
- * @param {Element} el - element to insert the graph into
- * @param {Object} data - an array or object of dataseries
- * @param {Object} options - an object containing options
- */
-Graph = function(el, data, options){
+    var
+        D = Flotr.DOM,
+        E = Flotr.EventAdapter,
+        _ = Flotr._,
+        flotr = Flotr;
+    /**
+     * Flotr Graph constructor.
+     * @param {Element} el - element to insert the graph into
+     * @param {Object} data - an array or object of dataseries
+     * @param {Object} options - an object containing options
+     */
+    Graph = function (el, data, options) {
 // Let's see if we can get away with out this [JS]
 //  try {
-    this._setEl(el);
-    this._initMembers();
-    this._initPlugins();
-
-    E.fire(this.el, 'flotr:beforeinit', [this]);
-
-    this.data = data;
-    this.series = flotr.Series.getSeries(data);
-    this._initOptions(options);
-    this._initGraphTypes();
-    this._initCanvas();
-    this._text = new flotr.Text({
-      element : this.el,
-      ctx : this.ctx,
-      html : this.options.HtmlText,
-      textEnabled : this.textEnabled
-    });
-    E.fire(this.el, 'flotr:afterconstruct', [this]);
-    this._initEvents();
-
-    this.findDataRanges();
-    this.calculateSpacing();
-
-    this.draw(_.bind(function() {
-      E.fire(this.el, 'flotr:afterinit', [this]);
-    }, this));
-/*
-    try {
-  } catch (e) {
-    try {
-      console.error(e);
-    } catch (e2) {}
-  }*/
-};
-
-function observe (object, name, callback) {
-  E.observe.apply(this, arguments);
-  this._handles.push(arguments);
-  return this;
-}
-
-Graph.prototype = {
-
-  destroy: function () {
-    E.fire(this.el, 'flotr:destroy');
-    _.each(this._handles, function (handle) {
-      E.stopObserving.apply(this, handle);
-    });
-    this._handles = [];
-    this.el.graph = null;
-  },
-
-  observe : observe,
-
-  /**
-   * @deprecated
-   */
-  _observe : observe,
-
-  processColor: function(color, options){
-    var o = { x1: 0, y1: 0, x2: this.plotWidth, y2: this.plotHeight, opacity: 1, ctx: this.ctx };
-    _.extend(o, options);
-    return flotr.Color.processColor(color, o);
-  },
-  /**
-   * Function determines the min and max values for the xaxis and yaxis.
-   *
-   * TODO logarithmic range validation (consideration of 0)
-   */
-  findDataRanges: function(){
-    var a = this.axes,
-      xaxis, yaxis, range;
-
-    _.each(this.series, function (series) {
-      range = series.getRange();
-      if (range) {
-        xaxis = series.xaxis;
-        yaxis = series.yaxis;
-        xaxis.datamin = Math.min(range.xmin, xaxis.datamin);
-        xaxis.datamax = Math.max(range.xmax, xaxis.datamax);
-        yaxis.datamin = Math.min(range.ymin, yaxis.datamin);
-        yaxis.datamax = Math.max(range.ymax, yaxis.datamax);
-        xaxis.used = (xaxis.used || range.xused);
-        yaxis.used = (yaxis.used || range.yused);
-      }
-    }, this);
-
-    // Check for empty data, no data case (none used)
-    if (!a.x.used && !a.x2.used) a.x.used = true;
-    if (!a.y.used && !a.y2.used) a.y.used = true;
-
-    _.each(a, function (axis) {
-      axis.calculateRange();
-    });
-
-    var
-      types = _.keys(flotr.graphTypes),
-      drawn = false;
-
-    _.each(this.series, function (series) {
-      if (series.hide) return;
-      _.each(types, function (type) {
-        if (series[type] && series[type].show) {
-          this.extendRange(type, series);
-          drawn = true;
-        }
-      }, this);
-      if (!drawn) {
-        this.extendRange(this.options.defaultType, series);
-      }
-    }, this);
-  },
-
-  extendRange : function (type, series) {
-    if (this[type].extendRange) this[type].extendRange(series, series.data, series[type], this[type]);
-    if (this[type].extendYRange) this[type].extendYRange(series.yaxis, series.data, series[type], this[type]);
-    if (this[type].extendXRange) this[type].extendXRange(series.xaxis, series.data, series[type], this[type]);
-  },
-
-  /**
-   * Calculates axis label sizes.
-   */
-  calculateSpacing: function(){
-
-    var a = this.axes,
-        options = this.options,
-        series = this.series,
-        margin = options.grid.labelMargin,
-        T = this._text,
-        x = a.x,
-        x2 = a.x2,
-        y = a.y,
-        y2 = a.y2,
-        maxOutset = options.grid.outlineWidth,
-        i, j, l, dim;
-
-    // TODO post refactor, fix this
-    _.each(a, function (axis) {
-      axis.calculateTicks();
-      axis.calculateTextDimensions(T, options);
-    });
-
-    // Title height
-    dim = T.dimensions(
-      options.title,
-      {size: options.fontSize*1.5},
-      'font-size:1em;font-weight:bold;',
-      'flotr-title'
-    );
-    this.titleHeight = dim.height;
-
-    // Subtitle height
-    dim = T.dimensions(
-      options.subtitle,
-      {size: options.fontSize},
-      'font-size:smaller;',
-      'flotr-subtitle'
-    );
-    this.subtitleHeight = dim.height;
-
-    for(j = 0; j < options.length; ++j){
-      if (series[j].points.show){
-        maxOutset = Math.max(maxOutset, series[j].points.radius + series[j].points.lineWidth/2);
-      }
+        this._setEl(el);
+        this._initMembers();
+        this._initPlugins();
+
+        E.fire(this.el, 'flotr:beforeinit', [this]);
+
+        this.data = data;
+        this.series = flotr.Series.getSeries(data);
+        this._initOptions(options);
+        this._initGraphTypes();
+        this._initCanvas();
+        this._text = new flotr.Text({
+            element: this.el,
+            ctx: this.ctx,
+            html: this.options.HtmlText,
+            textEnabled: this.textEnabled
+        });
+        E.fire(this.el, 'flotr:afterconstruct', [this]);
+        this._initEvents();
+
+        this.findDataRanges();
+        this.calculateSpacing();
+
+        this.draw(_.bind(function () {
+            E.fire(this.el, 'flotr:afterinit', [this]);
+        }, this));
+        /*
+         try {
+         } catch (e) {
+         try {
+         console.error(e);
+         } catch (e2) {}
+         }*/
+    };
+
+    function observe(object, name, callback) {
+        E.observe.apply(this, arguments);
+        this._handles.push(arguments);
+        return this;
     }
 
-    var p = this.plotOffset;
-    if (x.options.margin === false) {
-      p.bottom = 0;
-      p.top    = 0;
-    } else {
-      p.bottom += (options.grid.circular ? 0 : (x.used && x.options.showLabels ?  (x.maxLabel.height + margin) : 0)) +
-                  (x.used && x.options.title ? (x.titleSize.height + margin) : 0) + maxOutset;
-
-      p.top    += (options.grid.circular ? 0 : (x2.used && x2.options.showLabels ? (x2.maxLabel.height + margin) : 0)) +
-                  (x2.used && x2.options.title ? (x2.titleSize.height + margin) : 0) + this.subtitleHeight + this.titleHeight + maxOutset;
-    }
-    if (y.options.margin === false) {
-      p.left  = 0;
-      p.right = 0;
-    } else {
-      p.left   += (options.grid.circular ? 0 : (y.used && y.options.showLabels ?  (y.maxLabel.width + margin) : 0)) +
-                  (y.used && y.options.title ? (y.titleSize.width + margin) : 0) + maxOutset;
-
-      p.right  += (options.grid.circular ? 0 : (y2.used && y2.options.showLabels ? (y2.maxLabel.width + margin) : 0)) +
-                  (y2.used && y2.options.title ? (y2.titleSize.width + margin) : 0) + maxOutset;
-    }
-
-    p.top = Math.floor(p.top); // In order the outline not to be blured
-
-    this.plotWidth  = this.canvasWidth - p.left - p.right;
-    this.plotHeight = this.canvasHeight - p.bottom - p.top;
-
-    // TODO post refactor, fix this
-    x.length = x2.length = this.plotWidth;
-    y.length = y2.length = this.plotHeight;
-    y.offset = y2.offset = this.plotHeight;
-    x.setScale();
-    x2.setScale();
-    y.setScale();
-    y2.setScale();
-  },
-  /**
-   * Draws grid, labels, series and outline.
-   */
-  draw: function(after) {
-
-    var
-      context = this.ctx,
-      i;
-
-    E.fire(this.el, 'flotr:beforedraw', [this.series, this]);
-
-    if (this.series.length) {
-
-      context.save();
-      context.translate(this.plotOffset.left, this.plotOffset.top);
-
-      for (i = 0; i < this.series.length; i++) {
-        if (!this.series[i].hide) this.drawSeries(this.series[i]);
-      }
-
-      context.restore();
-      this.clip();
-    }
-
-    E.fire(this.el, 'flotr:afterdraw', [this.series, this]);
-    if (after) after();
-  },
-  /**
-   * Actually draws the graph.
-   * @param {Object} series - series to draw
-   */
-  drawSeries: function(series){
-
-    function drawChart (series, typeKey) {
-      var options = this.getOptions(series, typeKey);
-      this[typeKey].draw(options);
-    }
-
-    var drawn = false;
-    series = series || this.series;
-
-    _.each(flotr.graphTypes, function (type, typeKey) {
-      if (series[typeKey] && series[typeKey].show && this[typeKey]) {
-        drawn = true;
-        drawChart.call(this, series, typeKey);
-      }
-    }, this);
-
-    if (!drawn) drawChart.call(this, series, this.options.defaultType);
-  },
-
-  getOptions : function (series, typeKey) {
-    var
-      type = series[typeKey],
-      graphType = this[typeKey],
-      options = {
-        context     : this.ctx,
-        width       : this.plotWidth,
-        height      : this.plotHeight,
-        fontSize    : this.options.fontSize,
-        fontColor   : this.options.fontColor,
-        textEnabled : this.textEnabled,
-        htmlText    : this.options.HtmlText,
-        text        : this._text, // TODO Is this necessary?
-        element     : this.el,
-        data        : series.data,
-        color       : series.color,
-        shadowSize  : series.shadowSize,
-        xScale      : _.bind(series.xaxis.d2p, series.xaxis),
-        yScale      : _.bind(series.yaxis.d2p, series.yaxis)
-      };
-
-    options = flotr.merge(type, options);
-
-    // Fill
-    options.fillStyle = this.processColor(
-      type.fillColor || series.color,
-      {opacity: type.fillOpacity}
-    );
-
-    return options;
-  },
-  /**
-   * Calculates the coordinates from a mouse event object.
-   * @param {Event} event - Mouse Event object.
-   * @return {Object} Object with coordinates of the mouse.
-   */
-  getEventPosition: function (e){
-
-    var
-      d = document,
-      b = d.body,
-      de = d.documentElement,
-      axes = this.axes,
-      plotOffset = this.plotOffset,
-      lastMousePos = this.lastMousePos,
-      pointer = E.eventPointer(e),
-      dx = pointer.x - lastMousePos.pageX,
-      dy = pointer.y - lastMousePos.pageY,
-      r, rx, ry;
-
-    if ('ontouchstart' in this.el) {
-      r = D.position(this.overlay);
-      rx = pointer.x - r.left - plotOffset.left;
-      ry = pointer.y - r.top - plotOffset.top;
-    } else {
-      r = this.overlay.getBoundingClientRect();
-      rx = e.clientX - r.left - plotOffset.left - b.scrollLeft - de.scrollLeft;
-      ry = e.clientY - r.top - plotOffset.top - b.scrollTop - de.scrollTop;
-    }
-
-    return {
-      x:  axes.x.p2d(rx),
-      x2: axes.x2.p2d(rx),
-      y:  axes.y.p2d(ry),
-      y2: axes.y2.p2d(ry),
-      relX: rx,
-      relY: ry,
-      dX: dx,
-      dY: dy,
-      absX: pointer.x,
-      absY: pointer.y,
-      pageX: pointer.x,
-      pageY: pointer.y
-    };
-  },
-  /**
-   * Observes the 'click' event and fires the 'flotr:click' event.
-   * @param {Event} event - 'click' Event object.
-   */
-  clickHandler: function(event){
-    if(this.ignoreClick){
-      this.ignoreClick = false;
-      return this.ignoreClick;
-    }
-    E.fire(this.el, 'flotr:click', [this.getEventPosition(event), this]);
-  },
-  /**
-   * Observes mouse movement over the graph area. Fires the 'flotr:mousemove' event.
-   * @param {Event} event - 'mousemove' Event object.
-   */
-  mouseMoveHandler: function(event){
-    if (this.mouseDownMoveHandler) return;
-    var pos = this.getEventPosition(event);
-    E.fire(this.el, 'flotr:mousemove', [event, pos, this]);
-    this.lastMousePos = pos;
-  },
-  /**
-   * Observes the 'mousedown' event.
-   * @param {Event} event - 'mousedown' Event object.
-   */
-  mouseDownHandler: function (event){
-
-    /*
-    // @TODO Context menu?
-    if(event.isRightClick()) {
-      event.stop();
-
-      var overlay = this.overlay;
-      overlay.hide();
-
-      function cancelContextMenu () {
-        overlay.show();
-        E.stopObserving(document, 'mousemove', cancelContextMenu);
-      }
-      E.observe(document, 'mousemove', cancelContextMenu);
-      return;
-    }
-    */
-
-    if (this.mouseUpHandler) return;
-    this.mouseUpHandler = _.bind(function (e) {
-      E.stopObserving(document, 'mouseup', this.mouseUpHandler);
-      E.stopObserving(document, 'mousemove', this.mouseDownMoveHandler);
-      this.mouseDownMoveHandler = null;
-      this.mouseUpHandler = null;
-      // @TODO why?
-      //e.stop();
-      E.fire(this.el, 'flotr:mouseup', [e, this]);
-    }, this);
-    this.mouseDownMoveHandler = _.bind(function (e) {
-        var pos = this.getEventPosition(e);
-        E.fire(this.el, 'flotr:mousemove', [event, pos, this]);
-        this.lastMousePos = pos;
-    }, this);
-    E.observe(document, 'mouseup', this.mouseUpHandler);
-    E.observe(document, 'mousemove', this.mouseDownMoveHandler);
-    E.fire(this.el, 'flotr:mousedown', [event, this]);
-    this.ignoreClick = false;
-  },
-  drawTooltip: function(content, x, y, options) {
-    var mt = this.getMouseTrack(),
-        style = 'opacity:0.7;background-color:#000;color:#fff;display:none;position:absolute;padding:2px 8px;-moz-border-radius:4px;border-radius:4px;white-space:nowrap;',
-        p = options.position,
-        m = options.margin,
-        plotOffset = this.plotOffset;
-
-    if(x !== null && y !== null){
-      if (!options.relative) { // absolute to the canvas
-             if(p.charAt(0) == 'n') style += 'top:' + (m + plotOffset.top) + 'px;bottom:auto;';
-        else if(p.charAt(0) == 's') style += 'bottom:' + (m + plotOffset.bottom) + 'px;top:auto;';
-             if(p.charAt(1) == 'e') style += 'right:' + (m + plotOffset.right) + 'px;left:auto;';
-        else if(p.charAt(1) == 'w') style += 'left:' + (m + plotOffset.left) + 'px;right:auto;';
-      }
-      else { // relative to the mouse
-             if(p.charAt(0) == 'n') style += 'bottom:' + (m - plotOffset.top - y + this.canvasHeight) + 'px;top:auto;';
-        else if(p.charAt(0) == 's') style += 'top:' + (m + plotOffset.top + y) + 'px;bottom:auto;';
-             if(p.charAt(1) == 'e') style += 'left:' + (m + plotOffset.left + x) + 'px;right:auto;';
-        else if(p.charAt(1) == 'w') style += 'right:' + (m - plotOffset.left - x + this.canvasWidth) + 'px;left:auto;';
-      }
-
-      mt.style.cssText = style;
-      D.empty(mt);
-      D.insert(mt, content);
-      D.show(mt);
-    }
-    else {
-      D.hide(mt);
-    }
-  },
-
-  clip: function (ctx) {
-
-    var
-      o   = this.plotOffset,
-      w   = this.canvasWidth,
-      h   = this.canvasHeight;
-
-    ctx = ctx || this.ctx;
-
-    if (flotr.isIE && flotr.isIE < 9) {
-      // Clipping for excanvas :-(
-      ctx.save();
-      ctx.fillStyle = this.processColor(this.options.ieBackgroundColor);
-      ctx.fillRect(0, 0, w, o.top);
-      ctx.fillRect(0, 0, o.left, h);
-      ctx.fillRect(0, h - o.bottom, w, o.bottom);
-      ctx.fillRect(w - o.right, 0, o.right,h);
-      ctx.restore();
-    } else {
-      ctx.clearRect(0, 0, w, o.top);
-      ctx.clearRect(0, 0, o.left, h);
-      ctx.clearRect(0, h - o.bottom, w, o.bottom);
-      ctx.clearRect(w - o.right, 0, o.right,h);
-    }
-  },
-
-  _initMembers: function() {
-    this._handles = [];
-    this.lastMousePos = {pageX: null, pageY: null };
-    this.plotOffset = {left: 0, right: 0, top: 0, bottom: 0};
-    this.ignoreClick = true;
-    this.prevHit = null;
-  },
-
-  _initGraphTypes: function() {
-    _.each(flotr.graphTypes, function(handler, graphType){
-      this[graphType] = flotr.clone(handler);
-    }, this);
-  },
-
-  _initEvents: function () {
-
-    var
-      el = this.el,
-      touchendHandler, movement, touchend;
-
-    if ('ontouchstart' in el) {
-
-      touchendHandler = _.bind(function (e) {
-        touchend = true;
-        E.stopObserving(document, 'touchend', touchendHandler);
-        E.fire(el, 'flotr:mouseup', [event, this]);
-        this.multitouches = null;
-
-        if (!movement) {
-          this.clickHandler(e);
-        }
-      }, this);
-
-      this.observe(this.overlay, 'touchstart', _.bind(function (e) {
-        movement = false;
-        touchend = false;
-        this.ignoreClick = false;
-
-        if (e.touches && e.touches.length > 1) {
-          this.multitouches = e.touches;
-        }
-
-        E.fire(el, 'flotr:mousedown', [event, this]);
-        this.observe(document, 'touchend', touchendHandler);
-      }, this));
-
-      this.observe(this.overlay, 'touchmove', _.bind(function (e) {
-
-        var pos = this.getEventPosition(e);
-
-        e.preventDefault();
-
-        movement = true;
-
-        if (this.multitouches || (e.touches && e.touches.length > 1)) {
-          this.multitouches = e.touches;
-        } else {
-          if (!touchend) {
-            E.fire(el, 'flotr:mousemove', [event, pos, this]);
-          }
-        }
-        this.lastMousePos = pos;
-      }, this));
-
-    } else {
-      this.
-        observe(this.overlay, 'mousedown', _.bind(this.mouseDownHandler, this)).
-        observe(el, 'mousemove', _.bind(this.mouseMoveHandler, this)).
-        observe(this.overlay, 'click', _.bind(this.clickHandler, this)).
-        observe(el, 'mouseout', function () {
-          E.fire(el, 'flotr:mouseout');
-        });
-    }
-  },
-
-  /**
-   * Initializes the canvas and it's overlay canvas element. When the browser is IE, this makes use
-   * of excanvas. The overlay canvas is inserted for displaying interactions. After the canvas elements
-   * are created, the elements are inserted into the container element.
-   */
-  _initCanvas: function(){
-    var el = this.el,
-      o = this.options,
-      children = el.children,
-      removedChildren = [],
-      child, i,
-      size, style;
-
-    // Empty the el
-    for (i = children.length; i--;) {
-      child = children[i];
-      if (!this.canvas && child.className === 'flotr-canvas') {
-        this.canvas = child;
-      } else if (!this.overlay && child.className === 'flotr-overlay') {
-        this.overlay = child;
-      } else {
-        removedChildren.push(child);
-      }
-    }
-    for (i = removedChildren.length; i--;) {
-      el.removeChild(removedChildren[i]);
-    }
-
-    D.setStyles(el, {position: 'relative'}); // For positioning labels and overlay.
-    size = {};
-    size.width = el.clientWidth;
-    size.height = el.clientHeight;
-
-    if(size.width <= 0 || size.height <= 0 || o.resolution <= 0){
-      throw 'Invalid dimensions for plot, width = ' + size.width + ', height = ' + size.height + ', resolution = ' + o.resolution;
-    }
-
-    // Main canvas for drawing graph types
-    this.canvas = getCanvas(this.canvas, 'canvas');
-    // Overlay canvas for interactive features
-    this.overlay = getCanvas(this.overlay, 'overlay');
-    this.ctx = getContext(this.canvas);
-    this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
-    this.octx = getContext(this.overlay);
-    this.octx.clearRect(0, 0, this.overlay.width, this.overlay.height);
-    this.canvasHeight = size.height;
-    this.canvasWidth = size.width;
-    this.textEnabled = !!this.ctx.drawText || !!this.ctx.fillText; // Enable text functions
-
-    function getCanvas(canvas, name){
-      if(!canvas){
-        canvas = D.create('canvas');
-        if (typeof FlashCanvas != "undefined" && typeof canvas.getContext === 'function') {
-          FlashCanvas.initElement(canvas);
-        }
-        canvas.className = 'flotr-'+name;
-        canvas.style.cssText = 'position:absolute;left:0px;top:0px;';
-        D.insert(el, canvas);
-      }
-      _.each(size, function(size, attribute){
-        D.show(canvas);
-        if (name == 'canvas' && canvas.getAttribute(attribute) === size) {
-          return;
-        }
-        canvas.setAttribute(attribute, size * o.resolution);
-        canvas.style[attribute] = size + 'px';
-      });
-      canvas.context_ = null; // Reset the ExCanvas context
-      return canvas;
-    }
-
-    function getContext(canvas){
-      if(window.G_vmlCanvasManager) window.G_vmlCanvasManager.initElement(canvas); // For ExCanvas
-      var context = canvas.getContext('2d');
-      if(!window.G_vmlCanvasManager) context.scale(o.resolution, o.resolution);
-      return context;
-    }
-  },
-
-  _initPlugins: function(){
-    // TODO Should be moved to flotr and mixed in.
-    _.each(flotr.plugins, function(plugin, name){
-      _.each(plugin.callbacks, function(fn, c){
-        this.observe(this.el, c, _.bind(fn, this));
-      }, this);
-      this[name] = flotr.clone(plugin);
-      _.each(this[name], function(fn, p){
-        if (_.isFunction(fn))
-          this[name][p] = _.bind(fn, this);
-      }, this);
-    }, this);
-  },
-
-  /**
-   * Sets options and initializes some variables and color specific values, used by the constructor.
-   * @param {Object} opts - options object
-   */
-  _initOptions: function(opts){
-    var options = flotr.clone(flotr.defaultOptions);
-    options.x2axis = _.extend(_.clone(options.xaxis), options.x2axis);
-    options.y2axis = _.extend(_.clone(options.yaxis), options.y2axis);
-    this.options = flotr.merge(opts || {}, options);
-
-    if (this.options.grid.minorVerticalLines === null &&
-      this.options.xaxis.scaling === 'logarithmic') {
-      this.options.grid.minorVerticalLines = true;
-    }
-    if (this.options.grid.minorHorizontalLines === null &&
-      this.options.yaxis.scaling === 'logarithmic') {
-      this.options.grid.minorHorizontalLines = true;
-    }
-
-    E.fire(this.el, 'flotr:afterinitoptions', [this]);
-
-    this.axes = flotr.Axis.getAxes(this.options);
-
-    // Initialize some variables used throughout this function.
-    var assignedColors = [],
-        colors = [],
-        ln = this.series.length,
-        neededColors = this.series.length,
-        oc = this.options.colors,
-        usedColors = [],
-        variation = 0,
-        c, i, j, s;
-
-    // Collect user-defined colors from series.
-    for(i = neededColors - 1; i > -1; --i){
-      c = this.series[i].color;
-      if(c){
-        --neededColors;
-        if(_.isNumber(c)) assignedColors.push(c);
-        else usedColors.push(flotr.Color.parse(c));
-      }
-    }
-
-    // Calculate the number of colors that need to be generated.
-    for(i = assignedColors.length - 1; i > -1; --i)
-      neededColors = Math.max(neededColors, assignedColors[i] + 1);
-
-    // Generate needed number of colors.
-    for(i = 0; colors.length < neededColors;){
-      c = (oc.length == i) ? new flotr.Color(100, 100, 100) : flotr.Color.parse(oc[i]);
-
-      // Make sure each serie gets a different color.
-      var sign = variation % 2 == 1 ? -1 : 1,
-          factor = 1 + sign * Math.ceil(variation / 2) * 0.2;
-      c.scale(factor, factor, factor);
-
-      /**
-       * @todo if we're getting too close to something else, we should probably skip this one
-       */
-      colors.push(c);
-
-      if(++i >= oc.length){
-        i = 0;
-        ++variation;
-      }
-    }
-
-    // Fill the options with the generated colors.
-    for(i = 0, j = 0; i < ln; ++i){
-      s = this.series[i];
-
-      // Assign the color.
-      if (!s.color){
-        s.color = colors[j++].toString();
-      }else if(_.isNumber(s.color)){
-        s.color = colors[s.color].toString();
-      }
-
-      // Every series needs an axis
-      if (!s.xaxis) s.xaxis = this.axes.x;
-           if (s.xaxis == 1) s.xaxis = this.axes.x;
-      else if (s.xaxis == 2) s.xaxis = this.axes.x2;
-
-      if (!s.yaxis) s.yaxis = this.axes.y;
-           if (s.yaxis == 1) s.yaxis = this.axes.y;
-      else if (s.yaxis == 2) s.yaxis = this.axes.y2;
-
-      // Apply missing options to the series.
-      for (var t in flotr.graphTypes){
-        s[t] = _.extend(_.clone(this.options[t]), s[t]);
-      }
-      s.mouse = _.extend(_.clone(this.options.mouse), s.mouse);
-
-      if (_.isUndefined(s.shadowSize)) s.shadowSize = this.options.shadowSize;
-    }
-  },
-
-  _setEl: function(el) {
-    if (!el) throw 'The target container doesn\'t exist';
-    else if (el.graph instanceof Graph) el.graph.destroy();
-    else if (!el.clientWidth) throw 'The target container must be visible';
-
-    el.graph = this;
-    this.el = el;
-  }
-};
-
-Flotr.Graph = Graph;
+    Graph.prototype = {
+
+        destroy: function () {
+            E.fire(this.el, 'flotr:destroy');
+            _.each(this._handles, function (handle) {
+                E.stopObserving.apply(this, handle);
+            });
+            this._handles = [];
+            this.el.graph = null;
+        },
+
+        observe: observe,
+
+        /**
+         * @deprecated
+         */
+        _observe: observe,
+
+        processColor: function (color, options) {
+            var o = { x1: 0, y1: 0, x2: this.plotWidth, y2: this.plotHeight, opacity: 1, ctx: this.ctx };
+            _.extend(o, options);
+            return flotr.Color.processColor(color, o);
+        },
+        /**
+         * Function determines the min and max values for the xaxis and yaxis.
+         *
+         * TODO logarithmic range validation (consideration of 0)
+         */
+        findDataRanges: function () {
+            var a = this.axes,
+                xaxis, yaxis, range;
+
+            _.each(this.series, function (series) {
+                range = series.getRange();
+                if (range) {
+                    xaxis = series.xaxis;
+                    yaxis = series.yaxis;
+                    xaxis.datamin = Math.min(range.xmin, xaxis.datamin);
+                    xaxis.datamax = Math.max(range.xmax, xaxis.datamax);
+                    yaxis.datamin = Math.min(range.ymin, yaxis.datamin);
+                    yaxis.datamax = Math.max(range.ymax, yaxis.datamax);
+                    xaxis.used = (xaxis.used || range.xused);
+                    yaxis.used = (yaxis.used || range.yused);
+                }
+            }, this);
+
+            // Check for empty data, no data case (none used)
+            if (!a.x.used && !a.x2.used) a.x.used = true;
+            if (!a.y.used && !a.y2.used) a.y.used = true;
+
+            _.each(a, function (axis) {
+                axis.calculateRange();
+            });
+
+            var
+                types = _.keys(flotr.graphTypes),
+                drawn = false;
+
+            _.each(this.series, function (series) {
+                if (series.hide) return;
+                _.each(types, function (type) {
+                    if (series[type] && series[type].show) {
+                        this.extendRange(type, series);
+                        drawn = true;
+                    }
+                }, this);
+                if (!drawn) {
+                    this.extendRange(this.options.defaultType, series);
+                }
+            }, this);
+        },
+
+        extendRange: function (type, series) {
+            if (this[type].extendRange) this[type].extendRange(series, series.data, series[type], this[type]);
+            if (this[type].extendYRange) this[type].extendYRange(series.yaxis, series.data, series[type], this[type]);
+            if (this[type].extendXRange) this[type].extendXRange(series.xaxis, series.data, series[type], this[type]);
+        },
+
+        /**
+         * Calculates axis label sizes.
+         */
+        calculateSpacing: function () {
+
+            var a = this.axes,
+                options = this.options,
+                series = this.series,
+                margin = options.grid.labelMargin,
+                T = this._text,
+                x = a.x,
+                x2 = a.x2,
+                y = a.y,
+                y2 = a.y2,
+                maxOutset = options.grid.outlineWidth,
+                i, j, l, dim;
+
+            // TODO post refactor, fix this
+            _.each(a, function (axis) {
+                axis.calculateTicks();
+                axis.calculateTextDimensions(T, options);
+            });
+
+            // Title height
+            dim = T.dimensions(
+                options.title,
+                {size: options.fontSize * 1.5},
+                'font-size:1em;font-weight:bold;',
+                'flotr-title'
+            );
+            this.titleHeight = dim.height;
+
+            // Subtitle height
+            dim = T.dimensions(
+                options.subtitle,
+                {size: options.fontSize},
+                'font-size:smaller;',
+                'flotr-subtitle'
+            );
+            this.subtitleHeight = dim.height;
+
+            for (j = 0; j < options.length; ++j) {
+                if (series[j].points.show) {
+                    maxOutset = Math.max(maxOutset, series[j].points.radius + series[j].points.lineWidth / 2);
+                }
+            }
+
+            var p = this.plotOffset;
+            if (x.options.margin === false) {
+                p.bottom = 0;
+                p.top = 0;
+            } else {
+                p.bottom += (options.grid.circular ? 0 : (x.used && x.options.showLabels ? (x.maxLabel.height + margin) : 0)) +
+                    (x.used && x.options.title ? (x.titleSize.height + margin) : 0) + maxOutset;
+
+                p.top += (options.grid.circular ? 0 : (x2.used && x2.options.showLabels ? (x2.maxLabel.height + margin) : 0)) +
+                    (x2.used && x2.options.title ? (x2.titleSize.height + margin) : 0) + this.subtitleHeight + this.titleHeight + maxOutset;
+            }
+            if (y.options.margin === false) {
+                p.left = 0;
+                p.right = 0;
+            } else {
+                p.left += (options.grid.circular ? 0 : (y.used && y.options.showLabels ? (y.maxLabel.width + margin) : 0)) +
+                    (y.used && y.options.title ? (y.titleSize.width + margin) : 0) + maxOutset;
+
+                p.right += (options.grid.circular ? 0 : (y2.used && y2.options.showLabels ? (y2.maxLabel.width + margin) : 0)) +
+                    (y2.used && y2.options.title ? (y2.titleSize.width + margin) : 0) + maxOutset;
+            }
+
+            p.top = Math.floor(p.top); // In order the outline not to be blured
+
+            this.plotWidth = this.canvasWidth - p.left - p.right;
+            this.plotHeight = this.canvasHeight - p.bottom - p.top;
+
+            // TODO post refactor, fix this
+            x.length = x2.length = this.plotWidth;
+            y.length = y2.length = this.plotHeight;
+            y.offset = y2.offset = this.plotHeight;
+            x.setScale();
+            x2.setScale();
+            y.setScale();
+            y2.setScale();
+        },
+        /**
+         * Draws grid, labels, series and outline.
+         */
+        draw: function (after) {
+
+            var
+                context = this.ctx,
+                i;
+
+            E.fire(this.el, 'flotr:beforedraw', [this.series, this]);
+
+            if (this.series.length) {
+
+                context.save();
+                context.translate(this.plotOffset.left, this.plotOffset.top);
+
+                for (i = 0; i < this.series.length; i++) {
+                    if (!this.series[i].hide) this.drawSeries(this.series[i]);
+                }
+
+                context.restore();
+                this.clip();
+            }
+
+            E.fire(this.el, 'flotr:afterdraw', [this.series, this]);
+            if (after) after();
+        },
+        /**
+         * Actually draws the graph.
+         * @param {Object} series - series to draw
+         */
+        drawSeries: function (series) {
+
+            function drawChart(series, typeKey) {
+                var options = this.getOptions(series, typeKey);
+                this[typeKey].draw(options);
+            }
+
+            var drawn = false;
+            series = series || this.series;
+
+            _.each(flotr.graphTypes, function (type, typeKey) {
+                if (series[typeKey] && series[typeKey].show && this[typeKey]) {
+                    drawn = true;
+                    drawChart.call(this, series, typeKey);
+                }
+            }, this);
+
+            if (!drawn) drawChart.call(this, series, this.options.defaultType);
+        },
+
+        getOptions: function (series, typeKey) {
+            var
+                type = series[typeKey],
+                graphType = this[typeKey],
+                options = {
+                    context: this.ctx,
+                    width: this.plotWidth,
+                    height: this.plotHeight,
+                    fontSize: this.options.fontSize,
+                    fontColor: this.options.fontColor,
+                    textEnabled: this.textEnabled,
+                    htmlText: this.options.HtmlText,
+                    text: this._text, // TODO Is this necessary?
+                    element: this.el,
+                    data: series.data,
+                    color: series.color,
+                    shadowSize: series.shadowSize,
+                    xScale: _.bind(series.xaxis.d2p, series.xaxis),
+                    yScale: _.bind(series.yaxis.d2p, series.yaxis)
+                };
+
+            options = flotr.merge(type, options);
+
+            // Fill
+            options.fillStyle = this.processColor(
+                type.fillColor || series.color,
+                {opacity: type.fillOpacity}
+            );
+
+            return options;
+        },
+        /**
+         * Calculates the coordinates from a mouse event object.
+         * @param {Event} event - Mouse Event object.
+         * @return {Object} Object with coordinates of the mouse.
+         */
+        getEventPosition: function (e) {
+
+            var
+                d = document,
+                b = d.body,
+                de = d.documentElement,
+                axes = this.axes,
+                plotOffset = this.plotOffset,
+                lastMousePos = this.lastMousePos,
+                pointer = E.eventPointer(e),
+                dx = pointer.x - lastMousePos.pageX,
+                dy = pointer.y - lastMousePos.pageY,
+                r, rx, ry;
+
+            if ('ontouchstart' in this.el) {
+                r = D.position(this.overlay);
+                rx = pointer.x - r.left - plotOffset.left;
+                ry = pointer.y - r.top - plotOffset.top;
+            } else {
+                r = this.overlay.getBoundingClientRect();
+                rx = e.clientX - r.left - plotOffset.left - b.scrollLeft - de.scrollLeft;
+                ry = e.clientY - r.top - plotOffset.top - b.scrollTop - de.scrollTop;
+            }
+
+            return {
+                x: axes.x.p2d(rx),
+                x2: axes.x2.p2d(rx),
+                y: axes.y.p2d(ry),
+                y2: axes.y2.p2d(ry),
+                relX: rx,
+                relY: ry,
+                dX: dx,
+                dY: dy,
+                absX: pointer.x,
+                absY: pointer.y,
+                pageX: pointer.x,
+                pageY: pointer.y
+            };
+        },
+        /**
+         * Observes the 'click' event and fires the 'flotr:click' event.
+         * @param {Event} event - 'click' Event object.
+         */
+        clickHandler: function (event) {
+            if (this.ignoreClick) {
+                this.ignoreClick = false;
+                return this.ignoreClick;
+            }
+            E.fire(this.el, 'flotr:click', [this.getEventPosition(event), this]);
+        },
+        /**
+         * Observes mouse movement over the graph area. Fires the 'flotr:mousemove' event.
+         * @param {Event} event - 'mousemove' Event object.
+         */
+        mouseMoveHandler: function (event) {
+            if (this.mouseDownMoveHandler) return;
+            var pos = this.getEventPosition(event);
+            E.fire(this.el, 'flotr:mousemove', [event, pos, this]);
+            this.lastMousePos = pos;
+        },
+        /**
+         * Observes the 'mousedown' event.
+         * @param {Event} event - 'mousedown' Event object.
+         */
+        mouseDownHandler: function (event) {
+
+            /*
+             // @TODO Context menu?
+             if(event.isRightClick()) {
+             event.stop();
+
+             var overlay = this.overlay;
+             overlay.hide();
+
+             function cancelContextMenu () {
+             overlay.show();
+             E.stopObserving(document, 'mousemove', cancelContextMenu);
+             }
+             E.observe(document, 'mousemove', cancelContextMenu);
+             return;
+             }
+             */
+
+            if (this.mouseUpHandler) return;
+            this.mouseUpHandler = _.bind(function (e) {
+                E.stopObserving(document, 'mouseup', this.mouseUpHandler);
+                E.stopObserving(document, 'mousemove', this.mouseDownMoveHandler);
+                this.mouseDownMoveHandler = null;
+                this.mouseUpHandler = null;
+                // @TODO why?
+                //e.stop();
+                E.fire(this.el, 'flotr:mouseup', [e, this]);
+            }, this);
+            this.mouseDownMoveHandler = _.bind(function (e) {
+                var pos = this.getEventPosition(e);
+                E.fire(this.el, 'flotr:mousemove', [event, pos, this]);
+                this.lastMousePos = pos;
+            }, this);
+            E.observe(document, 'mouseup', this.mouseUpHandler);
+            E.observe(document, 'mousemove', this.mouseDownMoveHandler);
+            E.fire(this.el, 'flotr:mousedown', [event, this]);
+            this.ignoreClick = false;
+        },
+        drawTooltip: function (content, x, y, options) {
+            var mt = this.getMouseTrack(),
+                style = 'opacity:0.7;background-color:#000;color:#fff;display:none;position:absolute;padding:2px 8px;-moz-border-radius:4px;border-radius:4px;white-space:nowrap;',
+                p = options.position,
+                m = options.margin,
+                plotOffset = this.plotOffset;
+
+            if (x !== null && y !== null) {
+                if (!options.relative) { // absolute to the canvas
+                    if (p.charAt(0) == 'n') style += 'top:' + (m + plotOffset.top) + 'px;bottom:auto;';
+                    else if (p.charAt(0) == 's') style += 'bottom:' + (m + plotOffset.bottom) + 'px;top:auto;';
+                    if (p.charAt(1) == 'e') style += 'right:' + (m + plotOffset.right) + 'px;left:auto;';
+                    else if (p.charAt(1) == 'w') style += 'left:' + (m + plotOffset.left) + 'px;right:auto;';
+                }
+                else { // relative to the mouse
+                    if (p.charAt(0) == 'n') style += 'bottom:' + (m - plotOffset.top - y + this.canvasHeight) + 'px;top:auto;';
+                    else if (p.charAt(0) == 's') style += 'top:' + (m + plotOffset.top + y) + 'px;bottom:auto;';
+                    if (p.charAt(1) == 'e') style += 'left:' + (m + plotOffset.left + x) + 'px;right:auto;';
+                    else if (p.charAt(1) == 'w') style += 'right:' + (m - plotOffset.left - x + this.canvasWidth) + 'px;left:auto;';
+                }
+
+                mt.style.cssText = style;
+                D.empty(mt);
+                D.insert(mt, content);
+                D.show(mt);
+            }
+            else {
+                D.hide(mt);
+            }
+        },
+
+        clip: function (ctx) {
+
+            var
+                o = this.plotOffset,
+                w = this.canvasWidth,
+                h = this.canvasHeight;
+
+            ctx = ctx || this.ctx;
+
+            if (flotr.isIE && flotr.isIE < 9) {
+                // Clipping for excanvas :-(
+                ctx.save();
+                ctx.fillStyle = this.processColor(this.options.ieBackgroundColor);
+                ctx.fillRect(0, 0, w, o.top);
+                ctx.fillRect(0, 0, o.left, h);
+                ctx.fillRect(0, h - o.bottom, w, o.bottom);
+                ctx.fillRect(w - o.right, 0, o.right, h);
+                ctx.restore();
+            } else {
+                ctx.clearRect(0, 0, w, o.top);
+                ctx.clearRect(0, 0, o.left, h);
+                ctx.clearRect(0, h - o.bottom, w, o.bottom);
+                ctx.clearRect(w - o.right, 0, o.right, h);
+            }
+        },
+
+        _initMembers: function () {
+            this._handles = [];
+            this.lastMousePos = {pageX: null, pageY: null };
+            this.plotOffset = {left: 0, right: 0, top: 0, bottom: 0};
+            this.ignoreClick = true;
+            this.prevHit = null;
+        },
+
+        _initGraphTypes: function () {
+            _.each(flotr.graphTypes, function (handler, graphType) {
+                this[graphType] = flotr.clone(handler);
+            }, this);
+        },
+
+        _initEvents: function () {
+
+            var
+                el = this.el,
+                touchendHandler, movement, touchend;
+
+            if ('ontouchstart' in el) {
+
+                touchendHandler = _.bind(function (e) {
+                    touchend = true;
+                    E.stopObserving(document, 'touchend', touchendHandler);
+                    E.fire(el, 'flotr:mouseup', [event, this]);
+                    this.multitouches = null;
+
+                    if (!movement) {
+                        this.clickHandler(e);
+                    }
+                }, this);
+
+                this.observe(this.overlay, 'touchstart', _.bind(function (e) {
+                    movement = false;
+                    touchend = false;
+                    this.ignoreClick = false;
+
+                    if (e.touches && e.touches.length > 1) {
+                        this.multitouches = e.touches;
+                    }
+
+                    E.fire(el, 'flotr:mousedown', [event, this]);
+                    this.observe(document, 'touchend', touchendHandler);
+                }, this));
+
+                this.observe(this.overlay, 'touchmove', _.bind(function (e) {
+
+                    var pos = this.getEventPosition(e);
+
+                    e.preventDefault();
+
+                    movement = true;
+
+                    if (this.multitouches || (e.touches && e.touches.length > 1)) {
+                        this.multitouches = e.touches;
+                    } else {
+                        if (!touchend) {
+                            E.fire(el, 'flotr:mousemove', [event, pos, this]);
+                        }
+                    }
+                    this.lastMousePos = pos;
+                }, this));
+
+            } else {
+                this.
+                    observe(this.overlay, 'mousedown', _.bind(this.mouseDownHandler, this)).
+                    observe(el, 'mousemove', _.bind(this.mouseMoveHandler, this)).
+                    observe(this.overlay, 'click', _.bind(this.clickHandler, this)).
+                    observe(el, 'mouseout', function () {
+                        E.fire(el, 'flotr:mouseout');
+                    });
+            }
+        },
+
+        /**
+         * Initializes the canvas and it's overlay canvas element. When the browser is IE, this makes use
+         * of excanvas. The overlay canvas is inserted for displaying interactions. After the canvas elements
+         * are created, the elements are inserted into the container element.
+         */
+        _initCanvas: function () {
+            var el = this.el,
+                o = this.options,
+                children = el.children,
+                removedChildren = [],
+                child, i,
+                size, style;
+
+            // Empty the el
+            for (i = children.length; i--;) {
+                child = children[i];
+                if (!this.canvas && child.className === 'flotr-canvas') {
+                    this.canvas = child;
+                } else if (!this.overlay && child.className === 'flotr-overlay') {
+                    this.overlay = child;
+                } else {
+                    removedChildren.push(child);
+                }
+            }
+            for (i = removedChildren.length; i--;) {
+                el.removeChild(removedChildren[i]);
+            }
+
+            D.setStyles(el, {position: 'relative'}); // For positioning labels and overlay.
+            size = {};
+            size.width = el.clientWidth;
+            size.height = el.clientHeight;
+
+            if (size.width <= 0 || size.height <= 0 || o.resolution <= 0) {
+                throw 'Invalid dimensions for plot, width = ' + size.width + ', height = ' + size.height + ', resolution = ' + o.resolution;
+            }
+
+            // Main canvas for drawing graph types
+            this.canvas = getCanvas(this.canvas, 'canvas');
+            // Overlay canvas for interactive features
+            this.overlay = getCanvas(this.overlay, 'overlay');
+            this.ctx = getContext(this.canvas);
+            this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
+            this.octx = getContext(this.overlay);
+            this.octx.clearRect(0, 0, this.overlay.width, this.overlay.height);
+            this.canvasHeight = size.height;
+            this.canvasWidth = size.width;
+            this.textEnabled = !!this.ctx.drawText || !!this.ctx.fillText; // Enable text functions
+
+            function getCanvas(canvas, name) {
+                if (!canvas) {
+                    canvas = D.create('canvas');
+                    if (typeof FlashCanvas != "undefined" && typeof canvas.getContext === 'function') {
+                        FlashCanvas.initElement(canvas);
+                    }
+                    canvas.className = 'flotr-' + name;
+                    canvas.style.cssText = 'position:absolute;left:0px;top:0px;';
+                    D.insert(el, canvas);
+                }
+                _.each(size, function (size, attribute) {
+                    D.show(canvas);
+                    if (name == 'canvas' && canvas.getAttribute(attribute) === size) {
+                        return;
+                    }
+                    canvas.setAttribute(attribute, size * o.resolution);
+                    canvas.style[attribute] = size + 'px';
+                });
+                canvas.context_ = null; // Reset the ExCanvas context
+                return canvas;
+            }
+
+            function getContext(canvas) {
+                if (window.G_vmlCanvasManager) window.G_vmlCanvasManager.initElement(canvas); // For ExCanvas
+                var context = canvas.getContext('2d');
+                if (!window.G_vmlCanvasManager) context.scale(o.resolution, o.resolution);
+                return context;
+            }
+        },
+
+        _initPlugins: function () {
+            // TODO Should be moved to flotr and mixed in.
+            _.each(flotr.plugins, function (plugin, name) {
+                _.each(plugin.callbacks, function (fn, c) {
+                    this.observe(this.el, c, _.bind(fn, this));
+                }, this);
+                this[name] = flotr.clone(plugin);
+                _.each(this[name], function (fn, p) {
+                    if (_.isFunction(fn))
+                        this[name][p] = _.bind(fn, this);
+                }, this);
+            }, this);
+        },
+
+        /**
+         * Sets options and initializes some variables and color specific values, used by the constructor.
+         * @param {Object} opts - options object
+         */
+        _initOptions: function (opts) {
+            var options = flotr.clone(flotr.defaultOptions);
+            options.x2axis = _.extend(_.clone(options.xaxis), options.x2axis);
+            options.y2axis = _.extend(_.clone(options.yaxis), options.y2axis);
+            this.options = flotr.merge(opts || {}, options);
+
+            if (this.options.grid.minorVerticalLines === null &&
+                this.options.xaxis.scaling === 'logarithmic') {
+                this.options.grid.minorVerticalLines = true;
+            }
+            if (this.options.grid.minorHorizontalLines === null &&
+                this.options.yaxis.scaling === 'logarithmic') {
+                this.options.grid.minorHorizontalLines = true;
+            }
+
+            E.fire(this.el, 'flotr:afterinitoptions', [this]);
+
+            this.axes = flotr.Axis.getAxes(this.options);
+
+            // Initialize some variables used throughout this function.
+            var assignedColors = [],
+                colors = [],
+                ln = this.series.length,
+                neededColors = this.series.length,
+                oc = this.options.colors,
+                usedColors = [],
+                variation = 0,
+                c, i, j, s;
+
+            // Collect user-defined colors from series.
+            for (i = neededColors - 1; i > -1; --i) {
+                c = this.series[i].color;
+                if (c) {
+                    --neededColors;
+                    if (_.isNumber(c)) assignedColors.push(c);
+                    else usedColors.push(flotr.Color.parse(c));
+                }
+            }
+
+            // Calculate the number of colors that need to be generated.
+            for (i = assignedColors.length - 1; i > -1; --i)
+                neededColors = Math.max(neededColors, assignedColors[i] + 1);
+
+            // Generate needed number of colors.
+            for (i = 0; colors.length < neededColors;) {
+                c = (oc.length == i) ? new flotr.Color(100, 100, 100) : flotr.Color.parse(oc[i]);
+
+                // Make sure each serie gets a different color.
+                var sign = variation % 2 == 1 ? -1 : 1,
+                    factor = 1 + sign * Math.ceil(variation / 2) * 0.2;
+                c.scale(factor, factor, factor);
+
+                /**
+                 * @todo if we're getting too close to something else, we should probably skip this one
+                 */
+                colors.push(c);
+
+                if (++i >= oc.length) {
+                    i = 0;
+                    ++variation;
+                }
+            }
+
+            // Fill the options with the generated colors.
+            for (i = 0, j = 0; i < ln; ++i) {
+                s = this.series[i];
+
+                // Assign the color.
+                if (!s.color) {
+                    s.color = colors[j++].toString();
+                } else if (_.isNumber(s.color)) {
+                    s.color = colors[s.color].toString();
+                }
+
+                // Every series needs an axis
+                if (!s.xaxis) s.xaxis = this.axes.x;
+                if (s.xaxis == 1) s.xaxis = this.axes.x;
+                else if (s.xaxis == 2) s.xaxis = this.axes.x2;
+
+                if (!s.yaxis) s.yaxis = this.axes.y;
+                if (s.yaxis == 1) s.yaxis = this.axes.y;
+                else if (s.yaxis == 2) s.yaxis = this.axes.y2;
+
+                // Apply missing options to the series.
+                for (var t in flotr.graphTypes) {
+                    s[t] = _.extend(_.clone(this.options[t]), s[t]);
+                }
+                s.mouse = _.extend(_.clone(this.options.mouse), s.mouse);
+
+                if (_.isUndefined(s.shadowSize)) s.shadowSize = this.options.shadowSize;
+            }
+        },
+
+        _setEl: function (el) {
+            if (!el) throw 'The target container doesn\'t exist';
+            else if (el.graph instanceof Graph) el.graph.destroy();
+            else if (!el.clientWidth) throw 'The target container must be visible';
+
+            el.graph = this;
+            this.el = el;
+        }
+    };
+
+    Flotr.Graph = Graph;
 
 })();
 
@@ -3046,305 +3094,309 @@
 
 (function () {
 
-var
-  _ = Flotr._,
-  LOGARITHMIC = 'logarithmic';
-
-function Axis (o) {
-
-  this.orientation = 1;
-  this.offset = 0;
-  this.datamin = Number.MAX_VALUE;
-  this.datamax = -Number.MAX_VALUE;
-
-  _.extend(this, o);
-
-  this._setTranslations();
-}
+    var
+        _ = Flotr._,
+        LOGARITHMIC = 'logarithmic';
+
+    function Axis(o) {
+
+        this.orientation = 1;
+        this.offset = 0;
+        this.datamin = Number.MAX_VALUE;
+        this.datamax = -Number.MAX_VALUE;
+
+        _.extend(this, o);
+
+        this._setTranslations();
+    }
 
 
 // Prototype
-Axis.prototype = {
-
-  setScale : function () {
-    var length = this.length;
-    if (this.options.scaling == LOGARITHMIC) {
-      this.scale = length / (log(this.max, this.options.base) - log(this.min, this.options.base));
-    } else {
-      this.scale = length / (this.max - this.min);
+    Axis.prototype = {
+
+        setScale: function () {
+            var length = this.length;
+            if (this.options.scaling == LOGARITHMIC) {
+                this.scale = length / (log(this.max, this.options.base) - log(this.min, this.options.base));
+            } else {
+                this.scale = length / (this.max - this.min);
+            }
+        },
+
+        calculateTicks: function () {
+            var options = this.options;
+
+            this.ticks = [];
+            this.minorTicks = [];
+
+            // User Ticks
+            if (options.ticks) {
+                this._cleanUserTicks(options.ticks, this.ticks);
+                this._cleanUserTicks(options.minorTicks || [], this.minorTicks);
+            }
+            else {
+                if (options.mode == 'time') {
+                    this._calculateTimeTicks();
+                } else if (options.scaling === 'logarithmic') {
+                    this._calculateLogTicks();
+                } else {
+                    this._calculateTicks();
+                }
+            }
+
+            // Ticks to strings
+            _.each(this.ticks, function (tick) {
+                tick.label += '';
+            });
+            _.each(this.minorTicks, function (tick) {
+                tick.label += '';
+            });
+        },
+
+        /**
+         * Calculates the range of an axis to apply autoscaling.
+         */
+        calculateRange: function () {
+
+            if (!this.used) return;
+
+            var axis = this,
+                o = axis.options,
+                min = o.min !== null ? o.min : axis.datamin,
+                max = o.max !== null ? o.max : axis.datamax,
+                margin = o.autoscaleMargin;
+
+            if (o.scaling == 'logarithmic') {
+                if (min <= 0) min = axis.datamin;
+
+                // Let it widen later on
+                if (max <= 0) max = min;
+            }
+
+            if (max == min) {
+                var widen = max ? 0.01 : 1.00;
+                if (o.min === null) min -= widen;
+                if (o.max === null) max += widen;
+            }
+
+            if (o.scaling === 'logarithmic') {
+                if (min < 0) min = max / o.base;  // Could be the result of widening
+
+                var maxexp = Math.log(max);
+                if (o.base != Math.E) maxexp /= Math.log(o.base);
+                maxexp = Math.ceil(maxexp);
+
+                var minexp = Math.log(min);
+                if (o.base != Math.E) minexp /= Math.log(o.base);
+                minexp = Math.ceil(minexp);
+
+                axis.tickSize = Flotr.getTickSize(o.noTicks, minexp, maxexp, o.tickDecimals === null ? 0 : o.tickDecimals);
+
+                // Try to determine a suitable amount of miniticks based on the length of a decade
+                if (o.minorTickFreq === null) {
+                    if (maxexp - minexp > 10)
+                        o.minorTickFreq = 0;
+                    else if (maxexp - minexp > 5)
+                        o.minorTickFreq = 2;
+                    else
+                        o.minorTickFreq = 5;
+                }
+            } else {
+                axis.tickSize = Flotr.getTickSize(o.noTicks, min, max, o.tickDecimals);
+            }
+
+            axis.min = min;
+            axis.max = max; //extendRange may use axis.min or axis.max, so it should be set before it is caled
+
+            // Autoscaling. @todo This probably fails with log scale. Find a testcase and fix it
+            if (o.min === null && o.autoscale) {
+                axis.min -= axis.tickSize * margin;
+                // Make sure we don't go below zero if all values are positive.
+                if (axis.min < 0 && axis.datamin >= 0) axis.min = 0;
+                axis.min = axis.tickSize * Math.floor(axis.min / axis.tickSize);
+            }
+
+            if (o.max === null && o.autoscale) {
+                axis.max += axis.tickSize * margin;
+                if (axis.max > 0 && axis.datamax <= 0 && axis.datamax != axis.datamin) axis.max = 0;
+                axis.max = axis.tickSize * Math.ceil(axis.max / axis.tickSize);
+            }
+
+            if (axis.min == axis.max) axis.max = axis.min + 1;
+        },
+
+        calculateTextDimensions: function (T, options) {
+
+            var maxLabel = '',
+                length,
+                i;
+
+            if (this.options.showLabels) {
+                for (i = 0; i < this.ticks.length; ++i) {
+                    length = this.ticks[i].label.length;
+                    if (length > maxLabel.length) {
+                        maxLabel = this.ticks[i].label;
+                    }
+                }
+            }
+
+            this.maxLabel = T.dimensions(
+                maxLabel,
+                {size: options.fontSize, angle: Flotr.toRad(this.options.labelsAngle)},
+                'font-size:smaller;',
+                'flotr-grid-label'
+            );
+
+            this.titleSize = T.dimensions(
+                this.options.title,
+                {size: options.fontSize * 1.2, angle: Flotr.toRad(this.options.titleAngle)},
+                'font-weight:bold;',
+                'flotr-axis-title'
+            );
+        },
+
+        _cleanUserTicks: function (ticks, axisTicks) {
+
+            var axis = this, options = this.options,
+                v, i, label, tick;
+
+            if (_.isFunction(ticks)) ticks = ticks({min: axis.min, max: axis.max});
+
+            for (i = 0; i < ticks.length; ++i) {
+                tick = ticks[i];
+                if (typeof(tick) === 'object') {
+                    v = tick[0];
+                    label = (tick.length > 1) ? tick[1] : options.tickFormatter(v, {min: axis.min, max: axis.max});
+                } else {
+                    v = tick;
+                    label = options.tickFormatter(v, {min: this.min, max: this.max});
+                }
+                axisTicks[i] = { v: v, label: label };
+            }
+        },
+
+        _calculateTimeTicks: function () {
+            this.ticks = Flotr.Date.generator(this);
+        },
+
+        _calculateLogTicks: function () {
+
+            var axis = this,
+                o = axis.options,
+                v,
+                decadeStart;
+
+            var max = Math.log(axis.max);
+            if (o.base != Math.E) max /= Math.log(o.base);
+            max = Math.ceil(max);
+
+            var min = Math.log(axis.min);
+            if (o.base != Math.E) min /= Math.log(o.base);
+            min = Math.ceil(min);
+
+            for (i = min; i < max; i += axis.tickSize) {
+                decadeStart = (o.base == Math.E) ? Math.exp(i) : Math.pow(o.base, i);
+                // Next decade begins here:
+                var decadeEnd = decadeStart * ((o.base == Math.E) ? Math.exp(axis.tickSize) : Math.pow(o.base, axis.tickSize));
+                var stepSize = (decadeEnd - decadeStart) / o.minorTickFreq;
+
+                axis.ticks.push({v: decadeStart, label: o.tickFormatter(decadeStart, {min: axis.min, max: axis.max})});
+                for (v = decadeStart + stepSize; v < decadeEnd; v += stepSize)
+                    axis.minorTicks.push({v: v, label: o.tickFormatter(v, {min: axis.min, max: axis.max})});
+            }
+
+            // Always show the value at the would-be start of next decade (end of this decade)
+            decadeStart = (o.base == Math.E) ? Math.exp(i) : Math.pow(o.base, i);
+            axis.ticks.push({v: decadeStart, label: o.tickFormatter(decadeStart, {min: axis.min, max: axis.max})});
+        },
+
+        _calculateTicks: function () {
+
+            var axis = this,
+                o = axis.options,
+                tickSize = axis.tickSize,
+                min = axis.min,
+                max = axis.max,
+                start = tickSize * Math.ceil(min / tickSize), // Round to nearest multiple of tick size.
+                decimals,
+                minorTickSize,
+                v, v2,
+                i, j;
+
+            if (o.minorTickFreq)
+                minorTickSize = tickSize / o.minorTickFreq;
+
+            // Then store all possible ticks.
+            for (i = 0; (v = v2 = start + i * tickSize) <= max; ++i) {
+
+                // Round (this is always needed to fix numerical instability).
+                decimals = o.tickDecimals;
+                if (decimals === null) decimals = 1 - Math.floor(Math.log(tickSize) / Math.LN10);
+                if (decimals < 0) decimals = 0;
+
+                v = v.toFixed(decimals);
+                axis.ticks.push({ v: v, label: o.tickFormatter(v, {min: axis.min, max: axis.max}) });
+
+                if (o.minorTickFreq) {
+                    for (j = 0; j < o.minorTickFreq && (i * tickSize + j * minorTickSize) < max; ++j) {
+                        v = v2 + j * minorTickSize;
+                        axis.minorTicks.push({ v: v, label: o.tickFormatter(v, {min: axis.min, max: axis.max}) });
+                    }
+                }
+            }
+
+        },
+
+        _setTranslations: function (logarithmic) {
+            this.d2p = (logarithmic ? d2pLog : d2p);
+            this.p2d = (logarithmic ? p2dLog : p2d);
+        }
+    };
+
+
+// Static Methods
+    _.extend(Axis, {
+        getAxes: function (options) {
+            return {
+                x: new Axis({options: options.xaxis, n: 1, length: this.plotWidth}),
+                x2: new Axis({options: options.x2axis, n: 2, length: this.plotWidth}),
+                y: new Axis({options: options.yaxis, n: 1, length: this.plotHeight, offset: this.plotHeight, orientation: -1}),
+                y2: new Axis({options: options.y2axis, n: 2, length: this.plotHeight, offset: this.plotHeight, orientation: -1})
+            };
+        }
+    });
+
+
+// Helper Methods
+
+    function d2p(dataValue) {
+        return this.offset + this.orientation * (dataValue - this.min) * this.scale;
     }
-  },
-
-  calculateTicks : function () {
-    var options = this.options;
-
-    this.ticks = [];
-    this.minorTicks = [];
-    
-    // User Ticks
-    if(options.ticks){
-      this._cleanUserTicks(options.ticks, this.ticks);
-      this._cleanUserTicks(options.minorTicks || [], this.minorTicks);
+
+    function p2d(pointValue) {
+        return (this.offset + this.orientation * pointValue) / this.scale + this.min;
     }
-    else {
-      if (options.mode == 'time') {
-        this._calculateTimeTicks();
-      } else if (options.scaling === 'logarithmic') {
-        this._calculateLogTicks();
-      } else {
-        this._calculateTicks();
-      }
+
+    function d2pLog(dataValue) {
+        return this.offset + this.orientation * (log(dataValue, this.options.base) - log(this.min, this.options.base)) * this.scale;
     }
 
-    // Ticks to strings
-    _.each(this.ticks, function (tick) { tick.label += ''; });
-    _.each(this.minorTicks, function (tick) { tick.label += ''; });
-  },
-
-  /**
-   * Calculates the range of an axis to apply autoscaling.
-   */
-  calculateRange: function () {
-
-    if (!this.used) return;
-
-    var axis  = this,
-      o       = axis.options,
-      min     = o.min !== null ? o.min : axis.datamin,
-      max     = o.max !== null ? o.max : axis.datamax,
-      margin  = o.autoscaleMargin;
-        
-    if (o.scaling == 'logarithmic') {
-      if (min <= 0) min = axis.datamin;
-
-      // Let it widen later on
-      if (max <= 0) max = min;
+    function p2dLog(pointValue) {
+        return exp((this.offset + this.orientation * pointValue) / this.scale + log(this.min, this.options.base), this.options.base);
     }
 
-    if (max == min) {
-      var widen = max ? 0.01 : 1.00;
-      if (o.min === null) min -= widen;
-      if (o.max === null) max += widen;
+    function log(value, base) {
+        value = Math.log(Math.max(value, Number.MIN_VALUE));
+        if (base !== Math.E)
+            value /= Math.log(base);
+        return value;
     }
 
-    if (o.scaling === 'logarithmic') {
-      if (min < 0) min = max / o.base;  // Could be the result of widening
-
-      var maxexp = Math.log(max);
-      if (o.base != Math.E) maxexp /= Math.log(o.base);
-      maxexp = Math.ceil(maxexp);
-
-      var minexp = Math.log(min);
-      if (o.base != Math.E) minexp /= Math.log(o.base);
-      minexp = Math.ceil(minexp);
-      
-      axis.tickSize = Flotr.getTickSize(o.noTicks, minexp, maxexp, o.tickDecimals === null ? 0 : o.tickDecimals);
-                        
-      // Try to determine a suitable amount of miniticks based on the length of a decade
-      if (o.minorTickFreq === null) {
-        if (maxexp - minexp > 10)
-          o.minorTickFreq = 0;
-        else if (maxexp - minexp > 5)
-          o.minorTickFreq = 2;
-        else
-          o.minorTickFreq = 5;
-      }
-    } else {
-      axis.tickSize = Flotr.getTickSize(o.noTicks, min, max, o.tickDecimals);
+    function exp(value, base) {
+        return (base === Math.E) ? Math.exp(value) : Math.pow(base, value);
     }
 
-    axis.min = min;
-    axis.max = max; //extendRange may use axis.min or axis.max, so it should be set before it is caled
-
-    // Autoscaling. @todo This probably fails with log scale. Find a testcase and fix it
-    if(o.min === null && o.autoscale){
-      axis.min -= axis.tickSize * margin;
-      // Make sure we don't go below zero if all values are positive.
-      if(axis.min < 0 && axis.datamin >= 0) axis.min = 0;
-      axis.min = axis.tickSize * Math.floor(axis.min / axis.tickSize);
-    }
-    
-    if(o.max === null && o.autoscale){
-      axis.max += axis.tickSize * margin;
-      if(axis.max > 0 && axis.datamax <= 0 && axis.datamax != axis.datamin) axis.max = 0;        
-      axis.max = axis.tickSize * Math.ceil(axis.max / axis.tickSize);
-    }
-
-    if (axis.min == axis.max) axis.max = axis.min + 1;
-  },
-
-  calculateTextDimensions : function (T, options) {
-
-    var maxLabel = '',
-      length,
-      i;
-
-    if (this.options.showLabels) {
-      for (i = 0; i < this.ticks.length; ++i) {
-        length = this.ticks[i].label.length;
-        if (length > maxLabel.length){
-          maxLabel = this.ticks[i].label;
-        }
-      }
-    }
-
-    this.maxLabel = T.dimensions(
-      maxLabel,
-      {size:options.fontSize, angle: Flotr.toRad(this.options.labelsAngle)},
-      'font-size:smaller;',
-      'flotr-grid-label'
-    );
-
-    this.titleSize = T.dimensions(
-      this.options.title, 
-      {size:options.fontSize*1.2, angle: Flotr.toRad(this.options.titleAngle)},
-      'font-weight:bold;',
-      'flotr-axis-title'
-    );
-  },
-
-  _cleanUserTicks : function (ticks, axisTicks) {
-
-    var axis = this, options = this.options,
-      v, i, label, tick;
-
-    if(_.isFunction(ticks)) ticks = ticks({min : axis.min, max : axis.max});
-
-    for(i = 0; i < ticks.length; ++i){
-      tick = ticks[i];
-      if(typeof(tick) === 'object'){
-        v = tick[0];
-        label = (tick.length > 1) ? tick[1] : options.tickFormatter(v, {min : axis.min, max : axis.max});
-      } else {
-        v = tick;
-        label = options.tickFormatter(v, {min : this.min, max : this.max});
-      }
-      axisTicks[i] = { v: v, label: label };
-    }
-  },
-
-  _calculateTimeTicks : function () {
-    this.ticks = Flotr.Date.generator(this);
-  },
-
-  _calculateLogTicks : function () {
-
-    var axis = this,
-      o = axis.options,
-      v,
-      decadeStart;
-
-    var max = Math.log(axis.max);
-    if (o.base != Math.E) max /= Math.log(o.base);
-    max = Math.ceil(max);
-
-    var min = Math.log(axis.min);
-    if (o.base != Math.E) min /= Math.log(o.base);
-    min = Math.ceil(min);
-    
-    for (i = min; i < max; i += axis.tickSize) {
-      decadeStart = (o.base == Math.E) ? Math.exp(i) : Math.pow(o.base, i);
-      // Next decade begins here:
-      var decadeEnd = decadeStart * ((o.base == Math.E) ? Math.exp(axis.tickSize) : Math.pow(o.base, axis.tickSize));
-      var stepSize = (decadeEnd - decadeStart) / o.minorTickFreq;
-      
-      axis.ticks.push({v: decadeStart, label: o.tickFormatter(decadeStart, {min : axis.min, max : axis.max})});
-      for (v = decadeStart + stepSize; v < decadeEnd; v += stepSize)
-        axis.minorTicks.push({v: v, label: o.tickFormatter(v, {min : axis.min, max : axis.max})});
-    }
-    
-    // Always show the value at the would-be start of next decade (end of this decade)
-    decadeStart = (o.base == Math.E) ? Math.exp(i) : Math.pow(o.base, i);
-    axis.ticks.push({v: decadeStart, label: o.tickFormatter(decadeStart, {min : axis.min, max : axis.max})});
-  },
-
-  _calculateTicks : function () {
-
-    var axis      = this,
-        o         = axis.options,
-        tickSize  = axis.tickSize,
-        min       = axis.min,
-        max       = axis.max,
-        start     = tickSize * Math.ceil(min / tickSize), // Round to nearest multiple of tick size.
-        decimals,
-        minorTickSize,
-        v, v2,
-        i, j;
-    
-    if (o.minorTickFreq)
-      minorTickSize = tickSize / o.minorTickFreq;
-                      
-    // Then store all possible ticks.
-    for (i = 0; (v = v2 = start + i * tickSize) <= max; ++i){
-      
-      // Round (this is always needed to fix numerical instability).
-      decimals = o.tickDecimals;
-      if (decimals === null) decimals = 1 - Math.floor(Math.log(tickSize) / Math.LN10);
-      if (decimals < 0) decimals = 0;
-      
-      v = v.toFixed(decimals);
-      axis.ticks.push({ v: v, label: o.tickFormatter(v, {min : axis.min, max : axis.max}) });
-
-      if (o.minorTickFreq) {
-        for (j = 0; j < o.minorTickFreq && (i * tickSize + j * minorTickSize) < max; ++j) {
-          v = v2 + j * minorTickSize;
-          axis.minorTicks.push({ v: v, label: o.tickFormatter(v, {min : axis.min, max : axis.max}) });
-        }
-      }
-    }
-
-  },
-
-  _setTranslations : function (logarithmic) {
-    this.d2p = (logarithmic ? d2pLog : d2p);
-    this.p2d = (logarithmic ? p2dLog : p2d);
-  }
-};
-
-
-// Static Methods
-_.extend(Axis, {
-  getAxes : function (options) {
-    return {
-      x:  new Axis({options: options.xaxis,  n: 1, length: this.plotWidth}),
-      x2: new Axis({options: options.x2axis, n: 2, length: this.plotWidth}),
-      y:  new Axis({options: options.yaxis,  n: 1, length: this.plotHeight, offset: this.plotHeight, orientation: -1}),
-      y2: new Axis({options: options.y2axis, n: 2, length: this.plotHeight, offset: this.plotHeight, orientation: -1})
-    };
-  }
-});
-
-
-// Helper Methods
-
-function d2p (dataValue) {
-  return this.offset + this.orientation * (dataValue - this.min) * this.scale;
-}
-
-function p2d (pointValue) {
-  return (this.offset + this.orientation * pointValue) / this.scale + this.min;
-}
-
-function d2pLog (dataValue) {
-  return this.offset + this.orientation * (log(dataValue, this.options.base) - log(this.min, this.options.base)) * this.scale;
-}
-
-function p2dLog (pointValue) {
-  return exp((this.offset + this.orientation * pointValue) / this.scale + log(this.min, this.options.base), this.options.base);
-}
-
-function log (value, base) {
-  value = Math.log(Math.max(value, Number.MIN_VALUE));
-  if (base !== Math.E) 
-    value /= Math.log(base);
-  return value;
-}
-
-function exp (value, base) {
-  return (base === Math.E) ? Math.exp(value) : Math.pow(base, value);
-}
-
-Flotr.Axis = Axis;
+    Flotr.Axis = Axis;
 
 })();
 
@@ -3354,908 +3406,920 @@
 
 (function () {
 
-var
-  _ = Flotr._;
-
-function Series (o) {
-  _.extend(this, o);
-}
-
-Series.prototype = {
-
-  getRange: function () {
-
     var
-      data = this.data,
-      length = data.length,
-      xmin = Number.MAX_VALUE,
-      ymin = Number.MAX_VALUE,
-      xmax = -Number.MAX_VALUE,
-      ymax = -Number.MAX_VALUE,
-      xused = false,
-      yused = false,
-      x, y, i;
-