Added in support for new HPC Dashboard View, ability to retrieve HPC Dashboard view from views.py in separate function, support for log4javascript to provide integration with browser console for debugging, and leaflet support for MakiMarkers on encodings.
diff --git a/planetstack/core/plus/views.py b/planetstack/core/plus/views.py
index 386f6b5..b49e3a3 100644
--- a/planetstack/core/plus/views.py
+++ b/planetstack/core/plus/views.py
@@ -31,4 +31,147 @@
                                'reservations': reservations})
 
         context['userSliceInfo'] = userSliceInfo
+        context['cdnData'] = self.getCDNOperatorData();
         return self.render_to_response(context=context)
+
+    def getCDNOperatorData(self):
+        cdnData = {
+            "Arizona": {
+                "lat": 32.2333,
+                "long": -110.94799999999998,
+                "health": 0,
+                "numNodes": 15,
+                "numHPCSlivers": 2,
+                "siteUrl": "http://www.cs.arizona.edu/"
+            },
+            "I2 Singapore": {
+                "lat": 1.33544,
+                "long": 103.88999999999999,
+                "health": 0,
+                "numNodes": 15,
+                "numHPCSlivers": 5,
+                "siteUrl": "http://www.internet2.edu/"
+            },
+            "ON.Lab": {
+                "lat": 37.452955,
+                "long": -122.18176599999998,
+                "health": 0,
+                "numNodes": 45,
+                "numHPCSlivers": 12,
+                "siteUrl": "http://www.onlab.us/"
+            },
+            "I2 Washington DC": {
+                "lat": 38.009,
+                "long": -77.00029999999998,
+                "health": 0,
+                "numNodes": 50,
+                "numHPCSlivers": 7,
+                "siteUrl": "http://www.internet2.edu/"
+            },
+            "I2 Seattle": {
+                "lat": 47.6531,
+                "long": -122.31299999999999,
+                "health": 0,
+                "numNodes": 100,
+                "numHPCSlivers": 10,
+                "siteUrl": "http://www.internet2.edu/"
+            },
+            "I2 Salt Lake City": {
+                "lat": 40.7659,
+                "long": -111.844,
+                "health": 0,
+                "numNodes": 35,
+                "numHPCSlivers": 10,
+                "siteUrl": "http://www.internet2.edu/"
+            },
+            "I2 New York": {
+                "lat": 40.72,
+                "long": -73.99000000000001,
+                "health": 0,
+                "numNodes": 25,
+                "numHPCSlivers": 4,
+                "siteUrl": "http://www.internet2.edu/"
+            },
+            "I2 Los Angeles": {
+                "lat": 33.2505,
+                "long": -117.50299999999999,
+                "health": 0,
+                "numNodes": 20,
+                "numHPCSlivers": 10,
+                "siteUrl": "http://www.internet2.edu/"
+            },
+            "I2 Kansas City": {
+                "lat": 39.0012,
+                "long": -94.00630000000001,
+                "health": 0,
+                "numNodes": 17,
+                "numHPCSlivers": 8,
+                "siteUrl": "http://www.internet2.edu/"
+            },
+            "I2 Houston": {
+                "lat": 29.0077,
+                "long": -95.00369999999998,
+                "health": 0,
+                "numNodes": 15,
+                "numHPCSlivers": 10,
+                "siteUrl": "http://www.internet2.edu/"
+            },
+            "I2 Chicago": {
+                "lat": 41.0085,
+                "long": -87.00650000000002,
+                "health": 0,
+                "numNodes": 15,
+                "numHPCSlivers": 10,
+                "siteUrl": "http://www.internet2.edu/"
+            },
+            "I2 Atlanta": {
+                "lat": 33.0075,
+                "long": -84.00380000000001,
+                "health": 0,
+                "numNodes": 15,
+                "numHPCSlivers": 10,
+                "siteUrl": "http://www.internet2.edu/"
+            },
+            "MaxPlanck": {
+                "lat": 49.14,
+                "long": 6.588999999999942,
+                "health": 0,
+                "numNodes": 15,
+                "numHPCSlivers": 10,
+                "siteUrl": "http://www.mpi-sws.mpg.de/"
+            },
+            "GeorgiaTech": {
+                "lat": 33.7772,
+                "long": -84.39760000000001,
+                "health": 0,
+                "numNodes": 15,
+                "numHPCSlivers": 10,
+                "siteUrl": "http://www.gatech.edu/"
+            },
+            "Princeton": {
+                "lat": 40.3502,
+                "long": -74.6524,
+                "health": 0,
+                "numNodes": 15,
+                "numHPCSlivers": 10,
+                "siteUrl": "http://princeton.edu/"
+            },
+            "Washington": {
+                "lat": 47.6531,
+                "long": -122.31299999999999,
+                "health": 0,
+                "numNodes": 15,
+                "numHPCSlivers": 10,
+                "siteUrl": "https://www.washington.edu/"
+            },
+            "Stanford": {
+                "lat": 37.4294,
+                "long": -122.17200000000003,
+                "health": 0,
+                "numNodes": 15,
+                "numHPCSlivers": 10,
+                "siteUrl": "http://www.stanford.edu/"
+            },
+        }
+        return cdnData
+
diff --git a/planetstack/core/static/js/Leaflet.MakiMarkers.js b/planetstack/core/static/js/Leaflet.MakiMarkers.js
new file mode 100644
index 0000000..910bb31
--- /dev/null
+++ b/planetstack/core/static/js/Leaflet.MakiMarkers.js
@@ -0,0 +1,101 @@
+/*
+ * Leaflet plugin to create map icons using Maki Icons from MapBox.
+ *
+ * References:
+ *   Maki Icons: https://www.mapbox.com/maki/
+ *   MapBox Marker API: https://www.mapbox.com/developers/api/#Stand-alone.markers
+ *
+ * Usage:
+ *   var icon = L.MakiMarkers.icon({icon: "rocket", color: "#b0b", size: "m"});
+ *
+ * License:
+ *   MIT: http://jseppi.mit-license.org/
+ */
+(function () {
+  "use strict";
+  L.MakiMarkers = {
+    // Available Maki Icons
+    icons: ["circle-stroked", "circle", "square-stroked", "square",
+      "triangle-stroked", "triangle", "star-stroked", "star", "cross",
+      "marker-stroked", "marker", "religious-jewish", "religious-christian",
+      "religious-muslim", "cemetery", "rocket", "airport", "heliport", "rail",
+      "rail-metro", "rail-light", "bus", "fuel", "parking", "parking-garage",
+      "airfield", "roadblock", "ferry", "harbor", "bicycle", "park", "park2",
+      "museum", "lodging", "monument", "zoo", "garden", "campsite", "theatre",
+      "art-gallery", "pitch", "soccer", "america-football", "tennis", "basketball",
+      "baseball", "golf", "swimming", "cricket", "skiing", "school", "college",
+      "library", "post", "fire-station", "town-hall", "police", "prison",
+      "embassy", "beer", "restaurant", "cafe", "shop", "fast-food", "bar", "bank",
+      "grocery", "cinema", "pharmacy", "hospital", "danger", "industrial",
+      "warehouse", "commercial", "building", "place-of-worship", "alcohol-shop",
+      "logging", "oil-well", "slaughterhouse", "dam", "water", "wetland",
+      "disability", "telephone", "emergency-telephone", "toilets", "waste-basket",
+      "music", "land-use", "city", "town", "village", "farm", "bakery", "dog-park",
+      "lighthouse", "clothing-store", "polling-place", "playground", "entrance",
+      "heart", "london-underground", "minefield", "rail-underground", "rail-above",
+      "camera", "laundry", "car", "suitcase", "hairdresser", "chemist"],
+    defaultColor: "#0a0",
+    defaultIcon: "circle-stroked",
+    defaultSize: "m",
+    apiUrl: "https://api.tiles.mapbox.com/v3/marker/",
+    smallOptions: {
+      iconSize: [20, 50],
+      popupAnchor: [0,-20]
+    },
+    mediumOptions: {
+      iconSize: [30,70],
+      popupAnchor: [0,-30]
+    },
+    largeOptions: {
+      iconSize: [36,90],
+      popupAnchor: [0,-40]
+    }
+  };
+
+  L.MakiMarkers.Icon = L.Icon.extend({
+    options: {
+      //Maki icon: any from https://www.mapbox.com/maki/ (ref: L.MakiMarkers.icons)
+      icon: L.MakiMarkers.defaultIcon,
+      //Marker color: short or long form hex color code
+      color: L.MakiMarkers.defaultColor,
+      //Marker size: "s" (small), "m" (medium), or "l" (large)
+      size: L.MakiMarkers.defaultSize,
+      shadowAnchor: null,
+      shadowSize: null,
+      shadowUrl: null,
+      className: 'maki-marker'
+    },
+
+    initialize: function(options) {
+      var pin;
+
+      options = L.setOptions(this, options);
+
+      switch (options.size) {
+        case "s":
+          L.extend(options, L.MakiMarkers.smallOptions);
+          break;
+        case "l":
+          L.extend(options, L.MakiMarkers.largeOptions);
+          break;
+        default:
+          options.size = "m";
+          L.extend(options, L.MakiMarkers.mediumOptions);
+          break;
+      }
+
+      if (options.color.charAt(0) === '#') {
+        options.color = options.color.substr(1);
+      }
+
+      pin = "pin-" + options.size + "-" + options.icon + "+" +
+        options.color + ".png";
+
+      options.iconUrl = "" + L.MakiMarkers.apiUrl + pin;
+    }
+  });
+
+  L.MakiMarkers.icon = function(options) {
+    return new L.MakiMarkers.Icon(options);
+  };
+})();
diff --git a/planetstack/core/static/log4javascript-1.4.6/changelog.txt b/planetstack/core/static/log4javascript-1.4.6/changelog.txt
new file mode 100644
index 0000000..fe10b97
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/changelog.txt
@@ -0,0 +1,379 @@
+log4javascript change log

+-------------------------

+

+1.4.6 (19/3/2013)

+- Added fix to handle 1223 status code from XMLHttpRequest in IE

+

+1.4.5 (20/2/2013)

+- Changed AjaxAppender to send raw data rather than URL-encoded form data when

+  content-type is not "application/x-www-form-urlencoded"

+

+- Exposed sendAllRemaining() method of AjaxAppender

+

+1.4.4 (8/2/2013)

+- Fixed issue with repeated Content-Type headers in AjaxAppender

+

+- Improved uniqueness of PopUpAppender window name

+

+1.4.3 (18/9/2012)

+- Added addHeader() and getHeaders() methods to AjaxAppender

+

+- Modified sendAllOnUnload feature of AjaxAppender. It now works in WebKit but

+  at the expense of popping up a confirm dialog. That being the case, it is now

+  disabled by default.

+

+- Removed leaked global variable "initialized" 

+

+- Fixed bugs #3528265, #3560924, #3560922, #2805479, #3510639 on Sourceforge

+  Tracker

+

+

+1.4.2 (13/10/2011)

+- Fixed JsonLayout trailing comma issue. See

+  http://stackoverflow.com/questions/7735382/asmx-weirdness-deserializing-json-

+  blob-from-log4javascript-logging

+

+- Fixed bugs #3401332, #3185753, #2884623, #2817213 on Sourceforge Tracker

+

+

+1.4.1 (23/3/2009)

+- Fixed document.domain/query string bug (#2519903 on Sourceforge Tracker)

+

+- Added isVisible() method to PopUpAppender

+

+- Added check for whether the console has been closed in isVisible() method of

+  InPageAppender

+

+- Included unit tests in the distribution

+

+

+1.4 (30/10/2008)

+

+- Added time() and timeEnd() methods to Logger

+

+- Added group() and groupEnd() methods to Logger and support for displaying

+  expandable groups to InPageAppender and PopUpAppender

+

+- Added facility to layout custom fields. A custom field value may now

+  optionally be a function which is passed a reference to the layout and a

+  logging event and run at the time the layout's format method is called

+

+- Added option to XmlLayout and JsonLayout to allow multiple messages to be

+  formatted either as one combined message or multiple messages

+

+- Added code to set log4javascript as a property of the window object. This

+  ensures that if log4javascript is loaded via eval() (e.g. Dojo's module

+  loading system), the log4javascript object is guaranteed to be available even

+  though IE does not evaluate the script in the global scope

+

+- Added useDocumentWrite parameter to constructors and isUseDocumentWrite()

+  and setUseDocumentWrite() methods for InPageAppender and PopUpAppender and

+  added console.html to the build so that the appender may use either the

+  existing document.write method or the external HTML file to build the console.

+  This is to allow support for setting document.domain in the main document,

+  which is impossible with the document.write method

+

+- Added milliseconds property to logging events and changed JsonLayout,

+  XmlLayout and HttpPostDataLayout to include milliseconds by default

+

+- Added layout parameter to AjaxAppender and a toString() method on each layout

+

+- Setting configuration properties in appenders via constructor paramaters has

+  been phased out.

+

+- Added window.unload handler for AjaxAppender to send outstanding messages.

+  Doesn't work in Opera

+

+- Implemented log4j-style hierarchical loggers with additive appenders. For

+  example, a logger called "app.stuff" has as its parent the logger called

+  "app", all of whose appenders it inherits

+

+- Changed XmlLayout and JsonLayout to send data as a key/value pair

+

+- Bugfix for inaccessible error details

+

+- An appender can no longer be added more than once to the same logger

+

+- Multiple messages may now be specified in logger methods

+

+- New conversion character 'a' added to PatternLayout. This is the same as 'm'

+  except that if the first message specified is an array then it treats each

+  element of the array as though it had been passed in as a message parameter

+

+- Command line added to console windows with configurable object expansion

+  depth. Command line presence and object expansion depth are configurable in

+  the appender via setShowCommandLine() and setCommandLineObjectExpansionDepth()

+  methods respectively

+

+- Command line history, navigated by cursor keys and stored in a session cookie

+

+- Firebug-inspired command line functions added: $, dir, dirxml, cd, clear,

+  keys, values, expansionDepth

+

+- Fixes for several bugs in object expansion

+

+- Fix for bug in initialization of InPageAppender in IE 5

+

+- Fix to allow searchable HTML in log entries

+

+- Fix for bug which automatically displayed search next/previous buttons when

+  the search box is clicked regardless of whether there were any matches

+

+- Searches in PopUpAppender and InPageAppender now preserve formatting

+

+- More fixes to interaction of search and severity filters in console window

+  used by PopUpAppender and InPageAppender

+

+- Added SwitchableConsoleAppender that allows flipping from an in-page console

+  to a pop-up console window and back again while retaining state

+

+- Custom events added that are raised when PopUpAppender and InPageAppender

+  windows load and unload, and on the main log4javascript object when the main

+  page loads, when the main page is resized and when log4javascript errors occur

+

+- InPageAppender may now be initialized before the page loads by providing an

+  element id for its container, or omitting the container altogether (in which

+  case the appender is added as a fixed div at the bottom of the page)

+

+- Tweaked PopUpAppender and InPageAppender so that the formatted log message is

+  produced when append() is called rather than when the message is actually sent

+  to the console window, thus allowing reliable temporary switching of layouts

+

+- Much improved scrolling to current search match: scrolls only if part of the

+  search match is not visible and centres around it rather than putting flush to

+  the top left

+

+- Removed setReadable() method from JsonLayout - now specified only in the

+  constructor

+

+- Fixed problem in IE where copying selections of log entries would produce two

+  copies of each log entry

+

+

+1.3.1 (20/11/2006)

+

+- Fix to interaction of search and severity filters in console window used by

+  PopUpAppender and InPageAppender

+

+

+1.3 (19/10/2006)

+

+- Fully tested and supported in IE 7 Beta 3

+

+- Added support for FireBug logging levels in BrowserConsoleAppender

+

+- Added optional limit to the number of log messages stored by PopUpAppender and

+  InPageAppender. When this limit is reached, each new message causes the oldest

+  message to be discarded.

+

+- Exceptions passed into logging methods are now displayed in logging output.

+

+- Added facility to pass objects as well as strings to logging methods.

+  Enhanced conversion character 'm' to PatternLayout to expand object properties

+  in the formatted output

+

+- Added stack trace to error reports (alerts and log entries) in Firefox. This

+  is turned off by default but can be switched on via the new

+  log4javascript.setShowStackTraces function

+

+- Added log4javascript_stub.js to distribution - this has stub versions of all

+  objects and methods in log4javascript.js and can be used as a lightweight

+  replacement for log4javascript.js in production systems

+

+- Added log4javascript_compressed.js to distribution - comments and whitespace

+  are removed, resulting in a 30% smaller file

+

+- Added custom fields to layouts

+

+- Added setReopenWhenClosed and isReopenWhenClosed methods to PopUpAppender to

+  allow log4javascript to open a new pop-up console window automatically at the

+  time of the next log entry after the original window was closed

+

+- Layout.ignoresThrowable implemented to allow Layout/Appender combinations to

+  decide whether to display exceptions

+

+- Added NullLayout that performs no formatting on the logging event

+

+- Lowered BrowserConsoleAppender's default threshold to DEBUG and set its

+  default layout to NullLayout so that unformatted objects can be passed into

+  FireBug

+

+- Renamed InlineAppender to InPageAppender (though InlineAppender still works

+  for the sake of backwards compatibility)

+

+- Cosmetic changes to InPageAppender and PopUpAppender

+

+- Added equals() method to Level

+

+- Added removeAppender() and removeAllAppenders() methods to Logger

+

+- Added extensive test script

+

+- Fixed bug where Appender.setLayout and Appender.setThreshold threw an

+  unhandled error if not supplied with a genuine Layout or Level respectively

+

+- Fixed bug where InlinePopUpAppender and PopUpAppender continue to poll their

+  console windows indefinitely (thus generating warnings) if the console window

+  is closed before it has fully loaded

+

+- Fixed bug in w and W symbols in SimpleDateFormat

+

+- Fixed bug with quotes inside messages in JsonLayout

+

+- Fixed bugs in PatternLayout with built-in DATE format and truncation modifiers

+

+- Changed execution order of callbacks in AjaxAppender so that

+  requestSuccessCallback is guaranteed to be called before the next request is

+  sent

+

+- Changed AjaxAppender so that log messages are formatted immediately before

+  a request is sent rather than when append() is called, thus guaranteeing that

+  changes to the layout take effect immediately

+

+- PopUpAppender windows now have unique names per hostname to prevent clashes

+  from multiple instances of log4javascript running on different servers

+

+- Fixed error in XmlLayout's format method when passed an object

+

+- Fixed errors in JsonLayout's handling of strings containing line breaks and/or

+  double quotes

+

+

+1.2 (21/6/2006)

+

+- Tested in and added workaround for a bug in Opera 9 Beta 2 and Opera 9.0

+

+- Tested in Konqueror 3.4 and 3.5 and added workarounds and fixes for browser

+  bugs

+

+- Added addErrorListener and removeErrorListener methods to log4javascript

+  object to allow custom error handling

+

+- Added close() method to PopUpAppender and InlineAppender

+

+- Added test directory with an HTML page containing automated tests

+

+- Added enable/disable logging checkbox to InlinePopUpAppender and PopUpAppender

+  so that unnecessary messages (for instance, from a timer) can be ignored

+

+- An invalid value supplied to a configuration option setter now leaves config

+  property unchanged rather than reverting to the default

+

+- Fixed bug in PopUpAppender in IE on Windows XP Service Pack 2 when accessed

+  via the file system. The browser by default disables JavaScript in the pop-up

+  window until the user opts to enable it, at which point they would previously

+  see an uncaught error in log4javascript. Now, a proper error message is

+  displayed and the appender is disabled.

+

+- Slight alterations to toolbar in InlineAppender and PopUpAppender - text

+  capitalization and title attributes added to inputs

+

+- toString() method added to all appenders

+

+- Correction to errors in XmlLayout's output

+

+- Documentation corrections and additions

+

+

+1.1.1 (17/5/2006)

+

+- Fixed a minor bug with scrolling to the latest message and added "scroll to

+  latest" checkbox to console window in InlineAppender and PopUpAppender

+

+

+1.1 (16/5/2006)

+

+- Added configuration option setters on Appenders and refactored to prevent

+  config properties being altered directly. Several configuration options

+  may not be altered after the appender has been initialized

+

+- Added scrollToLatestMessage constructor parameter, isScrollToLatestMessage

+  and setScrollToLatestMessage methods to InlineAppender and PopUpAppender

+

+- Added isVisible method to InlineAppender

+

+- Changed setShowOneError to setAlertAllErrors in logLog, with obvious change

+  in logic

+

+- Added layout property key configuration options to layout constructors for

+  JsonLayout and HttpPostDataLayout

+

+- Changed the default timestamp property name to "timestamp" instead of

+  "timeStamp" in JsonLayout and HttpPostDataLayout

+

+- Expanded documentation to include a section in the manual about configuring

+  appenders

+

+- Removed browser sniffing code

+

+

+1.0.1 (30/4/2006)

+

+- Option to have new log messages appear at the top added to InlineAppender and

+  PopUpAppender. This option can be specified in the constructor and can also

+  be toggled via a checkbox in the console window

+

+- PopUpAppender changed to not focus the pop-up console window by default, and

+  the demo page altered to create its own logger with focussing turned on,

+  meaning the behaviour in the demo is essentially unchanged

+

+

+1.0 (26/4/2006)

+

+- Tweaks to default values in PopUpAppender and InlineAppender

+

+- Bugfixes and stylistic tweaks resulting from running JSLint on

+  log4javascript.js

+

+

+1.0 beta 2

+

+- Show/hide button removed from InlineAppender, replaced by show() and hide()

+  methods on the InlineAppender object

+

+- batchSeparator, batchHeader and batchFooter added to Layout and applied to

+  JsonLayout - a batch of JSON log messages is now created as an array literal

+

+

+1.0 beta

+

+- TRACE level added, since this was added to log4j in 1.2.12

+

+- PopUpAppender default settings bugfix

+

+- getLevel method added to Logger

+

+- Tweak to vertical alignment of checkboxes and padding of buttons in

+  InlineAppender and PopUpAppender

+

+- Fixed getDefaultLogger and getNullLogger to return loggers other than the

+  root logger

+

+0.96

+

+- Moved console.html to inline document.writes in log4javascript.js

+

+- Fixed getDefaultLogger to return the same object on successive calls

+

+- Fixed scrolling issue in Opera InlineAppender and PopUpAppender

+

+- Scrollbars are now automatic on InlineAppender and PopUpAppender, i.e. they

+  only appear when required

+

+- Fixed bug where regex searches were not applied to new log entries in

+  InlineAppender and PopUpAppender

+

+- Changed Safari font size in InlineAppender and PopUpAppender

+

+0.95

+

+- AjaxAppender enhancements:

+	- waitForResponse added

+	- timer added

+

+- layout parameter added to all appender constructors

+

+0.94

+- First publicly available version

+- IE 5 support added

+- Full support for wrapping in IE added for InlineAppender and PopUpAppender
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/console.html b/planetstack/core/static/log4javascript-1.4.6/console.html
new file mode 100644
index 0000000..476d272
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/console.html
@@ -0,0 +1,263 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+<head>

+<title>log4javascript</title>

+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

+<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->

+<meta http-equiv="X-UA-Compatible" content="IE=7" />

+<script type="text/javascript">var isIe = false, isIePre7 = false;</script>

+<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->

+<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->

+<script type="text/javascript">

+//<![CDATA[

+var loggingEnabled=true;var logQueuedEventsTimer=null;var logEntries=[];var logEntriesAndSeparators=[];var logItems=[];var renderDelay=100;var unrenderedLogItemsExist=false;var rootGroup,currentGroup=null;var loaded=false;var currentLogItem=null;var logMainContainer;function copyProperties(obj,props){for(var i in props){obj[i]=props[i];}}

+function LogItem(){}

+LogItem.prototype={mainContainer:null,wrappedContainer:null,unwrappedContainer:null,group:null,appendToLog:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].appendToLog();}

+this.group.update();},doRemove:function(doUpdate,removeFromGroup){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].remove();}

+this.unwrappedElementContainer=null;this.wrappedElementContainer=null;this.mainElementContainer=null;}

+if(this.group&&removeFromGroup){this.group.removeChild(this,doUpdate);}

+if(this===currentLogItem){currentLogItem=null;}},remove:function(doUpdate,removeFromGroup){this.doRemove(doUpdate,removeFromGroup);},render:function(){},accept:function(visitor){visitor.visit(this);},getUnwrappedDomContainer:function(){return this.group.unwrappedElementContainer.contentDiv;},getWrappedDomContainer:function(){return this.group.wrappedElementContainer.contentDiv;},getMainDomContainer:function(){return this.group.mainElementContainer.contentDiv;}};LogItem.serializedItemKeys={LOG_ENTRY:0,GROUP_START:1,GROUP_END:2};function LogItemContainerElement(){}

+LogItemContainerElement.prototype={appendToLog:function(){var insertBeforeFirst=(newestAtTop&&this.containerDomNode.hasChildNodes());if(insertBeforeFirst){this.containerDomNode.insertBefore(this.mainDiv,this.containerDomNode.firstChild);}else{this.containerDomNode.appendChild(this.mainDiv);}}};function SeparatorElementContainer(containerDomNode){this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="separator";this.mainDiv.innerHTML="&nbsp;";}

+SeparatorElementContainer.prototype=new LogItemContainerElement();SeparatorElementContainer.prototype.remove=function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;};function Separator(){this.rendered=false;}

+Separator.prototype=new LogItem();copyProperties(Separator.prototype,{render:function(){var containerDomNode=this.group.contentDiv;if(isIe){this.unwrappedElementContainer=new SeparatorElementContainer(this.getUnwrappedDomContainer());this.wrappedElementContainer=new SeparatorElementContainer(this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new SeparatorElementContainer(this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}

+this.content=this.formattedMessage;this.rendered=true;}});function GroupElementContainer(group,containerDomNode,isRoot,isWrapped){this.group=group;this.containerDomNode=containerDomNode;this.isRoot=isRoot;this.isWrapped=isWrapped;this.expandable=false;if(this.isRoot){if(isIe){this.contentDiv=logMainContainer.appendChild(document.createElement("div"));this.contentDiv.id=this.isWrapped?"log_wrapped":"log_unwrapped";}else{this.contentDiv=logMainContainer;}}else{var groupElementContainer=this;this.mainDiv=document.createElement("div");this.mainDiv.className="group";this.headingDiv=this.mainDiv.appendChild(document.createElement("div"));this.headingDiv.className="groupheading";this.expander=this.headingDiv.appendChild(document.createElement("span"));this.expander.className="expander unselectable greyedout";this.expander.unselectable=true;var expanderText=this.group.expanded?"-":"+";this.expanderTextNode=this.expander.appendChild(document.createTextNode(expanderText));this.headingDiv.appendChild(document.createTextNode(" "+this.group.name));this.contentDiv=this.mainDiv.appendChild(document.createElement("div"));var contentCssClass=this.group.expanded?"expanded":"collapsed";this.contentDiv.className="groupcontent "+contentCssClass;this.expander.onclick=function(){if(groupElementContainer.group.expandable){groupElementContainer.group.toggleExpanded();}};}}

+GroupElementContainer.prototype=new LogItemContainerElement();copyProperties(GroupElementContainer.prototype,{toggleExpanded:function(){if(!this.isRoot){var oldCssClass,newCssClass,expanderText;if(this.group.expanded){newCssClass="expanded";oldCssClass="collapsed";expanderText="-";}else{newCssClass="collapsed";oldCssClass="expanded";expanderText="+";}

+replaceClass(this.contentDiv,newCssClass,oldCssClass);this.expanderTextNode.nodeValue=expanderText;}},remove:function(){if(!this.isRoot){this.headingDiv=null;this.expander.onclick=null;this.expander=null;this.expanderTextNode=null;this.contentDiv=null;this.containerDomNode=null;this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;}},reverseChildren:function(){var node=null;var childDomNodes=[];while((node=this.contentDiv.firstChild)){this.contentDiv.removeChild(node);childDomNodes.push(node);}

+while((node=childDomNodes.pop())){this.contentDiv.appendChild(node);}},update:function(){if(!this.isRoot){if(this.group.expandable){removeClass(this.expander,"greyedout");}else{addClass(this.expander,"greyedout");}}},clear:function(){if(this.isRoot){this.contentDiv.innerHTML="";}}});function Group(name,isRoot,initiallyExpanded){this.name=name;this.group=null;this.isRoot=isRoot;this.initiallyExpanded=initiallyExpanded;this.elementContainers=[];this.children=[];this.expanded=initiallyExpanded;this.rendered=false;this.expandable=false;}

+Group.prototype=new LogItem();copyProperties(Group.prototype,{addChild:function(logItem){this.children.push(logItem);logItem.group=this;},render:function(){if(isIe){var unwrappedDomContainer,wrappedDomContainer;if(this.isRoot){unwrappedDomContainer=logMainContainer;wrappedDomContainer=logMainContainer;}else{unwrappedDomContainer=this.getUnwrappedDomContainer();wrappedDomContainer=this.getWrappedDomContainer();}

+this.unwrappedElementContainer=new GroupElementContainer(this,unwrappedDomContainer,this.isRoot,false);this.wrappedElementContainer=new GroupElementContainer(this,wrappedDomContainer,this.isRoot,true);this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{var mainDomContainer=this.isRoot?logMainContainer:this.getMainDomContainer();this.mainElementContainer=new GroupElementContainer(this,mainDomContainer,this.isRoot,false);this.elementContainers=[this.mainElementContainer];}

+this.rendered=true;},toggleExpanded:function(){this.expanded=!this.expanded;for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].toggleExpanded();}},expand:function(){if(!this.expanded){this.toggleExpanded();}},accept:function(visitor){visitor.visitGroup(this);},reverseChildren:function(){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].reverseChildren();}}},update:function(){var previouslyExpandable=this.expandable;this.expandable=(this.children.length!==0);if(this.expandable!==previouslyExpandable){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].update();}}},flatten:function(){var visitor=new GroupFlattener();this.accept(visitor);return visitor.logEntriesAndSeparators;},removeChild:function(child,doUpdate){array_remove(this.children,child);child.group=null;if(doUpdate){this.update();}},remove:function(doUpdate,removeFromGroup){for(var i=0,len=this.children.length;i<len;i++){this.children[i].remove(false,false);}

+this.children=[];this.update();if(this===currentGroup){currentGroup=this.group;}

+this.doRemove(doUpdate,removeFromGroup);},serialize:function(items){items.push([LogItem.serializedItemKeys.GROUP_START,this.name]);for(var i=0,len=this.children.length;i<len;i++){this.children[i].serialize(items);}

+if(this!==currentGroup){items.push([LogItem.serializedItemKeys.GROUP_END]);}},clear:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clear();}}});function LogEntryElementContainer(){}

+LogEntryElementContainer.prototype=new LogItemContainerElement();copyProperties(LogEntryElementContainer.prototype,{remove:function(){this.doRemove();},doRemove:function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;this.contentElement=null;this.containerDomNode=null;},setContent:function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=content;}},setSearchMatch:function(isMatch){var oldCssClass=isMatch?"searchnonmatch":"searchmatch";var newCssClass=isMatch?"searchmatch":"searchnonmatch";replaceClass(this.mainDiv,newCssClass,oldCssClass);},clearSearch:function(){removeClass(this.mainDiv,"searchmatch");removeClass(this.mainDiv,"searchnonmatch");}});function LogEntryWrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.mainDiv.className="logentry wrapped "+this.logEntry.level;this.contentElement=this.mainDiv;}

+LogEntryWrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryWrappedElementContainer.prototype.setContent=function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=wrappedContent;}};function LogEntryUnwrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry unwrapped "+this.logEntry.level;this.pre=this.mainDiv.appendChild(document.createElement("pre"));this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.pre.className="unwrapped";this.contentElement=this.pre;}

+LogEntryUnwrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryUnwrappedElementContainer.prototype.remove=function(){this.doRemove();this.pre=null;};function LogEntryMainElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry nonielogentry "+this.logEntry.level;this.contentElement=this.mainDiv.appendChild(document.createElement("span"));this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));}

+LogEntryMainElementContainer.prototype=new LogEntryElementContainer();function LogEntry(level,formattedMessage){this.level=level;this.formattedMessage=formattedMessage;this.rendered=false;}

+LogEntry.prototype=new LogItem();copyProperties(LogEntry.prototype,{render:function(){var logEntry=this;var containerDomNode=this.group.contentDiv;if(isIe){this.formattedMessage=this.formattedMessage.replace(/\r\n/g,"\r");this.unwrappedElementContainer=new LogEntryUnwrappedElementContainer(this,this.getUnwrappedDomContainer());this.wrappedElementContainer=new LogEntryWrappedElementContainer(this,this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new LogEntryMainElementContainer(this,this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}

+this.content=this.formattedMessage;this.rendered=true;},setContent:function(content,wrappedContent){if(content!=this.content){if(isIe&&(content!==this.formattedMessage)){content=content.replace(/\r\n/g,"\r");}

+for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setContent(content,wrappedContent);}

+this.content=content;}},getSearchMatches:function(){var matches=[];var i,len;if(isIe){var unwrappedEls=getElementsByClass(this.unwrappedElementContainer.mainDiv,"searchterm","span");var wrappedEls=getElementsByClass(this.wrappedElementContainer.mainDiv,"searchterm","span");for(i=0,len=unwrappedEls.length;i<len;i++){matches[i]=new Match(this.level,null,unwrappedEls[i],wrappedEls[i]);}}else{var els=getElementsByClass(this.mainElementContainer.mainDiv,"searchterm","span");for(i=0,len=els.length;i<len;i++){matches[i]=new Match(this.level,els[i]);}}

+return matches;},setSearchMatch:function(isMatch){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setSearchMatch(isMatch);}},clearSearch:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clearSearch();}},accept:function(visitor){visitor.visitLogEntry(this);},serialize:function(items){items.push([LogItem.serializedItemKeys.LOG_ENTRY,this.level,this.formattedMessage]);}});function LogItemVisitor(){}

+LogItemVisitor.prototype={visit:function(logItem){},visitParent:function(logItem){if(logItem.group){logItem.group.accept(this);}},visitChildren:function(logItem){for(var i=0,len=logItem.children.length;i<len;i++){logItem.children[i].accept(this);}},visitLogEntry:function(logEntry){this.visit(logEntry);},visitSeparator:function(separator){this.visit(separator);},visitGroup:function(group){this.visit(group);}};function GroupFlattener(){this.logEntriesAndSeparators=[];}

+GroupFlattener.prototype=new LogItemVisitor();GroupFlattener.prototype.visitGroup=function(group){this.visitChildren(group);};GroupFlattener.prototype.visitLogEntry=function(logEntry){this.logEntriesAndSeparators.push(logEntry);};GroupFlattener.prototype.visitSeparator=function(separator){this.logEntriesAndSeparators.push(separator);};window.onload=function(){if(location.search){var queryBits=unescape(location.search).substr(1).split("&"),nameValueBits;for(var i=0,len=queryBits.length;i<len;i++){nameValueBits=queryBits[i].split("=");if(nameValueBits[0]=="log4javascript_domain"){document.domain=nameValueBits[1];break;}}}

+logMainContainer=$("log");if(isIePre7){addClass(logMainContainer,"oldIe");}

+rootGroup=new Group("root",true);rootGroup.render();currentGroup=rootGroup;setCommandInputWidth();setLogContainerHeight();toggleLoggingEnabled();toggleSearchEnabled();toggleSearchFilter();toggleSearchHighlight();applyFilters();checkAllLevels();toggleWrap();toggleNewestAtTop();toggleScrollToLatest();renderQueuedLogItems();loaded=true;$("command").value="";$("command").autocomplete="off";$("command").onkeydown=function(evt){evt=getEvent(evt);if(evt.keyCode==10||evt.keyCode==13){evalCommandLine();stopPropagation(evt);}else if(evt.keyCode==27){this.value="";this.focus();}else if(evt.keyCode==38&&commandHistory.length>0){currentCommandIndex=Math.max(0,currentCommandIndex-1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}else if(evt.keyCode==40&&commandHistory.length>0){currentCommandIndex=Math.min(commandHistory.length-1,currentCommandIndex+1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}};$("command").onkeypress=function(evt){evt=getEvent(evt);if(evt.keyCode==38&&commandHistory.length>0&&evt.preventDefault){evt.preventDefault();}};$("command").onkeyup=function(evt){evt=getEvent(evt);if(evt.keyCode==27&&evt.preventDefault){evt.preventDefault();this.focus();}};document.onkeydown=function keyEventHandler(evt){evt=getEvent(evt);switch(evt.keyCode){case 69:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){evalLastCommand();cancelKeyEvent(evt);return false;}

+break;case 75:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusSearch();cancelKeyEvent(evt);return false;}

+break;case 40:case 76:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusCommandLine();cancelKeyEvent(evt);return false;}

+break;}};setTimeout(setLogContainerHeight,20);setShowCommandLine(showCommandLine);doSearch();};window.onunload=function(){if(mainWindowExists()){appender.unload();}

+appender=null;};function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}

+function setLoggingEnabled(enable){loggingEnabled=enable;}

+var appender=null;function setAppender(appenderParam){appender=appenderParam;}

+function setShowCloseButton(showCloseButton){$("closeButton").style.display=showCloseButton?"inline":"none";}

+function setShowHideButton(showHideButton){$("hideButton").style.display=showHideButton?"inline":"none";}

+var newestAtTop=false;function LogItemContentReverser(){}

+LogItemContentReverser.prototype=new LogItemVisitor();LogItemContentReverser.prototype.visitGroup=function(group){group.reverseChildren();this.visitChildren(group);};function setNewestAtTop(isNewestAtTop){var oldNewestAtTop=newestAtTop;var i,iLen,j,jLen;newestAtTop=Boolean(isNewestAtTop);if(oldNewestAtTop!=newestAtTop){var visitor=new LogItemContentReverser();rootGroup.accept(visitor);if(currentSearch){var currentMatch=currentSearch.matches[currentMatchIndex];var matchIndex=0;var matches=[];var actOnLogEntry=function(logEntry){var logEntryMatches=logEntry.getSearchMatches();for(j=0,jLen=logEntryMatches.length;j<jLen;j++){matches[matchIndex]=logEntryMatches[j];if(currentMatch&&logEntryMatches[j].equals(currentMatch)){currentMatchIndex=matchIndex;}

+matchIndex++;}};if(newestAtTop){for(i=logEntries.length-1;i>=0;i--){actOnLogEntry(logEntries[i]);}}else{for(i=0,iLen=logEntries.length;i<iLen;i++){actOnLogEntry(logEntries[i]);}}

+currentSearch.matches=matches;if(currentMatch){currentMatch.setCurrent();}}else if(scrollToLatest){doScrollToLatest();}}

+$("newestAtTop").checked=isNewestAtTop;}

+function toggleNewestAtTop(){var isNewestAtTop=$("newestAtTop").checked;setNewestAtTop(isNewestAtTop);}

+var scrollToLatest=true;function setScrollToLatest(isScrollToLatest){scrollToLatest=isScrollToLatest;if(scrollToLatest){doScrollToLatest();}

+$("scrollToLatest").checked=isScrollToLatest;}

+function toggleScrollToLatest(){var isScrollToLatest=$("scrollToLatest").checked;setScrollToLatest(isScrollToLatest);}

+function doScrollToLatest(){var l=logMainContainer;if(typeof l.scrollTop!="undefined"){if(newestAtTop){l.scrollTop=0;}else{var latestLogEntry=l.lastChild;if(latestLogEntry){l.scrollTop=l.scrollHeight;}}}}

+var closeIfOpenerCloses=true;function setCloseIfOpenerCloses(isCloseIfOpenerCloses){closeIfOpenerCloses=isCloseIfOpenerCloses;}

+var maxMessages=null;function setMaxMessages(max){maxMessages=max;pruneLogEntries();}

+var showCommandLine=false;function setShowCommandLine(isShowCommandLine){showCommandLine=isShowCommandLine;if(loaded){$("commandLine").style.display=showCommandLine?"block":"none";setCommandInputWidth();setLogContainerHeight();}}

+function focusCommandLine(){if(loaded){$("command").focus();}}

+function focusSearch(){if(loaded){$("searchBox").focus();}}

+function getLogItems(){var items=[];for(var i=0,len=logItems.length;i<len;i++){logItems[i].serialize(items);}

+return items;}

+function setLogItems(items){var loggingReallyEnabled=loggingEnabled;loggingEnabled=true;for(var i=0,len=items.length;i<len;i++){switch(items[i][0]){case LogItem.serializedItemKeys.LOG_ENTRY:log(items[i][1],items[i][2]);break;case LogItem.serializedItemKeys.GROUP_START:group(items[i][1]);break;case LogItem.serializedItemKeys.GROUP_END:groupEnd();break;}}

+loggingEnabled=loggingReallyEnabled;}

+function log(logLevel,formattedMessage){if(loggingEnabled){var logEntry=new LogEntry(logLevel,formattedMessage);logEntries.push(logEntry);logEntriesAndSeparators.push(logEntry);logItems.push(logEntry);currentGroup.addChild(logEntry);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}

+logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}

+function renderQueuedLogItems(){logQueuedEventsTimer=null;var pruned=pruneLogEntries();var initiallyHasMatches=currentSearch?currentSearch.hasMatches():false;for(var i=0,len=logItems.length;i<len;i++){if(!logItems[i].rendered){logItems[i].render();logItems[i].appendToLog();if(currentSearch&&(logItems[i]instanceof LogEntry)){currentSearch.applyTo(logItems[i]);}}}

+if(currentSearch){if(pruned){if(currentSearch.hasVisibleMatches()){if(currentMatchIndex===null){setCurrentMatchIndex(0);}

+displayMatches();}else{displayNoMatches();}}else if(!initiallyHasMatches&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}}

+if(scrollToLatest){doScrollToLatest();}

+unrenderedLogItemsExist=false;}

+function pruneLogEntries(){if((maxMessages!==null)&&(logEntriesAndSeparators.length>maxMessages)){var numberToDelete=logEntriesAndSeparators.length-maxMessages;var prunedLogEntries=logEntriesAndSeparators.slice(0,numberToDelete);if(currentSearch){currentSearch.removeMatches(prunedLogEntries);}

+var group;for(var i=0;i<numberToDelete;i++){group=logEntriesAndSeparators[i].group;array_remove(logItems,logEntriesAndSeparators[i]);array_remove(logEntries,logEntriesAndSeparators[i]);logEntriesAndSeparators[i].remove(true,true);if(group.children.length===0&&group!==currentGroup&&group!==rootGroup){array_remove(logItems,group);group.remove(true,true);}}

+logEntriesAndSeparators=array_removeFromStart(logEntriesAndSeparators,numberToDelete);return true;}

+return false;}

+function group(name,startExpanded){if(loggingEnabled){initiallyExpanded=(typeof startExpanded==="undefined")?true:Boolean(startExpanded);var newGroup=new Group(name,false,initiallyExpanded);currentGroup.addChild(newGroup);currentGroup=newGroup;logItems.push(newGroup);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}

+logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}

+function groupEnd(){currentGroup=(currentGroup===rootGroup)?rootGroup:currentGroup.group;}

+function mainPageReloaded(){currentGroup=rootGroup;var separator=new Separator();logEntriesAndSeparators.push(separator);logItems.push(separator);currentGroup.addChild(separator);}

+function closeWindow(){if(appender&&mainWindowExists()){appender.close(true);}else{window.close();}}

+function hide(){if(appender&&mainWindowExists()){appender.hide();}}

+var mainWindow=window;var windowId="log4javascriptConsoleWindow_"+new Date().getTime()+"_"+(""+Math.random()).substr(2);function setMainWindow(win){mainWindow=win;mainWindow[windowId]=window;if(opener&&closeIfOpenerCloses){pollOpener();}}

+function pollOpener(){if(closeIfOpenerCloses){if(mainWindowExists()){setTimeout(pollOpener,500);}else{closeWindow();}}}

+function mainWindowExists(){try{return(mainWindow&&!mainWindow.closed&&mainWindow[windowId]==window);}catch(ex){}

+return false;}

+var logLevels=["TRACE","DEBUG","INFO","WARN","ERROR","FATAL"];function getCheckBox(logLevel){return $("switch_"+logLevel);}

+function getIeWrappedLogContainer(){return $("log_wrapped");}

+function getIeUnwrappedLogContainer(){return $("log_unwrapped");}

+function applyFilters(){for(var i=0;i<logLevels.length;i++){if(getCheckBox(logLevels[i]).checked){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}

+updateSearchFromFilters();}

+function toggleAllLevels(){var turnOn=$("switch_ALL").checked;for(var i=0;i<logLevels.length;i++){getCheckBox(logLevels[i]).checked=turnOn;if(turnOn){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}}

+function checkAllLevels(){for(var i=0;i<logLevels.length;i++){if(!getCheckBox(logLevels[i]).checked){getCheckBox("ALL").checked=false;return;}}

+getCheckBox("ALL").checked=true;}

+function clearLog(){rootGroup.clear();currentGroup=rootGroup;logEntries=[];logItems=[];logEntriesAndSeparators=[];doSearch();}

+function toggleWrap(){var enable=$("wrap").checked;if(enable){addClass(logMainContainer,"wrap");}else{removeClass(logMainContainer,"wrap");}

+refreshCurrentMatch();}

+var searchTimer=null;function scheduleSearch(){try{clearTimeout(searchTimer);}catch(ex){}

+searchTimer=setTimeout(doSearch,500);}

+function Search(searchTerm,isRegex,searchRegex,isCaseSensitive){this.searchTerm=searchTerm;this.isRegex=isRegex;this.searchRegex=searchRegex;this.isCaseSensitive=isCaseSensitive;this.matches=[];}

+Search.prototype={hasMatches:function(){return this.matches.length>0;},hasVisibleMatches:function(){if(this.hasMatches()){for(var i=0;i<this.matches.length;i++){if(this.matches[i].isVisible()){return true;}}}

+return false;},match:function(logEntry){var entryText=String(logEntry.formattedMessage);var matchesSearch=false;if(this.isRegex){matchesSearch=this.searchRegex.test(entryText);}else if(this.isCaseSensitive){matchesSearch=(entryText.indexOf(this.searchTerm)>-1);}else{matchesSearch=(entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase())>-1);}

+return matchesSearch;},getNextVisibleMatchIndex:function(){for(var i=currentMatchIndex+1;i<this.matches.length;i++){if(this.matches[i].isVisible()){return i;}}

+for(i=0;i<=currentMatchIndex;i++){if(this.matches[i].isVisible()){return i;}}

+return-1;},getPreviousVisibleMatchIndex:function(){for(var i=currentMatchIndex-1;i>=0;i--){if(this.matches[i].isVisible()){return i;}}

+for(var i=this.matches.length-1;i>=currentMatchIndex;i--){if(this.matches[i].isVisible()){return i;}}

+return-1;},applyTo:function(logEntry){var doesMatch=this.match(logEntry);if(doesMatch){logEntry.group.expand();logEntry.setSearchMatch(true);var logEntryContent;var wrappedLogEntryContent;var searchTermReplacementStartTag="<span class=\"searchterm\">";var searchTermReplacementEndTag="<"+"/span>";var preTagName=isIe?"pre":"span";var preStartTag="<"+preTagName+" class=\"pre\">";var preEndTag="<"+"/"+preTagName+">";var startIndex=0;var searchIndex,matchedText,textBeforeMatch;if(this.isRegex){var flags=this.isCaseSensitive?"g":"gi";var capturingRegex=new RegExp("("+this.searchRegex.source+")",flags);var rnd=(""+Math.random()).substr(2);var startToken="%%s"+rnd+"%%";var endToken="%%e"+rnd+"%%";logEntryContent=logEntry.formattedMessage.replace(capturingRegex,startToken+"$1"+endToken);logEntryContent=escapeHtml(logEntryContent);var result;var searchString=logEntryContent;logEntryContent="";wrappedLogEntryContent="";while((searchIndex=searchString.indexOf(startToken,startIndex))>-1){var endTokenIndex=searchString.indexOf(endToken,searchIndex);matchedText=searchString.substring(searchIndex+startToken.length,endTokenIndex);textBeforeMatch=searchString.substring(startIndex,searchIndex);logEntryContent+=preStartTag+textBeforeMatch+preEndTag;logEntryContent+=searchTermReplacementStartTag+preStartTag+matchedText+

+preEndTag+searchTermReplacementEndTag;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+

+matchedText+searchTermReplacementEndTag;}

+startIndex=endTokenIndex+endToken.length;}

+logEntryContent+=preStartTag+searchString.substr(startIndex)+preEndTag;if(isIe){wrappedLogEntryContent+=searchString.substr(startIndex);}}else{logEntryContent="";wrappedLogEntryContent="";var searchTermReplacementLength=searchTermReplacementStartTag.length+

+this.searchTerm.length+searchTermReplacementEndTag.length;var searchTermLength=this.searchTerm.length;var searchTermLowerCase=this.searchTerm.toLowerCase();var logTextLowerCase=logEntry.formattedMessage.toLowerCase();while((searchIndex=logTextLowerCase.indexOf(searchTermLowerCase,startIndex))>-1){matchedText=escapeHtml(logEntry.formattedMessage.substr(searchIndex,this.searchTerm.length));textBeforeMatch=escapeHtml(logEntry.formattedMessage.substring(startIndex,searchIndex));var searchTermReplacement=searchTermReplacementStartTag+

+preStartTag+matchedText+preEndTag+searchTermReplacementEndTag;logEntryContent+=preStartTag+textBeforeMatch+preEndTag+searchTermReplacement;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+

+matchedText+searchTermReplacementEndTag;}

+startIndex=searchIndex+searchTermLength;}

+var textAfterLastMatch=escapeHtml(logEntry.formattedMessage.substr(startIndex));logEntryContent+=preStartTag+textAfterLastMatch+preEndTag;if(isIe){wrappedLogEntryContent+=textAfterLastMatch;}}

+logEntry.setContent(logEntryContent,wrappedLogEntryContent);var logEntryMatches=logEntry.getSearchMatches();this.matches=this.matches.concat(logEntryMatches);}else{logEntry.setSearchMatch(false);logEntry.setContent(logEntry.formattedMessage,logEntry.formattedMessage);}

+return doesMatch;},removeMatches:function(logEntries){var matchesToRemoveCount=0;var currentMatchRemoved=false;var matchesToRemove=[];var i,iLen,j,jLen;for(i=0,iLen=this.matches.length;i<iLen;i++){for(j=0,jLen=logEntries.length;j<jLen;j++){if(this.matches[i].belongsTo(logEntries[j])){matchesToRemove.push(this.matches[i]);if(i===currentMatchIndex){currentMatchRemoved=true;}}}}

+var newMatch=currentMatchRemoved?null:this.matches[currentMatchIndex];if(currentMatchRemoved){for(i=currentMatchIndex,iLen=this.matches.length;i<iLen;i++){if(this.matches[i].isVisible()&&!array_contains(matchesToRemove,this.matches[i])){newMatch=this.matches[i];break;}}}

+for(i=0,iLen=matchesToRemove.length;i<iLen;i++){array_remove(this.matches,matchesToRemove[i]);matchesToRemove[i].remove();}

+if(this.hasVisibleMatches()){if(newMatch===null){setCurrentMatchIndex(0);}else{var newMatchIndex=0;for(i=0,iLen=this.matches.length;i<iLen;i++){if(newMatch===this.matches[i]){newMatchIndex=i;break;}}

+setCurrentMatchIndex(newMatchIndex);}}else{currentMatchIndex=null;displayNoMatches();}}};function getPageOffsetTop(el,container){var currentEl=el;var y=0;while(currentEl&&currentEl!=container){y+=currentEl.offsetTop;currentEl=currentEl.offsetParent;}

+return y;}

+function scrollIntoView(el){var logContainer=logMainContainer;if(!$("wrap").checked){var logContainerLeft=logContainer.scrollLeft;var logContainerRight=logContainerLeft+logContainer.offsetWidth;var elLeft=el.offsetLeft;var elRight=elLeft+el.offsetWidth;if(elLeft<logContainerLeft||elRight>logContainerRight){logContainer.scrollLeft=elLeft-(logContainer.offsetWidth-el.offsetWidth)/2;}}

+var logContainerTop=logContainer.scrollTop;var logContainerBottom=logContainerTop+logContainer.offsetHeight;var elTop=getPageOffsetTop(el)-getToolBarsHeight();var elBottom=elTop+el.offsetHeight;if(elTop<logContainerTop||elBottom>logContainerBottom){logContainer.scrollTop=elTop-(logContainer.offsetHeight-el.offsetHeight)/2;}}

+function Match(logEntryLevel,spanInMainDiv,spanInUnwrappedPre,spanInWrappedDiv){this.logEntryLevel=logEntryLevel;this.spanInMainDiv=spanInMainDiv;if(isIe){this.spanInUnwrappedPre=spanInUnwrappedPre;this.spanInWrappedDiv=spanInWrappedDiv;}

+this.mainSpan=isIe?spanInUnwrappedPre:spanInMainDiv;}

+Match.prototype={equals:function(match){return this.mainSpan===match.mainSpan;},setCurrent:function(){if(isIe){addClass(this.spanInUnwrappedPre,"currentmatch");addClass(this.spanInWrappedDiv,"currentmatch");var elementToScroll=$("wrap").checked?this.spanInWrappedDiv:this.spanInUnwrappedPre;scrollIntoView(elementToScroll);}else{addClass(this.spanInMainDiv,"currentmatch");scrollIntoView(this.spanInMainDiv);}},belongsTo:function(logEntry){if(isIe){return isDescendant(this.spanInUnwrappedPre,logEntry.unwrappedPre);}else{return isDescendant(this.spanInMainDiv,logEntry.mainDiv);}},setNotCurrent:function(){if(isIe){removeClass(this.spanInUnwrappedPre,"currentmatch");removeClass(this.spanInWrappedDiv,"currentmatch");}else{removeClass(this.spanInMainDiv,"currentmatch");}},isOrphan:function(){return isOrphan(this.mainSpan);},isVisible:function(){return getCheckBox(this.logEntryLevel).checked;},remove:function(){if(isIe){this.spanInUnwrappedPre=null;this.spanInWrappedDiv=null;}else{this.spanInMainDiv=null;}}};var currentSearch=null;var currentMatchIndex=null;function doSearch(){var searchBox=$("searchBox");var searchTerm=searchBox.value;var isRegex=$("searchRegex").checked;var isCaseSensitive=$("searchCaseSensitive").checked;var i;if(searchTerm===""){$("searchReset").disabled=true;$("searchNav").style.display="none";removeClass(document.body,"searching");removeClass(searchBox,"hasmatches");removeClass(searchBox,"nomatches");for(i=0;i<logEntries.length;i++){logEntries[i].clearSearch();logEntries[i].setContent(logEntries[i].formattedMessage,logEntries[i].formattedMessage);}

+currentSearch=null;setLogContainerHeight();}else{$("searchReset").disabled=false;$("searchNav").style.display="block";var searchRegex;var regexValid;if(isRegex){try{searchRegex=isCaseSensitive?new RegExp(searchTerm,"g"):new RegExp(searchTerm,"gi");regexValid=true;replaceClass(searchBox,"validregex","invalidregex");searchBox.title="Valid regex";}catch(ex){regexValid=false;replaceClass(searchBox,"invalidregex","validregex");searchBox.title="Invalid regex: "+(ex.message?ex.message:(ex.description?ex.description:"unknown error"));return;}}else{searchBox.title="";removeClass(searchBox,"validregex");removeClass(searchBox,"invalidregex");}

+addClass(document.body,"searching");currentSearch=new Search(searchTerm,isRegex,searchRegex,isCaseSensitive);for(i=0;i<logEntries.length;i++){currentSearch.applyTo(logEntries[i]);}

+setLogContainerHeight();if(currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}else{displayNoMatches();}}}

+function updateSearchFromFilters(){if(currentSearch){if(currentSearch.hasMatches()){if(currentMatchIndex===null){currentMatchIndex=0;}

+var currentMatch=currentSearch.matches[currentMatchIndex];if(currentMatch.isVisible()){displayMatches();setCurrentMatchIndex(currentMatchIndex);}else{currentMatch.setNotCurrent();var nextVisibleMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextVisibleMatchIndex>-1){setCurrentMatchIndex(nextVisibleMatchIndex);displayMatches();}else{displayNoMatches();}}}else{displayNoMatches();}}}

+function refreshCurrentMatch(){if(currentSearch&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(currentMatchIndex);}}

+function displayMatches(){replaceClass($("searchBox"),"hasmatches","nomatches");$("searchBox").title=""+currentSearch.matches.length+" matches found";$("searchNav").style.display="block";setLogContainerHeight();}

+function displayNoMatches(){replaceClass($("searchBox"),"nomatches","hasmatches");$("searchBox").title="No matches found";$("searchNav").style.display="none";setLogContainerHeight();}

+function toggleSearchEnabled(enable){enable=(typeof enable=="undefined")?!$("searchDisable").checked:enable;$("searchBox").disabled=!enable;$("searchReset").disabled=!enable;$("searchRegex").disabled=!enable;$("searchNext").disabled=!enable;$("searchPrevious").disabled=!enable;$("searchCaseSensitive").disabled=!enable;$("searchNav").style.display=(enable&&($("searchBox").value!=="")&&currentSearch&&currentSearch.hasVisibleMatches())?"block":"none";if(enable){removeClass($("search"),"greyedout");addClass(document.body,"searching");if($("searchHighlight").checked){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}

+if($("searchFilter").checked){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}

+$("searchDisable").checked=!enable;}else{addClass($("search"),"greyedout");removeClass(document.body,"searching");removeClass(logMainContainer,"searchhighlight");removeClass(logMainContainer,"searchfilter");}

+setLogContainerHeight();}

+function toggleSearchFilter(){var enable=$("searchFilter").checked;if(enable){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}

+refreshCurrentMatch();}

+function toggleSearchHighlight(){var enable=$("searchHighlight").checked;if(enable){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}}

+function clearSearch(){$("searchBox").value="";doSearch();}

+function searchNext(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var nextMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextMatchIndex>currentMatchIndex||confirm("Reached the end of the page. Start from the top?")){setCurrentMatchIndex(nextMatchIndex);}}}

+function searchPrevious(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var previousMatchIndex=currentSearch.getPreviousVisibleMatchIndex();if(previousMatchIndex<currentMatchIndex||confirm("Reached the start of the page. Continue from the bottom?")){setCurrentMatchIndex(previousMatchIndex);}}}

+function setCurrentMatchIndex(index){currentMatchIndex=index;currentSearch.matches[currentMatchIndex].setCurrent();}

+function addClass(el,cssClass){if(!hasClass(el,cssClass)){if(el.className){el.className+=" "+cssClass;}else{el.className=cssClass;}}}

+function hasClass(el,cssClass){if(el.className){var classNames=el.className.split(" ");return array_contains(classNames,cssClass);}

+return false;}

+function removeClass(el,cssClass){if(hasClass(el,cssClass)){var existingClasses=el.className.split(" ");var newClasses=[];for(var i=0,len=existingClasses.length;i<len;i++){if(existingClasses[i]!=cssClass){newClasses[newClasses.length]=existingClasses[i];}}

+el.className=newClasses.join(" ");}}

+function replaceClass(el,newCssClass,oldCssClass){removeClass(el,oldCssClass);addClass(el,newCssClass);}

+function getElementsByClass(el,cssClass,tagName){var elements=el.getElementsByTagName(tagName);var matches=[];for(var i=0,len=elements.length;i<len;i++){if(hasClass(elements[i],cssClass)){matches.push(elements[i]);}}

+return matches;}

+function $(id){return document.getElementById(id);}

+function isDescendant(node,ancestorNode){while(node!=null){if(node===ancestorNode){return true;}

+node=node.parentNode;}

+return false;}

+function isOrphan(node){var currentNode=node;while(currentNode){if(currentNode==document.body){return false;}

+currentNode=currentNode.parentNode;}

+return true;}

+function escapeHtml(str){return str.replace(/&/g,"&amp;").replace(/[<]/g,"&lt;").replace(/>/g,"&gt;");}

+function getWindowWidth(){if(window.innerWidth){return window.innerWidth;}else if(document.documentElement&&document.documentElement.clientWidth){return document.documentElement.clientWidth;}else if(document.body){return document.body.clientWidth;}

+return 0;}

+function getWindowHeight(){if(window.innerHeight){return window.innerHeight;}else if(document.documentElement&&document.documentElement.clientHeight){return document.documentElement.clientHeight;}else if(document.body){return document.body.clientHeight;}

+return 0;}

+function getToolBarsHeight(){return $("switches").offsetHeight;}

+function getChromeHeight(){var height=getToolBarsHeight();if(showCommandLine){height+=$("commandLine").offsetHeight;}

+return height;}

+function setLogContainerHeight(){if(logMainContainer){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";logMainContainer.style.height=""+

+Math.max(0,windowHeight-getChromeHeight())+"px";}}

+function setCommandInputWidth(){if(showCommandLine){$("command").style.width=""+Math.max(0,$("commandLineContainer").offsetWidth-

+($("evaluateButton").offsetWidth+13))+"px";}}

+window.onresize=function(){setCommandInputWidth();setLogContainerHeight();};if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}

+return this.length;};}

+if(!Array.prototype.pop){Array.prototype.pop=function(){if(this.length>0){var val=this[this.length-1];this.length=this.length-1;return val;}};}

+if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}

+this.length=this.length-1;return firstItem;}};}

+if(!Array.prototype.splice){Array.prototype.splice=function(startIndex,deleteCount){var itemsAfterDeleted=this.slice(startIndex+deleteCount);var itemsDeleted=this.slice(startIndex,startIndex+deleteCount);this.length=startIndex;var argumentsArray=[];for(var i=0,len=arguments.length;i<len;i++){argumentsArray[i]=arguments[i];}

+var itemsToAppend=(argumentsArray.length>2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i<len;i++){this.push(itemsToAppend[i]);}

+return itemsDeleted;};}

+function array_remove(arr,val){var index=-1;for(var i=0,len=arr.length;i<len;i++){if(arr[i]===val){index=i;break;}}

+if(index>=0){arr.splice(index,1);return index;}else{return false;}}

+function array_removeFromStart(array,numberToRemove){if(Array.prototype.splice){array.splice(0,numberToRemove);}else{for(var i=numberToRemove,len=array.length;i<len;i++){array[i-numberToRemove]=array[i];}

+array.length=array.length-numberToRemove;}

+return array;}

+function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}

+return false;}

+function getErrorMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}

+return""+ex;}

+function moveCaretToEnd(input){if(input.setSelectionRange){input.focus();var length=input.value.length;input.setSelectionRange(length,length);}else if(input.createTextRange){var range=input.createTextRange();range.collapse(false);range.select();}

+input.focus();}

+function stopPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}}

+function getEvent(evt){return evt?evt:event;}

+function getTarget(evt){return evt.target?evt.target:evt.srcElement;}

+function getRelatedTarget(evt){if(evt.relatedTarget){return evt.relatedTarget;}else if(evt.srcElement){switch(evt.type){case"mouseover":return evt.fromElement;case"mouseout":return evt.toElement;default:return evt.srcElement;}}}

+function cancelKeyEvent(evt){evt.returnValue=false;stopPropagation(evt);}

+function evalCommandLine(){var expr=$("command").value;evalCommand(expr);$("command").value="";}

+function evalLastCommand(){if(lastCommand!=null){evalCommand(lastCommand);}}

+var lastCommand=null;var commandHistory=[];var currentCommandIndex=0;function evalCommand(expr){if(appender){appender.evalCommandAndAppend(expr);}else{var prefix=">>> "+expr+"\r\n";try{log("INFO",prefix+eval(expr));}catch(ex){log("ERROR",prefix+"Error: "+getErrorMessage(ex));}}

+if(expr!=commandHistory[commandHistory.length-1]){commandHistory.push(expr);if(appender){appender.storeCommandHistory(commandHistory);}}

+currentCommandIndex=(expr==commandHistory[currentCommandIndex])?currentCommandIndex+1:commandHistory.length;lastCommand=expr;}

+//]]>

+</script>

+<style type="text/css">

+body{background-color:white;color:black;padding:0;margin:0;font-family:tahoma,verdana,arial,helvetica,sans-serif;overflow:hidden}div#switchesContainer input{margin-bottom:0}div.toolbar{border-top:solid #ffffff 1px;border-bottom:solid #aca899 1px;background-color:#f1efe7;padding:3px 5px;font-size:68.75%}div.toolbar,div#search input{font-family:tahoma,verdana,arial,helvetica,sans-serif}div.toolbar input.button{padding:0 5px;font-size:100%}div.toolbar input.hidden{display:none}div#switches input#clearButton{margin-left:20px}div#levels label{font-weight:bold}div#levels label,div#options label{margin-right:5px}div#levels label#wrapLabel{font-weight:normal}div#search label{margin-right:10px}div#search label.searchboxlabel{margin-right:0}div#search input{font-size:100%}div#search input.validregex{color:green}div#search input.invalidregex{color:red}div#search input.nomatches{color:white;background-color:#ff6666}div#search input.nomatches{color:white;background-color:#ff6666}div#searchNav{display:none}div#commandLine{display:none}div#commandLine input#command{font-size:100%;font-family:Courier New,Courier}div#commandLine input#evaluateButton{}*.greyedout{color:gray !important;border-color:gray !important}*.greyedout *.alwaysenabled{color:black}*.unselectable{-khtml-user-select:none;-moz-user-select:none;user-select:none}div#log{font-family:Courier New,Courier;font-size:75%;width:100%;overflow:auto;clear:both;position:relative}div.group{border-color:#cccccc;border-style:solid;border-width:1px 0 1px 1px;overflow:visible}div.oldIe div.group,div.oldIe div.group *,div.oldIe *.logentry{height:1%}div.group div.groupheading span.expander{border:solid black 1px;font-family:Courier New,Courier;font-size:0.833em;background-color:#eeeeee;position:relative;top:-1px;color:black;padding:0 2px;cursor:pointer;cursor:hand;height:1%}div.group div.groupcontent{margin-left:10px;padding-bottom:2px;overflow:visible}div.group div.expanded{display:block}div.group div.collapsed{display:none}*.logentry{overflow:visible;display:none;white-space:pre}span.pre{white-space:pre}pre.unwrapped{display:inline !important}pre.unwrapped pre.pre,div.wrapped pre.pre{display:inline}div.wrapped pre.pre{white-space:normal}div.wrapped{display:none}body.searching *.logentry span.currentmatch{color:white !important;background-color:green !important}body.searching div.searchhighlight *.logentry span.searchterm{color:black;background-color:yellow}div.wrap *.logentry{white-space:normal !important;border-width:0 0 1px 0;border-color:#dddddd;border-style:dotted}div.wrap #log_wrapped,#log_unwrapped{display:block}div.wrap #log_unwrapped,#log_wrapped{display:none}div.wrap *.logentry span.pre{overflow:visible;white-space:normal}div.wrap *.logentry pre.unwrapped{display:none}div.wrap *.logentry span.wrapped{display:inline}div.searchfilter *.searchnonmatch{display:none !important}div#log *.TRACE,label#label_TRACE{color:#666666}div#log *.DEBUG,label#label_DEBUG{color:green}div#log *.INFO,label#label_INFO{color:#000099}div#log *.WARN,label#label_WARN{color:#999900}div#log *.ERROR,label#label_ERROR{color:red}div#log *.FATAL,label#label_FATAL{color:#660066}div.TRACE#log *.TRACE,div.DEBUG#log *.DEBUG,div.INFO#log *.INFO,div.WARN#log *.WARN,div.ERROR#log *.ERROR,div.FATAL#log *.FATAL{display:block}div#log div.separator{background-color:#cccccc;margin:5px 0;line-height:1px}

+</style>

+</head>

+<body id="body">

+<div id="switchesContainer">

+<div id="switches">

+<div id="levels" class="toolbar">

+Filters:

+<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>

+<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>

+<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>

+<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>

+<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>

+<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>

+<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>

+</div>

+<div id="search" class="toolbar">

+<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />

+<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />

+<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>

+<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>

+<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>

+<div id="searchNav">

+<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />

+<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />

+<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>

+<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>

+</div>

+</div>

+<div id="options" class="toolbar">

+Options:

+<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>

+<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>

+<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>

+<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>

+<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />

+<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />

+<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />

+</div>

+</div>

+</div>

+<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>

+<div id="commandLine" class="toolbar">

+<div id="commandLineContainer">

+<input type="text" id="command" title="Enter a JavaScript command here and hit return or press 'Evaluate'" />

+<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />

+</div>

+</div>

+</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/console_uncompressed.html b/planetstack/core/static/log4javascript-1.4.6/console_uncompressed.html
new file mode 100644
index 0000000..55679f8
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/console_uncompressed.html
@@ -0,0 +1,2279 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript</title>

+		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

+		<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->

+		<meta http-equiv="X-UA-Compatible" content="IE=7" />

+		<script type="text/javascript">var isIe = false, isIePre7 = false;</script>

+		<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->

+		<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->

+		<script type="text/javascript">

+			//<![CDATA[

+			var loggingEnabled = true;

+			var logQueuedEventsTimer = null;

+			var logEntries = [];

+			var logEntriesAndSeparators = [];

+			var logItems = [];

+			var renderDelay = 100;

+			var unrenderedLogItemsExist = false;

+			var rootGroup, currentGroup = null;

+			var loaded = false;

+			var currentLogItem = null;

+			var logMainContainer;

+

+			function copyProperties(obj, props) {

+				for (var i in props) {

+					obj[i] = props[i];

+				}

+			}

+

+			/*----------------------------------------------------------------*/

+

+			function LogItem() {

+			}

+

+			LogItem.prototype = {

+				mainContainer: null,

+				wrappedContainer: null,

+				unwrappedContainer: null,

+				group: null,

+

+				appendToLog: function() {

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].appendToLog();

+					}

+					this.group.update();

+				},

+

+				doRemove: function(doUpdate, removeFromGroup) {

+					if (this.rendered) {

+						for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+							this.elementContainers[i].remove();

+						}

+						this.unwrappedElementContainer = null;

+						this.wrappedElementContainer = null;

+						this.mainElementContainer = null;

+					}

+					if (this.group && removeFromGroup) {

+						this.group.removeChild(this, doUpdate);

+					}

+					if (this === currentLogItem) {

+						currentLogItem = null;

+					}

+				},

+

+				remove: function(doUpdate, removeFromGroup) {

+					this.doRemove(doUpdate, removeFromGroup);

+				},

+

+				render: function() {},

+

+				accept: function(visitor) {

+					visitor.visit(this);

+				},

+

+				getUnwrappedDomContainer: function() {

+					return this.group.unwrappedElementContainer.contentDiv;

+				},

+

+				getWrappedDomContainer: function() {

+					return this.group.wrappedElementContainer.contentDiv;

+				},

+

+				getMainDomContainer: function() {

+					return this.group.mainElementContainer.contentDiv;

+				}

+			};

+

+			LogItem.serializedItemKeys = {LOG_ENTRY: 0, GROUP_START: 1, GROUP_END: 2};

+

+			/*----------------------------------------------------------------*/

+

+			function LogItemContainerElement() {

+			}

+

+			LogItemContainerElement.prototype = {

+				appendToLog: function() {

+					var insertBeforeFirst = (newestAtTop && this.containerDomNode.hasChildNodes());

+					if (insertBeforeFirst) {

+						this.containerDomNode.insertBefore(this.mainDiv, this.containerDomNode.firstChild);

+					} else {

+						this.containerDomNode.appendChild(this.mainDiv);

+					}

+				}

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function SeparatorElementContainer(containerDomNode) {

+				this.containerDomNode = containerDomNode;

+				this.mainDiv = document.createElement("div");

+				this.mainDiv.className = "separator";

+				this.mainDiv.innerHTML = "&nbsp;";

+			}

+

+			SeparatorElementContainer.prototype = new LogItemContainerElement();

+

+			SeparatorElementContainer.prototype.remove = function() {

+				this.mainDiv.parentNode.removeChild(this.mainDiv);

+				this.mainDiv = null;

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function Separator() {

+				this.rendered = false;

+			}

+

+			Separator.prototype = new LogItem();

+

+			copyProperties(Separator.prototype, {

+				render: function() {

+					var containerDomNode = this.group.contentDiv;

+					if (isIe) {

+						this.unwrappedElementContainer = new SeparatorElementContainer(this.getUnwrappedDomContainer());

+						this.wrappedElementContainer = new SeparatorElementContainer(this.getWrappedDomContainer());

+						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];

+					} else {

+						this.mainElementContainer = new SeparatorElementContainer(this.getMainDomContainer());

+						this.elementContainers = [this.mainElementContainer];

+					}

+					this.content = this.formattedMessage;

+					this.rendered = true;

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function GroupElementContainer(group, containerDomNode, isRoot, isWrapped) {

+				this.group = group;

+				this.containerDomNode = containerDomNode;

+				this.isRoot = isRoot;

+				this.isWrapped = isWrapped;

+				this.expandable = false;

+

+				if (this.isRoot) {

+					if (isIe) {

+						this.contentDiv = logMainContainer.appendChild(document.createElement("div"));

+						this.contentDiv.id = this.isWrapped ? "log_wrapped" : "log_unwrapped";

+					} else {

+						this.contentDiv = logMainContainer;

+					}

+				} else {

+					var groupElementContainer = this;

+					

+					this.mainDiv = document.createElement("div");

+					this.mainDiv.className = "group";

+

+					this.headingDiv = this.mainDiv.appendChild(document.createElement("div"));

+					this.headingDiv.className = "groupheading";

+

+					this.expander = this.headingDiv.appendChild(document.createElement("span"));

+					this.expander.className = "expander unselectable greyedout";

+					this.expander.unselectable = true;

+					var expanderText = this.group.expanded ? "-" : "+";

+					this.expanderTextNode = this.expander.appendChild(document.createTextNode(expanderText));

+					

+					this.headingDiv.appendChild(document.createTextNode(" " + this.group.name));

+

+					this.contentDiv = this.mainDiv.appendChild(document.createElement("div"));

+					var contentCssClass = this.group.expanded ? "expanded" : "collapsed";

+					this.contentDiv.className = "groupcontent " + contentCssClass;

+

+					this.expander.onclick = function() {

+						if (groupElementContainer.group.expandable) {

+							groupElementContainer.group.toggleExpanded();

+						}

+					};

+				}

+			}

+

+			GroupElementContainer.prototype = new LogItemContainerElement();

+

+			copyProperties(GroupElementContainer.prototype, {

+				toggleExpanded: function() {

+					if (!this.isRoot) {

+						var oldCssClass, newCssClass, expanderText;

+						if (this.group.expanded) {

+							newCssClass = "expanded";

+							oldCssClass = "collapsed";

+							expanderText = "-";

+						} else {

+							newCssClass = "collapsed";

+							oldCssClass = "expanded";

+							expanderText = "+";

+						}

+						replaceClass(this.contentDiv, newCssClass, oldCssClass);

+						this.expanderTextNode.nodeValue = expanderText;

+					}

+				},

+

+				remove: function() {

+					if (!this.isRoot) {

+						this.headingDiv = null;

+						this.expander.onclick = null;

+						this.expander = null;

+						this.expanderTextNode = null;

+						this.contentDiv = null;

+						this.containerDomNode = null;

+						this.mainDiv.parentNode.removeChild(this.mainDiv);

+						this.mainDiv = null;

+					}

+				},

+

+				reverseChildren: function() {

+					// Invert the order of the log entries

+					var node = null;

+

+					// Remove all the log container nodes

+					var childDomNodes = [];

+					while ((node = this.contentDiv.firstChild)) {

+						this.contentDiv.removeChild(node);

+						childDomNodes.push(node);

+					}

+

+					// Put them all back in reverse order

+					while ((node = childDomNodes.pop())) {

+						this.contentDiv.appendChild(node);

+					}

+				},

+

+				update: function() {

+					if (!this.isRoot) {

+						if (this.group.expandable) {

+							removeClass(this.expander, "greyedout");

+						} else {

+							addClass(this.expander, "greyedout");

+						}

+					}

+				},

+

+				clear: function() {

+					if (this.isRoot) {

+						this.contentDiv.innerHTML = "";

+					}

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function Group(name, isRoot, initiallyExpanded) {

+				this.name = name;

+				this.group = null;

+				this.isRoot = isRoot;

+				this.initiallyExpanded = initiallyExpanded;

+				this.elementContainers = [];

+				this.children = [];

+				this.expanded = initiallyExpanded;

+				this.rendered = false;

+				this.expandable = false;

+			}

+

+			Group.prototype = new LogItem();

+

+			copyProperties(Group.prototype, {

+				addChild: function(logItem) {

+					this.children.push(logItem);

+					logItem.group = this;

+				},

+

+				render: function() {

+					if (isIe) {

+						var unwrappedDomContainer, wrappedDomContainer;

+						if (this.isRoot) {

+							unwrappedDomContainer = logMainContainer;

+							wrappedDomContainer = logMainContainer;

+						} else {

+							unwrappedDomContainer = this.getUnwrappedDomContainer();

+							wrappedDomContainer = this.getWrappedDomContainer();

+						}

+						this.unwrappedElementContainer = new GroupElementContainer(this, unwrappedDomContainer, this.isRoot, false);

+						this.wrappedElementContainer = new GroupElementContainer(this, wrappedDomContainer, this.isRoot, true);

+						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];

+					} else {

+						var mainDomContainer = this.isRoot ? logMainContainer : this.getMainDomContainer();

+						this.mainElementContainer = new GroupElementContainer(this, mainDomContainer, this.isRoot, false);

+						this.elementContainers = [this.mainElementContainer];

+					}

+					this.rendered = true;

+				},

+

+				toggleExpanded: function() {

+					this.expanded = !this.expanded;

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].toggleExpanded();

+					}

+				},

+

+				expand: function() {

+					if (!this.expanded) {

+						this.toggleExpanded();

+					}

+				},

+

+				accept: function(visitor) {

+					visitor.visitGroup(this);

+				},

+

+				reverseChildren: function() {

+					if (this.rendered) {

+						for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+							this.elementContainers[i].reverseChildren();

+						}

+					}

+				},

+

+				update: function() {

+					var previouslyExpandable = this.expandable;

+					this.expandable = (this.children.length !== 0);

+					if (this.expandable !== previouslyExpandable) {

+						for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+							this.elementContainers[i].update();

+						}

+					}

+				},

+

+				flatten: function() {

+					var visitor = new GroupFlattener();

+					this.accept(visitor);

+					return visitor.logEntriesAndSeparators;

+				},

+

+				removeChild: function(child, doUpdate) {

+					array_remove(this.children, child);

+					child.group = null;

+					if (doUpdate) {

+						this.update();

+					}

+				},

+

+				remove: function(doUpdate, removeFromGroup) {

+					for (var i = 0, len = this.children.length; i < len; i++) {

+						this.children[i].remove(false, false);

+					}

+					this.children = [];

+					this.update();

+					if (this === currentGroup) {

+						currentGroup = this.group;

+					}

+					this.doRemove(doUpdate, removeFromGroup);

+				},

+

+				serialize: function(items) {

+					items.push([LogItem.serializedItemKeys.GROUP_START, this.name]);

+					for (var i = 0, len = this.children.length; i < len; i++) {

+						this.children[i].serialize(items);

+					}

+					if (this !== currentGroup) {

+						items.push([LogItem.serializedItemKeys.GROUP_END]);

+					}

+				},

+

+				clear: function() {

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].clear();

+					}

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntryElementContainer() {

+			}

+

+			LogEntryElementContainer.prototype = new LogItemContainerElement();

+

+			copyProperties(LogEntryElementContainer.prototype, {

+				remove: function() {

+					this.doRemove();

+				},

+

+				doRemove: function() {

+					this.mainDiv.parentNode.removeChild(this.mainDiv);

+					this.mainDiv = null;

+					this.contentElement = null;

+					this.containerDomNode = null;

+				},

+

+				setContent: function(content, wrappedContent) {

+					if (content === this.formattedMessage) {

+						this.contentElement.innerHTML = "";

+						this.contentElement.appendChild(document.createTextNode(this.formattedMessage));

+					} else {

+						this.contentElement.innerHTML = content;

+					}

+				},

+

+				setSearchMatch: function(isMatch) {

+					var oldCssClass = isMatch ? "searchnonmatch" : "searchmatch";

+					var newCssClass = isMatch ? "searchmatch" : "searchnonmatch";

+					replaceClass(this.mainDiv, newCssClass, oldCssClass);

+				},

+

+				clearSearch: function() {

+					removeClass(this.mainDiv, "searchmatch");

+					removeClass(this.mainDiv, "searchnonmatch");

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntryWrappedElementContainer(logEntry, containerDomNode) {

+				this.logEntry = logEntry;

+				this.containerDomNode = containerDomNode;

+				this.mainDiv = document.createElement("div");

+				this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));

+				this.mainDiv.className = "logentry wrapped " + this.logEntry.level;

+				this.contentElement = this.mainDiv;

+			}

+

+			LogEntryWrappedElementContainer.prototype = new LogEntryElementContainer();

+

+			LogEntryWrappedElementContainer.prototype.setContent = function(content, wrappedContent) {

+				if (content === this.formattedMessage) {

+					this.contentElement.innerHTML = "";

+					this.contentElement.appendChild(document.createTextNode(this.formattedMessage));

+				} else {

+					this.contentElement.innerHTML = wrappedContent;

+				}

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntryUnwrappedElementContainer(logEntry, containerDomNode) {

+				this.logEntry = logEntry;

+				this.containerDomNode = containerDomNode;

+				this.mainDiv = document.createElement("div");

+				this.mainDiv.className = "logentry unwrapped " + this.logEntry.level;

+				this.pre = this.mainDiv.appendChild(document.createElement("pre"));

+				this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));

+				this.pre.className = "unwrapped";

+				this.contentElement = this.pre;

+			}

+

+			LogEntryUnwrappedElementContainer.prototype = new LogEntryElementContainer();

+

+			LogEntryUnwrappedElementContainer.prototype.remove = function() {

+				this.doRemove();

+				this.pre = null;

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntryMainElementContainer(logEntry, containerDomNode) {

+				this.logEntry = logEntry;

+				this.containerDomNode = containerDomNode;

+				this.mainDiv = document.createElement("div");

+				this.mainDiv.className = "logentry nonielogentry " + this.logEntry.level;

+				this.contentElement = this.mainDiv.appendChild(document.createElement("span"));

+				this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));

+			}

+

+			LogEntryMainElementContainer.prototype = new LogEntryElementContainer();

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntry(level, formattedMessage) {

+				this.level = level;

+				this.formattedMessage = formattedMessage;

+				this.rendered = false;

+			}

+

+			LogEntry.prototype = new LogItem();

+

+			copyProperties(LogEntry.prototype, {

+				render: function() {

+					var logEntry = this;

+					var containerDomNode = this.group.contentDiv;

+

+					// Support for the CSS attribute white-space in IE for Windows is

+					// non-existent pre version 6 and slightly odd in 6, so instead

+					// use two different HTML elements

+					if (isIe) {

+						this.formattedMessage = this.formattedMessage.replace(/\r\n/g, "\r"); // Workaround for IE's treatment of white space

+						this.unwrappedElementContainer = new LogEntryUnwrappedElementContainer(this, this.getUnwrappedDomContainer());

+						this.wrappedElementContainer = new LogEntryWrappedElementContainer(this, this.getWrappedDomContainer());

+						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];

+					} else {

+						this.mainElementContainer = new LogEntryMainElementContainer(this, this.getMainDomContainer());

+						this.elementContainers = [this.mainElementContainer];

+					}

+					this.content = this.formattedMessage;

+					this.rendered = true;

+				},

+

+				setContent: function(content, wrappedContent) {

+					if (content != this.content) {

+						if (isIe && (content !== this.formattedMessage)) {

+							content = content.replace(/\r\n/g, "\r"); // Workaround for IE's treatment of white space

+						}

+						for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+							this.elementContainers[i].setContent(content, wrappedContent);

+						}

+						this.content = content;

+					}

+				},

+

+				getSearchMatches: function() {

+					var matches = [];

+					var i, len;

+					if (isIe) {

+						var unwrappedEls = getElementsByClass(this.unwrappedElementContainer.mainDiv, "searchterm", "span");

+						var wrappedEls = getElementsByClass(this.wrappedElementContainer.mainDiv, "searchterm", "span");

+						for (i = 0, len = unwrappedEls.length; i < len; i++) {

+							matches[i] = new Match(this.level, null, unwrappedEls[i], wrappedEls[i]);

+						}

+					} else {

+						var els = getElementsByClass(this.mainElementContainer.mainDiv, "searchterm", "span");

+						for (i = 0, len = els.length; i < len; i++) {

+							matches[i] = new Match(this.level, els[i]);

+						}

+					}

+					return matches;

+				},

+

+				setSearchMatch: function(isMatch) {

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].setSearchMatch(isMatch);

+					}

+				},

+

+				clearSearch: function() {

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].clearSearch();

+					}

+				},

+

+				accept: function(visitor) {

+					visitor.visitLogEntry(this);

+				},

+

+				serialize: function(items) {

+					items.push([LogItem.serializedItemKeys.LOG_ENTRY, this.level, this.formattedMessage]);

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function LogItemVisitor() {

+			}

+

+			LogItemVisitor.prototype = {

+				visit: function(logItem) {

+				},

+

+				visitParent: function(logItem) {

+					if (logItem.group) {

+						logItem.group.accept(this);

+					}

+				},

+

+				visitChildren: function(logItem) {

+					for (var i = 0, len = logItem.children.length; i < len; i++) {

+						logItem.children[i].accept(this);

+					}

+				},

+

+				visitLogEntry: function(logEntry) {

+					this.visit(logEntry);

+				},

+

+				visitSeparator: function(separator) {

+					this.visit(separator);

+				},

+

+				visitGroup: function(group) {

+					this.visit(group);

+				}

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function GroupFlattener() {

+				this.logEntriesAndSeparators = [];

+			}

+

+			GroupFlattener.prototype = new LogItemVisitor();

+

+			GroupFlattener.prototype.visitGroup = function(group) {

+				this.visitChildren(group);

+			};

+

+			GroupFlattener.prototype.visitLogEntry = function(logEntry) {

+				this.logEntriesAndSeparators.push(logEntry);

+			};

+

+			GroupFlattener.prototype.visitSeparator = function(separator) {

+				this.logEntriesAndSeparators.push(separator);

+			};

+

+			/*----------------------------------------------------------------*/

+

+			window.onload = function() {

+				// Sort out document.domain

+				if (location.search) {

+					var queryBits = unescape(location.search).substr(1).split("&"), nameValueBits;

+					for (var i = 0, len = queryBits.length; i < len; i++) {

+						nameValueBits = queryBits[i].split("=");

+						if (nameValueBits[0] == "log4javascript_domain") {

+							document.domain = nameValueBits[1];

+							break;

+						}

+					}

+				}

+

+				// Create DOM objects

+				logMainContainer = $("log");

+				if (isIePre7) {

+					addClass(logMainContainer, "oldIe");

+				}

+

+				rootGroup = new Group("root", true);

+				rootGroup.render();

+				currentGroup = rootGroup;

+				

+				setCommandInputWidth();

+				setLogContainerHeight();

+				toggleLoggingEnabled();

+				toggleSearchEnabled();

+				toggleSearchFilter();

+				toggleSearchHighlight();

+				applyFilters();

+				checkAllLevels();

+				toggleWrap();

+				toggleNewestAtTop();

+				toggleScrollToLatest();

+				renderQueuedLogItems();

+				loaded = true;

+				$("command").value = "";

+				$("command").autocomplete = "off";

+				$("command").onkeydown = function(evt) {

+					evt = getEvent(evt);

+					if (evt.keyCode == 10 || evt.keyCode == 13) { // Return/Enter

+						evalCommandLine();

+						stopPropagation(evt);

+					} else if (evt.keyCode == 27) { // Escape

+						this.value = "";

+						this.focus();

+					} else if (evt.keyCode == 38 && commandHistory.length > 0) { // Up

+						currentCommandIndex = Math.max(0, currentCommandIndex - 1);

+						this.value = commandHistory[currentCommandIndex];

+						moveCaretToEnd(this);

+					} else if (evt.keyCode == 40 && commandHistory.length > 0) { // Down

+						currentCommandIndex = Math.min(commandHistory.length - 1, currentCommandIndex + 1);

+						this.value = commandHistory[currentCommandIndex];

+						moveCaretToEnd(this);

+					}

+				};

+

+				// Prevent the keypress moving the caret in Firefox

+				$("command").onkeypress = function(evt) {

+					evt = getEvent(evt);

+					if (evt.keyCode == 38 && commandHistory.length > 0 && evt.preventDefault) { // Up

+						evt.preventDefault();

+					}

+				};

+

+				// Prevent the keyup event blurring the input in Opera

+				$("command").onkeyup = function(evt) {

+					evt = getEvent(evt);

+					if (evt.keyCode == 27 && evt.preventDefault) { // Up

+						evt.preventDefault();

+						this.focus();

+					}

+				};

+

+				// Add document keyboard shortcuts

+				document.onkeydown = function keyEventHandler(evt) {

+					evt = getEvent(evt);

+					switch (evt.keyCode) {

+						case 69: // Ctrl + shift + E: re-execute last command

+							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {

+								evalLastCommand();

+								cancelKeyEvent(evt);

+								return false;

+							}

+							break;

+						case 75: // Ctrl + shift + K: focus search

+							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {

+								focusSearch();

+								cancelKeyEvent(evt);

+								return false;

+							}

+							break;

+						case 40: // Ctrl + shift + down arrow: focus command line

+						case 76: // Ctrl + shift + L: focus command line

+							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {

+								focusCommandLine();

+								cancelKeyEvent(evt);

+								return false;

+							}

+							break;

+					}

+				};

+

+				// Workaround to make sure log div starts at the correct size

+				setTimeout(setLogContainerHeight, 20);

+

+				setShowCommandLine(showCommandLine);

+				doSearch();

+			};

+

+			window.onunload = function() {

+				if (mainWindowExists()) {

+					appender.unload();

+				}

+				appender = null;

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function toggleLoggingEnabled() {

+				setLoggingEnabled($("enableLogging").checked);

+			}

+

+			function setLoggingEnabled(enable) {

+				loggingEnabled = enable;

+			}

+

+			var appender = null;

+

+			function setAppender(appenderParam) {

+				appender = appenderParam;

+			}

+

+			function setShowCloseButton(showCloseButton) {

+				$("closeButton").style.display = showCloseButton ? "inline" : "none";

+			}

+

+			function setShowHideButton(showHideButton) {

+				$("hideButton").style.display = showHideButton ? "inline" : "none";

+			}

+

+			var newestAtTop = false;

+

+			/*----------------------------------------------------------------*/

+

+			function LogItemContentReverser() {

+			}

+			

+			LogItemContentReverser.prototype = new LogItemVisitor();

+			

+			LogItemContentReverser.prototype.visitGroup = function(group) {

+				group.reverseChildren();

+				this.visitChildren(group);

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function setNewestAtTop(isNewestAtTop) {

+				var oldNewestAtTop = newestAtTop;

+				var i, iLen, j, jLen;

+				newestAtTop = Boolean(isNewestAtTop);

+				if (oldNewestAtTop != newestAtTop) {

+					var visitor = new LogItemContentReverser();

+					rootGroup.accept(visitor);

+

+					// Reassemble the matches array

+					if (currentSearch) {

+						var currentMatch = currentSearch.matches[currentMatchIndex];

+						var matchIndex = 0;

+						var matches = [];

+						var actOnLogEntry = function(logEntry) {

+							var logEntryMatches = logEntry.getSearchMatches();

+							for (j = 0, jLen = logEntryMatches.length; j < jLen; j++) {

+								matches[matchIndex] = logEntryMatches[j];

+								if (currentMatch && logEntryMatches[j].equals(currentMatch)) {

+									currentMatchIndex = matchIndex;

+								}

+								matchIndex++;

+							}

+						};

+						if (newestAtTop) {

+							for (i = logEntries.length - 1; i >= 0; i--) {

+								actOnLogEntry(logEntries[i]);

+							}

+						} else {

+							for (i = 0, iLen = logEntries.length; i < iLen; i++) {

+								actOnLogEntry(logEntries[i]);

+							}

+						}

+						currentSearch.matches = matches;

+						if (currentMatch) {

+							currentMatch.setCurrent();

+						}

+					} else if (scrollToLatest) {

+						doScrollToLatest();

+					}

+				}

+				$("newestAtTop").checked = isNewestAtTop;

+			}

+

+			function toggleNewestAtTop() {

+				var isNewestAtTop = $("newestAtTop").checked;

+				setNewestAtTop(isNewestAtTop);

+			}

+

+			var scrollToLatest = true;

+

+			function setScrollToLatest(isScrollToLatest) {

+				scrollToLatest = isScrollToLatest;

+				if (scrollToLatest) {

+					doScrollToLatest();

+				}

+				$("scrollToLatest").checked = isScrollToLatest;

+			}

+

+			function toggleScrollToLatest() {

+				var isScrollToLatest = $("scrollToLatest").checked;

+				setScrollToLatest(isScrollToLatest);

+			}

+

+			function doScrollToLatest() {

+				var l = logMainContainer;

+				if (typeof l.scrollTop != "undefined") {

+					if (newestAtTop) {

+						l.scrollTop = 0;

+					} else {

+						var latestLogEntry = l.lastChild;

+						if (latestLogEntry) {

+							l.scrollTop = l.scrollHeight;

+						}

+					}

+				}

+			}

+

+			var closeIfOpenerCloses = true;

+

+			function setCloseIfOpenerCloses(isCloseIfOpenerCloses) {

+				closeIfOpenerCloses = isCloseIfOpenerCloses;

+			}

+

+			var maxMessages = null;

+

+			function setMaxMessages(max) {

+				maxMessages = max;

+				pruneLogEntries();

+			}

+

+			var showCommandLine = false;

+

+			function setShowCommandLine(isShowCommandLine) {

+				showCommandLine = isShowCommandLine;

+				if (loaded) {

+					$("commandLine").style.display = showCommandLine ? "block" : "none";

+					setCommandInputWidth();

+					setLogContainerHeight();

+				}

+			}

+

+			function focusCommandLine() {

+				if (loaded) {

+					$("command").focus();

+				}

+			}

+

+			function focusSearch() {

+				if (loaded) {

+					$("searchBox").focus();

+				}

+			}

+

+			function getLogItems() {

+				var items = [];

+				for (var i = 0, len = logItems.length; i < len; i++) {

+					logItems[i].serialize(items);

+				}

+				return items;

+			}

+

+			function setLogItems(items) {

+				var loggingReallyEnabled = loggingEnabled;

+				// Temporarily turn logging on

+				loggingEnabled = true;

+				for (var i = 0, len = items.length; i < len; i++) {

+					switch (items[i][0]) {

+						case LogItem.serializedItemKeys.LOG_ENTRY:

+							log(items[i][1], items[i][2]);

+							break;

+						case LogItem.serializedItemKeys.GROUP_START:

+							group(items[i][1]);

+							break;

+						case LogItem.serializedItemKeys.GROUP_END:

+							groupEnd();

+							break;

+					}

+				}

+				loggingEnabled = loggingReallyEnabled;

+			}

+

+			function log(logLevel, formattedMessage) {

+				if (loggingEnabled) {

+					var logEntry = new LogEntry(logLevel, formattedMessage);

+					logEntries.push(logEntry);

+					logEntriesAndSeparators.push(logEntry);

+					logItems.push(logEntry);

+					currentGroup.addChild(logEntry);

+					if (loaded) {

+						if (logQueuedEventsTimer !== null) {

+							clearTimeout(logQueuedEventsTimer);

+						}

+						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);

+						unrenderedLogItemsExist = true;

+					}

+				}

+			}

+

+			function renderQueuedLogItems() {

+				logQueuedEventsTimer = null;

+				var pruned = pruneLogEntries();

+

+				// Render any unrendered log entries and apply the current search to them

+				var initiallyHasMatches = currentSearch ? currentSearch.hasMatches() : false;

+				for (var i = 0, len = logItems.length; i < len; i++) {

+					if (!logItems[i].rendered) {

+						logItems[i].render();

+						logItems[i].appendToLog();

+						if (currentSearch && (logItems[i] instanceof LogEntry)) {

+							currentSearch.applyTo(logItems[i]);

+						}

+					}

+				}

+				if (currentSearch) {

+					if (pruned) {

+						if (currentSearch.hasVisibleMatches()) {

+							if (currentMatchIndex === null) {

+								setCurrentMatchIndex(0);

+							}

+							displayMatches();

+						} else {

+							displayNoMatches();

+						}

+					} else if (!initiallyHasMatches && currentSearch.hasVisibleMatches()) {

+						setCurrentMatchIndex(0);

+						displayMatches();

+					}

+				}

+				if (scrollToLatest) {

+					doScrollToLatest();

+				}

+				unrenderedLogItemsExist = false;

+			}

+

+			function pruneLogEntries() {

+				if ((maxMessages !== null) && (logEntriesAndSeparators.length > maxMessages)) {

+					var numberToDelete = logEntriesAndSeparators.length - maxMessages;

+					var prunedLogEntries = logEntriesAndSeparators.slice(0, numberToDelete);

+					if (currentSearch) {

+						currentSearch.removeMatches(prunedLogEntries);

+					}

+					var group;

+					for (var i = 0; i < numberToDelete; i++) {

+						group = logEntriesAndSeparators[i].group;

+						array_remove(logItems, logEntriesAndSeparators[i]);

+						array_remove(logEntries, logEntriesAndSeparators[i]);

+						logEntriesAndSeparators[i].remove(true, true);

+						if (group.children.length === 0 && group !== currentGroup && group !== rootGroup) {

+							array_remove(logItems, group);

+							group.remove(true, true);

+						}

+					}

+					logEntriesAndSeparators = array_removeFromStart(logEntriesAndSeparators, numberToDelete);

+					return true;

+				}

+				return false;

+			}

+

+			function group(name, startExpanded) {

+				if (loggingEnabled) {

+					initiallyExpanded = (typeof startExpanded === "undefined") ? true : Boolean(startExpanded);

+					var newGroup = new Group(name, false, initiallyExpanded);

+					currentGroup.addChild(newGroup);

+					currentGroup = newGroup;

+					logItems.push(newGroup);

+					if (loaded) {

+						if (logQueuedEventsTimer !== null) {

+							clearTimeout(logQueuedEventsTimer);

+						}

+						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);

+						unrenderedLogItemsExist = true;

+					}

+				}

+			}

+

+			function groupEnd() {

+				currentGroup = (currentGroup === rootGroup) ? rootGroup : currentGroup.group;

+			}

+

+			function mainPageReloaded() {

+				currentGroup = rootGroup;

+				var separator = new Separator();

+				logEntriesAndSeparators.push(separator);

+				logItems.push(separator);

+				currentGroup.addChild(separator);

+			}

+

+			function closeWindow() {

+				if (appender && mainWindowExists()) {

+					appender.close(true);

+				} else {

+					window.close();

+				}

+			}

+

+			function hide() {

+				if (appender && mainWindowExists()) {

+					appender.hide();

+				}

+			}

+

+			var mainWindow = window;

+			var windowId = "log4javascriptConsoleWindow_" + new Date().getTime() + "_" + ("" + Math.random()).substr(2);

+

+			function setMainWindow(win) {

+				mainWindow = win;

+				mainWindow[windowId] = window;

+				// If this is a pop-up, poll the opener to see if it's closed

+				if (opener && closeIfOpenerCloses) {

+					pollOpener();

+				}

+			}

+

+			function pollOpener() {

+				if (closeIfOpenerCloses) {

+					if (mainWindowExists()) {

+						setTimeout(pollOpener, 500);

+					} else {

+						closeWindow();

+					}

+				}

+			}

+

+			function mainWindowExists() {

+				try {

+					return (mainWindow && !mainWindow.closed &&

+						mainWindow[windowId] == window);

+				} catch (ex) {}

+				return false;

+			}

+

+			var logLevels = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"];

+

+			function getCheckBox(logLevel) {

+				return $("switch_" + logLevel);

+			}

+

+			function getIeWrappedLogContainer() {

+				return $("log_wrapped");

+			}

+

+			function getIeUnwrappedLogContainer() {

+				return $("log_unwrapped");

+			}

+

+			function applyFilters() {

+				for (var i = 0; i < logLevels.length; i++) {

+					if (getCheckBox(logLevels[i]).checked) {

+						addClass(logMainContainer, logLevels[i]);

+					} else {

+						removeClass(logMainContainer, logLevels[i]);

+					}

+				}

+				updateSearchFromFilters();

+			}

+

+			function toggleAllLevels() {

+				var turnOn = $("switch_ALL").checked;

+				for (var i = 0; i < logLevels.length; i++) {

+					getCheckBox(logLevels[i]).checked = turnOn;

+					if (turnOn) {

+						addClass(logMainContainer, logLevels[i]);

+					} else {

+						removeClass(logMainContainer, logLevels[i]);

+					}

+				}

+			}

+

+			function checkAllLevels() {

+				for (var i = 0; i < logLevels.length; i++) {

+					if (!getCheckBox(logLevels[i]).checked) {

+						getCheckBox("ALL").checked = false;

+						return;

+					}

+				}

+				getCheckBox("ALL").checked = true;

+			}

+

+			function clearLog() {

+				rootGroup.clear();

+				currentGroup = rootGroup;

+				logEntries = [];

+				logItems = [];

+				logEntriesAndSeparators = [];

+ 				doSearch();

+			}

+

+			function toggleWrap() {

+				var enable = $("wrap").checked;

+				if (enable) {

+					addClass(logMainContainer, "wrap");

+				} else {

+					removeClass(logMainContainer, "wrap");

+				}

+				refreshCurrentMatch();

+			}

+

+			/* ------------------------------------------------------------------- */

+

+			// Search

+

+			var searchTimer = null;

+

+			function scheduleSearch() {

+				try {

+					clearTimeout(searchTimer);

+				} catch (ex) {

+					// Do nothing

+				}

+				searchTimer = setTimeout(doSearch, 500);

+			}

+

+			function Search(searchTerm, isRegex, searchRegex, isCaseSensitive) {

+				this.searchTerm = searchTerm;

+				this.isRegex = isRegex;

+				this.searchRegex = searchRegex;

+				this.isCaseSensitive = isCaseSensitive;

+				this.matches = [];

+			}

+

+			Search.prototype = {

+				hasMatches: function() {

+					return this.matches.length > 0;

+				},

+

+				hasVisibleMatches: function() {

+					if (this.hasMatches()) {

+						for (var i = 0; i < this.matches.length; i++) {

+							if (this.matches[i].isVisible()) {

+								return true;

+							}

+						}

+					}

+					return false;

+				},

+

+				match: function(logEntry) {

+					var entryText = String(logEntry.formattedMessage);

+					var matchesSearch = false;

+					if (this.isRegex) {

+						matchesSearch = this.searchRegex.test(entryText);

+					} else if (this.isCaseSensitive) {

+						matchesSearch = (entryText.indexOf(this.searchTerm) > -1);

+					} else {

+						matchesSearch = (entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1);

+					}

+					return matchesSearch;

+				},

+

+				getNextVisibleMatchIndex: function() {

+					for (var i = currentMatchIndex + 1; i < this.matches.length; i++) {

+						if (this.matches[i].isVisible()) {

+							return i;

+						}

+					}

+					// Start again from the first match

+					for (i = 0; i <= currentMatchIndex; i++) {

+						if (this.matches[i].isVisible()) {

+							return i;

+						}

+					}

+					return -1;

+				},

+

+				getPreviousVisibleMatchIndex: function() {

+					for (var i = currentMatchIndex - 1; i >= 0; i--) {

+						if (this.matches[i].isVisible()) {

+							return i;

+						}

+					}

+					// Start again from the last match

+					for (var i = this.matches.length - 1; i >= currentMatchIndex; i--) {

+						if (this.matches[i].isVisible()) {

+							return i;

+						}

+					}

+					return -1;

+				},

+

+				applyTo: function(logEntry) {

+					var doesMatch = this.match(logEntry);

+					if (doesMatch) {

+						logEntry.group.expand();

+						logEntry.setSearchMatch(true);

+						var logEntryContent;

+						var wrappedLogEntryContent;

+						var searchTermReplacementStartTag = "<span class=\"searchterm\">";

+						var searchTermReplacementEndTag = "<" + "/span>";

+						var preTagName = isIe ? "pre" : "span";

+						var preStartTag = "<" + preTagName + " class=\"pre\">";

+						var preEndTag = "<" + "/" + preTagName + ">";

+						var startIndex = 0;

+						var searchIndex, matchedText, textBeforeMatch;

+						if (this.isRegex) {

+							var flags = this.isCaseSensitive ? "g" : "gi";

+							var capturingRegex = new RegExp("(" + this.searchRegex.source + ")", flags);

+

+							// Replace the search term with temporary tokens for the start and end tags

+							var rnd = ("" + Math.random()).substr(2);

+							var startToken = "%%s" + rnd + "%%";

+							var endToken = "%%e" + rnd + "%%";

+							logEntryContent = logEntry.formattedMessage.replace(capturingRegex, startToken + "$1" + endToken);

+

+							// Escape the HTML to get rid of angle brackets

+							logEntryContent = escapeHtml(logEntryContent);

+

+							// Substitute the proper HTML back in for the search match

+							var result;

+							var searchString = logEntryContent;

+							logEntryContent = "";

+							wrappedLogEntryContent = "";

+							while ((searchIndex = searchString.indexOf(startToken, startIndex)) > -1) {

+								var endTokenIndex = searchString.indexOf(endToken, searchIndex);

+								matchedText = searchString.substring(searchIndex + startToken.length, endTokenIndex);

+								textBeforeMatch = searchString.substring(startIndex, searchIndex);

+								logEntryContent += preStartTag + textBeforeMatch + preEndTag;

+								logEntryContent += searchTermReplacementStartTag + preStartTag + matchedText +

+									preEndTag + searchTermReplacementEndTag;

+								if (isIe) {

+									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +

+										matchedText + searchTermReplacementEndTag;

+								}

+								startIndex = endTokenIndex + endToken.length;

+							}

+							logEntryContent += preStartTag + searchString.substr(startIndex) + preEndTag;

+							if (isIe) {

+								wrappedLogEntryContent += searchString.substr(startIndex);

+							}

+						} else {

+							logEntryContent = "";

+							wrappedLogEntryContent = "";

+							var searchTermReplacementLength = searchTermReplacementStartTag.length +

+								this.searchTerm.length + searchTermReplacementEndTag.length;

+							var searchTermLength = this.searchTerm.length;

+							var searchTermLowerCase = this.searchTerm.toLowerCase();

+							var logTextLowerCase = logEntry.formattedMessage.toLowerCase();

+							while ((searchIndex = logTextLowerCase.indexOf(searchTermLowerCase, startIndex)) > -1) {

+								matchedText = escapeHtml(logEntry.formattedMessage.substr(searchIndex, this.searchTerm.length));

+								textBeforeMatch = escapeHtml(logEntry.formattedMessage.substring(startIndex, searchIndex));

+								var searchTermReplacement = searchTermReplacementStartTag +

+									preStartTag + matchedText + preEndTag + searchTermReplacementEndTag;

+								logEntryContent += preStartTag + textBeforeMatch + preEndTag + searchTermReplacement;

+								if (isIe) {

+									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +

+										matchedText + searchTermReplacementEndTag;

+								}

+								startIndex = searchIndex + searchTermLength;

+							}

+							var textAfterLastMatch = escapeHtml(logEntry.formattedMessage.substr(startIndex));

+							logEntryContent += preStartTag + textAfterLastMatch + preEndTag;

+							if (isIe) {

+								wrappedLogEntryContent += textAfterLastMatch;

+							}

+						}

+						logEntry.setContent(logEntryContent, wrappedLogEntryContent);

+						var logEntryMatches = logEntry.getSearchMatches();

+						this.matches = this.matches.concat(logEntryMatches);

+					} else {

+						logEntry.setSearchMatch(false);

+						logEntry.setContent(logEntry.formattedMessage, logEntry.formattedMessage);

+					}

+					return doesMatch;

+				},

+

+				removeMatches: function(logEntries) {

+					var matchesToRemoveCount = 0;

+					var currentMatchRemoved = false;

+					var matchesToRemove = [];

+					var i, iLen, j, jLen;

+

+					// Establish the list of matches to be removed

+					for (i = 0, iLen = this.matches.length; i < iLen; i++) {

+						for (j = 0, jLen = logEntries.length; j < jLen; j++) {

+							if (this.matches[i].belongsTo(logEntries[j])) {

+								matchesToRemove.push(this.matches[i]);

+								if (i === currentMatchIndex) {

+									currentMatchRemoved = true;

+								}

+							}

+						}

+					}

+

+					// Set the new current match index if the current match has been deleted

+					// This will be the first match that appears after the first log entry being

+					// deleted, if one exists; otherwise, it's the first match overall

+					var newMatch = currentMatchRemoved ? null : this.matches[currentMatchIndex];

+					if (currentMatchRemoved) {

+						for (i = currentMatchIndex, iLen = this.matches.length; i < iLen; i++) {

+							if (this.matches[i].isVisible() && !array_contains(matchesToRemove, this.matches[i])) {

+								newMatch = this.matches[i];

+								break;

+							}

+						}

+					}

+

+					// Remove the matches

+					for (i = 0, iLen = matchesToRemove.length; i < iLen; i++) {

+						array_remove(this.matches, matchesToRemove[i]);

+						matchesToRemove[i].remove();

+					}

+

+					// Set the new match, if one exists

+					if (this.hasVisibleMatches()) {

+						if (newMatch === null) {

+							setCurrentMatchIndex(0);

+						} else {

+							// Get the index of the new match

+							var newMatchIndex = 0;

+							for (i = 0, iLen = this.matches.length; i < iLen; i++) {

+								if (newMatch === this.matches[i]) {

+									newMatchIndex = i;

+									break;

+								}

+							}

+							setCurrentMatchIndex(newMatchIndex);

+						}

+					} else {

+						currentMatchIndex = null;

+						displayNoMatches();

+					}

+				}

+			};

+

+			function getPageOffsetTop(el, container) {

+				var currentEl = el;

+				var y = 0;

+				while (currentEl && currentEl != container) {

+					y += currentEl.offsetTop;

+					currentEl = currentEl.offsetParent;

+				}

+				return y;

+			}

+

+			function scrollIntoView(el) {

+				var logContainer = logMainContainer;

+				// Check if the whole width of the element is visible and centre if not

+				if (!$("wrap").checked) {

+					var logContainerLeft = logContainer.scrollLeft;

+					var logContainerRight = logContainerLeft  + logContainer.offsetWidth;

+					var elLeft = el.offsetLeft;

+					var elRight = elLeft + el.offsetWidth;

+					if (elLeft < logContainerLeft || elRight > logContainerRight) {

+						logContainer.scrollLeft = elLeft - (logContainer.offsetWidth - el.offsetWidth) / 2;

+					}

+				}

+				// Check if the whole height of the element is visible and centre if not

+				var logContainerTop = logContainer.scrollTop;

+				var logContainerBottom = logContainerTop  + logContainer.offsetHeight;

+				var elTop = getPageOffsetTop(el) - getToolBarsHeight();

+				var elBottom = elTop + el.offsetHeight;

+				if (elTop < logContainerTop || elBottom > logContainerBottom) {

+					logContainer.scrollTop = elTop - (logContainer.offsetHeight - el.offsetHeight) / 2;

+				}

+			}

+

+			function Match(logEntryLevel, spanInMainDiv, spanInUnwrappedPre, spanInWrappedDiv) {

+				this.logEntryLevel = logEntryLevel;

+				this.spanInMainDiv = spanInMainDiv;

+				if (isIe) {

+					this.spanInUnwrappedPre = spanInUnwrappedPre;

+					this.spanInWrappedDiv = spanInWrappedDiv;

+				}

+				this.mainSpan = isIe ? spanInUnwrappedPre : spanInMainDiv;

+			}

+

+			Match.prototype = {

+				equals: function(match) {

+					return this.mainSpan === match.mainSpan;

+				},

+

+				setCurrent: function() {

+					if (isIe) {

+						addClass(this.spanInUnwrappedPre, "currentmatch");

+						addClass(this.spanInWrappedDiv, "currentmatch");

+						// Scroll the visible one into view

+						var elementToScroll = $("wrap").checked ? this.spanInWrappedDiv : this.spanInUnwrappedPre;

+						scrollIntoView(elementToScroll);

+					} else {

+						addClass(this.spanInMainDiv, "currentmatch");

+						scrollIntoView(this.spanInMainDiv);

+					}

+				},

+

+				belongsTo: function(logEntry) {

+					if (isIe) {

+						return isDescendant(this.spanInUnwrappedPre, logEntry.unwrappedPre);

+					} else {

+						return isDescendant(this.spanInMainDiv, logEntry.mainDiv);

+					}

+				},

+

+				setNotCurrent: function() {

+					if (isIe) {

+						removeClass(this.spanInUnwrappedPre, "currentmatch");

+						removeClass(this.spanInWrappedDiv, "currentmatch");

+					} else {

+						removeClass(this.spanInMainDiv, "currentmatch");

+					}

+				},

+

+				isOrphan: function() {

+					return isOrphan(this.mainSpan);

+				},

+

+				isVisible: function() {

+					return getCheckBox(this.logEntryLevel).checked;

+				},

+

+				remove: function() {

+					if (isIe) {

+						this.spanInUnwrappedPre = null;

+						this.spanInWrappedDiv = null;

+					} else {

+						this.spanInMainDiv = null;

+					}

+				}

+			};

+

+			var currentSearch = null;

+			var currentMatchIndex = null;

+

+			function doSearch() {

+				var searchBox = $("searchBox");

+				var searchTerm = searchBox.value;

+				var isRegex = $("searchRegex").checked;

+				var isCaseSensitive = $("searchCaseSensitive").checked;

+				var i;

+

+				if (searchTerm === "") {

+					$("searchReset").disabled = true;

+					$("searchNav").style.display = "none";

+					removeClass(document.body, "searching");

+					removeClass(searchBox, "hasmatches");

+					removeClass(searchBox, "nomatches");

+					for (i = 0; i < logEntries.length; i++) {

+						logEntries[i].clearSearch();

+						logEntries[i].setContent(logEntries[i].formattedMessage, logEntries[i].formattedMessage);

+					}

+					currentSearch = null;

+					setLogContainerHeight();

+				} else {

+					$("searchReset").disabled = false;

+					$("searchNav").style.display = "block";

+					var searchRegex;

+					var regexValid;

+					if (isRegex) {

+						try {

+							searchRegex = isCaseSensitive ? new RegExp(searchTerm, "g") : new RegExp(searchTerm, "gi");

+							regexValid = true;

+							replaceClass(searchBox, "validregex", "invalidregex");

+							searchBox.title = "Valid regex";

+						} catch (ex) {

+							regexValid = false;

+							replaceClass(searchBox, "invalidregex", "validregex");

+							searchBox.title = "Invalid regex: " + (ex.message ? ex.message : (ex.description ? ex.description : "unknown error"));

+							return;

+						}

+					} else {

+						searchBox.title = "";

+						removeClass(searchBox, "validregex");

+						removeClass(searchBox, "invalidregex");

+					}

+					addClass(document.body, "searching");

+					currentSearch = new Search(searchTerm, isRegex, searchRegex, isCaseSensitive);

+					for (i = 0; i < logEntries.length; i++) {

+						currentSearch.applyTo(logEntries[i]);

+					}

+					setLogContainerHeight();

+

+					// Highlight the first search match

+					if (currentSearch.hasVisibleMatches()) {

+						setCurrentMatchIndex(0);

+						displayMatches();

+					} else {

+						displayNoMatches();

+					}

+				}

+			}

+

+			function updateSearchFromFilters() {

+				if (currentSearch) {

+					if (currentSearch.hasMatches()) {

+						if (currentMatchIndex === null) {

+							currentMatchIndex = 0;

+						}

+						var currentMatch = currentSearch.matches[currentMatchIndex];

+						if (currentMatch.isVisible()) {

+							displayMatches();

+							setCurrentMatchIndex(currentMatchIndex);

+						} else {

+							currentMatch.setNotCurrent();

+							// Find the next visible match, if one exists

+							var nextVisibleMatchIndex = currentSearch.getNextVisibleMatchIndex();

+							if (nextVisibleMatchIndex > -1) {

+								setCurrentMatchIndex(nextVisibleMatchIndex);

+								displayMatches();

+							} else {

+								displayNoMatches();

+							}

+						}

+					} else {

+						displayNoMatches();

+					}

+				}

+			}

+

+			function refreshCurrentMatch() {

+				if (currentSearch && currentSearch.hasVisibleMatches()) {

+					setCurrentMatchIndex(currentMatchIndex);

+				}

+			}

+

+			function displayMatches() {

+				replaceClass($("searchBox"), "hasmatches", "nomatches");

+				$("searchBox").title = "" + currentSearch.matches.length + " matches found";

+				$("searchNav").style.display = "block";

+				setLogContainerHeight();

+			}

+

+			function displayNoMatches() {

+				replaceClass($("searchBox"), "nomatches", "hasmatches");

+				$("searchBox").title = "No matches found";

+				$("searchNav").style.display = "none";

+				setLogContainerHeight();

+			}

+

+			function toggleSearchEnabled(enable) {

+				enable = (typeof enable == "undefined") ? !$("searchDisable").checked : enable;

+				$("searchBox").disabled = !enable;

+				$("searchReset").disabled = !enable;

+				$("searchRegex").disabled = !enable;

+				$("searchNext").disabled = !enable;

+				$("searchPrevious").disabled = !enable;

+				$("searchCaseSensitive").disabled = !enable;

+				$("searchNav").style.display = (enable && ($("searchBox").value !== "") &&

+						currentSearch && currentSearch.hasVisibleMatches()) ?

+					"block" : "none";

+				if (enable) {

+					removeClass($("search"), "greyedout");

+					addClass(document.body, "searching");

+					if ($("searchHighlight").checked) {

+						addClass(logMainContainer, "searchhighlight");

+					} else {

+						removeClass(logMainContainer, "searchhighlight");

+					}

+					if ($("searchFilter").checked) {

+						addClass(logMainContainer, "searchfilter");

+					} else {

+						removeClass(logMainContainer, "searchfilter");

+					}

+					$("searchDisable").checked = !enable;

+				} else {

+					addClass($("search"), "greyedout");

+					removeClass(document.body, "searching");

+					removeClass(logMainContainer, "searchhighlight");

+					removeClass(logMainContainer, "searchfilter");

+				}

+				setLogContainerHeight();

+			}

+

+			function toggleSearchFilter() {

+				var enable = $("searchFilter").checked;

+				if (enable) {

+					addClass(logMainContainer, "searchfilter");

+				} else {

+					removeClass(logMainContainer, "searchfilter");

+				}

+				refreshCurrentMatch();

+			}

+

+			function toggleSearchHighlight() {

+				var enable = $("searchHighlight").checked;

+				if (enable) {

+					addClass(logMainContainer, "searchhighlight");

+				} else {

+					removeClass(logMainContainer, "searchhighlight");

+				}

+			}

+

+			function clearSearch() {

+				$("searchBox").value = "";

+				doSearch();

+			}

+

+			function searchNext() {

+				if (currentSearch !== null && currentMatchIndex !== null) {

+					currentSearch.matches[currentMatchIndex].setNotCurrent();

+					var nextMatchIndex = currentSearch.getNextVisibleMatchIndex();

+					if (nextMatchIndex > currentMatchIndex || confirm("Reached the end of the page. Start from the top?")) {

+						setCurrentMatchIndex(nextMatchIndex);

+					}

+				}

+			}

+

+			function searchPrevious() {

+				if (currentSearch !== null && currentMatchIndex !== null) {

+					currentSearch.matches[currentMatchIndex].setNotCurrent();

+					var previousMatchIndex = currentSearch.getPreviousVisibleMatchIndex();

+					if (previousMatchIndex < currentMatchIndex || confirm("Reached the start of the page. Continue from the bottom?")) {

+						setCurrentMatchIndex(previousMatchIndex);

+					}

+				}

+			}

+

+			function setCurrentMatchIndex(index) {

+				currentMatchIndex = index;

+				currentSearch.matches[currentMatchIndex].setCurrent();

+			}

+

+			/* ------------------------------------------------------------------------- */

+

+			// CSS Utilities

+

+			function addClass(el, cssClass) {

+				if (!hasClass(el, cssClass)) {

+					if (el.className) {

+						el.className += " " + cssClass;

+					} else {

+						el.className = cssClass;

+					}

+				}

+			}

+

+			function hasClass(el, cssClass) {

+				if (el.className) {

+					var classNames = el.className.split(" ");

+					return array_contains(classNames, cssClass);

+				}

+				return false;

+			}

+

+			function removeClass(el, cssClass) {

+				if (hasClass(el, cssClass)) {

+					// Rebuild the className property

+					var existingClasses = el.className.split(" ");

+					var newClasses = [];

+					for (var i = 0, len = existingClasses.length; i < len; i++) {

+						if (existingClasses[i] != cssClass) {

+							newClasses[newClasses.length] = existingClasses[i];

+						}

+					}

+					el.className = newClasses.join(" ");

+				}

+			}

+

+			function replaceClass(el, newCssClass, oldCssClass) {

+				removeClass(el, oldCssClass);

+				addClass(el, newCssClass);

+			}

+

+			/* ------------------------------------------------------------------------- */

+

+			// Other utility functions

+

+			function getElementsByClass(el, cssClass, tagName) {

+				var elements = el.getElementsByTagName(tagName);

+				var matches = [];

+				for (var i = 0, len = elements.length; i < len; i++) {

+					if (hasClass(elements[i], cssClass)) {

+						matches.push(elements[i]);

+					}

+				}

+				return matches;

+			}

+

+			// Syntax borrowed from Prototype library

+			function $(id) {

+				return document.getElementById(id);

+			}

+

+			function isDescendant(node, ancestorNode) {

+				while (node != null) {

+					if (node === ancestorNode) {

+						return true;

+					}

+					node = node.parentNode;

+				}

+				return false;

+			}

+

+			function isOrphan(node) {

+				var currentNode = node;

+				while (currentNode) {

+					if (currentNode == document.body) {

+						return false;

+					}

+					currentNode = currentNode.parentNode;

+				}

+				return true;

+			}

+

+			function escapeHtml(str) {

+				return str.replace(/&/g, "&amp;").replace(/[<]/g, "&lt;").replace(/>/g, "&gt;");

+			}

+

+			function getWindowWidth() {

+				if (window.innerWidth) {

+					return window.innerWidth;

+				} else if (document.documentElement && document.documentElement.clientWidth) {

+					return document.documentElement.clientWidth;

+				} else if (document.body) {

+					return document.body.clientWidth;

+				}

+				return 0;

+			}

+

+			function getWindowHeight() {

+				if (window.innerHeight) {

+					return window.innerHeight;

+				} else if (document.documentElement && document.documentElement.clientHeight) {

+					return document.documentElement.clientHeight;

+				} else if (document.body) {

+					return document.body.clientHeight;

+				}

+				return 0;

+			}

+

+			function getToolBarsHeight() {

+				return $("switches").offsetHeight;

+			}

+

+			function getChromeHeight() {

+				var height = getToolBarsHeight();

+				if (showCommandLine) {

+					height += $("commandLine").offsetHeight;

+				}

+				return height;

+			}

+

+			function setLogContainerHeight() {

+				if (logMainContainer) {

+					var windowHeight = getWindowHeight();

+					$("body").style.height = getWindowHeight() + "px";

+					logMainContainer.style.height = "" +

+						Math.max(0, windowHeight - getChromeHeight()) + "px";

+				}

+			}

+

+			function setCommandInputWidth() {

+				if (showCommandLine) {

+					$("command").style.width = "" + Math.max(0, $("commandLineContainer").offsetWidth -

+						($("evaluateButton").offsetWidth + 13)) + "px";

+				}

+			}

+

+			window.onresize = function() {

+				setCommandInputWidth();

+				setLogContainerHeight();

+			};

+

+			if (!Array.prototype.push) {

+				Array.prototype.push = function() {

+			        for (var i = 0, len = arguments.length; i < len; i++){

+			            this[this.length] = arguments[i];

+			        }

+			        return this.length;

+				};

+			}

+

+			if (!Array.prototype.pop) {

+				Array.prototype.pop = function() {

+					if (this.length > 0) {

+						var val = this[this.length - 1];

+						this.length = this.length - 1;

+						return val;

+					}

+				};

+			}

+

+			if (!Array.prototype.shift) {

+				Array.prototype.shift = function() {

+					if (this.length > 0) {

+						var firstItem = this[0];

+						for (var i = 0, len = this.length - 1; i < len; i++) {

+							this[i] = this[i + 1];

+						}

+						this.length = this.length - 1;

+						return firstItem;

+					}

+				};

+			}

+

+			if (!Array.prototype.splice) {

+				Array.prototype.splice = function(startIndex, deleteCount) {

+					var itemsAfterDeleted = this.slice(startIndex + deleteCount);

+					var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);

+					this.length = startIndex;

+					// Copy the arguments into a proper Array object

+					var argumentsArray = [];

+					for (var i = 0, len = arguments.length; i < len; i++) {

+						argumentsArray[i] = arguments[i];

+					}

+					var itemsToAppend = (argumentsArray.length > 2) ?

+						itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;

+					for (i = 0, len = itemsToAppend.length; i < len; i++) {

+						this.push(itemsToAppend[i]);

+					}

+					return itemsDeleted;

+				};

+			}

+

+			function array_remove(arr, val) {

+				var index = -1;

+				for (var i = 0, len = arr.length; i < len; i++) {

+					if (arr[i] === val) {

+						index = i;

+						break;

+					}

+				}

+				if (index >= 0) {

+					arr.splice(index, 1);

+					return index;

+				} else {

+					return false;

+				}

+			}

+

+			function array_removeFromStart(array, numberToRemove) {

+				if (Array.prototype.splice) {

+					array.splice(0, numberToRemove);

+				} else {

+					for (var i = numberToRemove, len = array.length; i < len; i++) {

+						array[i - numberToRemove] = array[i];

+					}

+					array.length = array.length - numberToRemove;

+				}

+				return array;

+			}

+

+			function array_contains(arr, val) {

+				for (var i = 0, len = arr.length; i < len; i++) {

+					if (arr[i] == val) {

+						return true;

+					}

+				}

+				return false;

+			}

+

+			function getErrorMessage(ex) {

+				if (ex.message) {

+					return ex.message;

+				} else if (ex.description) {

+					return ex.description;

+				}

+				return "" + ex;

+			}

+

+			function moveCaretToEnd(input) {

+				if (input.setSelectionRange) {

+					input.focus();

+					var length = input.value.length;

+					input.setSelectionRange(length, length);

+				} else if (input.createTextRange) {

+					var range = input.createTextRange();

+					range.collapse(false);

+					range.select();

+				}

+				input.focus();

+			}

+

+			function stopPropagation(evt) {

+				if (evt.stopPropagation) {

+					evt.stopPropagation();

+				} else if (typeof evt.cancelBubble != "undefined") {

+					evt.cancelBubble = true;

+				}

+			}

+

+			function getEvent(evt) {

+				return evt ? evt : event;

+			}

+

+			function getTarget(evt) {

+				return evt.target ? evt.target : evt.srcElement;

+			}

+

+			function getRelatedTarget(evt) {

+				if (evt.relatedTarget) {

+					return evt.relatedTarget;

+				} else if (evt.srcElement) {

+					switch(evt.type) {

+						case "mouseover":

+							return evt.fromElement;

+						case "mouseout":

+							return evt.toElement;

+						default:

+							return evt.srcElement;

+					}

+				}

+			}

+

+			function cancelKeyEvent(evt) {

+				evt.returnValue = false;

+				stopPropagation(evt);

+			}

+

+			function evalCommandLine() {

+				var expr = $("command").value;

+				evalCommand(expr);

+				$("command").value = "";

+			}

+

+			function evalLastCommand() {

+				if (lastCommand != null) {

+					evalCommand(lastCommand);

+				}

+			}

+

+			var lastCommand = null;

+			var commandHistory = [];

+			var currentCommandIndex = 0;

+

+			function evalCommand(expr) {

+				if (appender) {

+					appender.evalCommandAndAppend(expr);

+				} else {

+					var prefix = ">>> " + expr + "\r\n";

+					try {

+						log("INFO", prefix + eval(expr));

+					} catch (ex) {

+						log("ERROR", prefix + "Error: " + getErrorMessage(ex));

+					}

+				}

+				// Update command history

+				if (expr != commandHistory[commandHistory.length - 1]) {

+					commandHistory.push(expr);

+					// Update the appender

+					if (appender) {

+						appender.storeCommandHistory(commandHistory);

+					}

+				}

+				currentCommandIndex = (expr == commandHistory[currentCommandIndex]) ? currentCommandIndex + 1 : commandHistory.length;

+				lastCommand = expr;

+			}

+			//]]>

+		</script>

+		<style type="text/css">

+			body {

+				background-color: white;

+				color: black;

+				padding: 0;

+				margin: 0;

+				font-family: tahoma, verdana, arial, helvetica, sans-serif;

+				overflow: hidden;

+			}

+

+			div#switchesContainer input {

+				margin-bottom: 0;

+			}

+

+			div.toolbar {

+				border-top: solid #ffffff 1px;

+				border-bottom: solid #aca899 1px;

+				background-color: #f1efe7;

+				padding: 3px 5px;

+				font-size: 68.75%;

+			}

+

+			div.toolbar, div#search input {

+				font-family: tahoma, verdana, arial, helvetica, sans-serif;

+			}

+

+			div.toolbar input.button {

+				padding: 0 5px;

+				font-size: 100%;

+			}

+

+			div.toolbar input.hidden {

+				display: none;

+			}

+

+			div#switches input#clearButton {

+				margin-left: 20px;

+			}

+

+			div#levels label {

+				font-weight: bold;

+			}

+

+			div#levels label, div#options label {

+				margin-right: 5px;

+			}

+

+			div#levels label#wrapLabel {

+				font-weight: normal;

+			}

+

+			div#search label {

+				margin-right: 10px;

+			}

+

+			div#search label.searchboxlabel {

+				margin-right: 0;

+			}

+

+			div#search input {

+				font-size: 100%;

+			}

+

+			div#search input.validregex {

+				color: green;

+			}

+

+			div#search input.invalidregex {

+				color: red;

+			}

+

+			div#search input.nomatches {

+				color: white;

+				background-color: #ff6666;

+			}

+

+			div#search input.nomatches {

+				color: white;

+				background-color: #ff6666;

+			}

+

+			div#searchNav {

+				display: none;

+			}

+

+			div#commandLine {

+				display: none;

+			}

+

+			div#commandLine input#command {

+				font-size: 100%;

+				font-family: Courier New, Courier;

+			}

+

+			div#commandLine input#evaluateButton {

+			}

+

+			*.greyedout {

+				color: gray !important;

+				border-color: gray !important;

+			}

+

+			*.greyedout *.alwaysenabled { color: black; }

+

+			*.unselectable {

+				-khtml-user-select: none;

+				-moz-user-select: none;

+				user-select: none;

+			}

+

+			div#log {

+				font-family: Courier New, Courier;

+				font-size: 75%;

+				width: 100%;

+				overflow: auto;

+				clear: both;

+				position: relative;

+			}

+

+			div.group {

+				border-color: #cccccc;

+				border-style: solid;

+				border-width: 1px 0 1px 1px;

+				overflow: visible;

+			}

+

+			div.oldIe div.group, div.oldIe div.group *, div.oldIe *.logentry {

+				height: 1%;

+			}

+

+			div.group div.groupheading span.expander {

+				border: solid black 1px;

+				font-family: Courier New, Courier;

+				font-size: 0.833em;

+				background-color: #eeeeee;

+				position: relative;

+				top: -1px;

+				color: black;

+				padding: 0 2px;

+				cursor: pointer;

+				cursor: hand;

+				height: 1%;

+			}

+

+			div.group div.groupcontent {

+				margin-left: 10px;

+				padding-bottom: 2px;

+				overflow: visible;

+			}

+

+			div.group div.expanded {

+				display: block;

+			}

+

+			div.group div.collapsed {

+				display: none;

+			}

+

+			*.logentry {

+				overflow: visible;

+				display: none;

+				white-space: pre;

+			}

+

+			span.pre {

+				white-space: pre;

+			}

+			

+			pre.unwrapped {

+				display: inline !important;

+			}

+

+			pre.unwrapped pre.pre, div.wrapped pre.pre {

+				display: inline;

+			}

+

+			div.wrapped pre.pre {

+				white-space: normal;

+			}

+

+			div.wrapped {

+				display: none;

+			}

+

+			body.searching *.logentry span.currentmatch {

+				color: white !important;

+				background-color: green !important;

+			}

+

+			body.searching div.searchhighlight *.logentry span.searchterm {

+				color: black;

+				background-color: yellow;

+			}

+

+			div.wrap *.logentry {

+				white-space: normal !important;

+				border-width: 0 0 1px 0;

+				border-color: #dddddd;

+				border-style: dotted;

+			}

+

+			div.wrap #log_wrapped, #log_unwrapped {

+				display: block;

+			}

+

+			div.wrap #log_unwrapped, #log_wrapped {

+				display: none;

+			}

+

+			div.wrap *.logentry span.pre {

+				overflow: visible;

+				white-space: normal;

+			}

+

+			div.wrap *.logentry pre.unwrapped {

+				display: none;

+			}

+

+			div.wrap *.logentry span.wrapped {

+				display: inline;

+			}

+

+			div.searchfilter *.searchnonmatch {

+				display: none !important;

+			}

+

+			div#log *.TRACE, label#label_TRACE {

+				color: #666666;

+			}

+

+			div#log *.DEBUG, label#label_DEBUG {

+				color: green;

+			}

+

+			div#log *.INFO, label#label_INFO {

+				color: #000099;

+			}

+

+			div#log *.WARN, label#label_WARN {

+				color: #999900;

+			}

+

+			div#log *.ERROR, label#label_ERROR {

+				color: red;

+			}

+

+			div#log *.FATAL, label#label_FATAL {

+				color: #660066;

+			}

+

+			div.TRACE#log *.TRACE,

+			div.DEBUG#log *.DEBUG,

+			div.INFO#log *.INFO,

+			div.WARN#log *.WARN,

+			div.ERROR#log *.ERROR,

+			div.FATAL#log *.FATAL {

+				display: block;

+			}

+

+			div#log div.separator {

+				background-color: #cccccc;

+				margin: 5px 0;

+				line-height: 1px;

+			}

+		</style>

+	</head>

+

+	<body id="body">

+		<div id="switchesContainer">

+			<div id="switches">

+				<div id="levels" class="toolbar">

+					Filters:

+					<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>

+					<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>

+					<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>

+					<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>

+					<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>

+					<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>

+					<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>

+				</div>

+				<div id="search" class="toolbar">

+					<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />

+					<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />

+					<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>

+					<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>

+					<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>

+					<div id="searchNav">

+						<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />

+						<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />

+						<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>

+						<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>

+					</div>

+				</div>

+				<div id="options" class="toolbar">

+					Options:

+					<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>

+					<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>

+					<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>

+					<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>

+					<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />

+					<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />

+					<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />

+				</div>

+			</div>

+		</div>

+		<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>

+		<div id="commandLine" class="toolbar">

+			<div id="commandLineContainer">

+				<input type="text" id="command" title="Enter a JavaScript command here and hit return or press 'Evaluate'" />

+				<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />

+			</div>

+		</div>

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/demos/basic.html b/planetstack/core/static/log4javascript-1.4.6/demos/basic.html
new file mode 100644
index 0000000..51d5857
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/demos/basic.html
@@ -0,0 +1,159 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript basic demo</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+		<script type="text/javascript" src="../js/log4javascript.js"></script>

+		<script type="text/javascript">

+			// <![CDATA[

+			var log = log4javascript.getLogger("main");

+			var appender = new log4javascript.PopUpAppender();

+			log.addAppender(appender);

+			log.debug("This is debugging message from the log4javascript basic demo page");

+

+			var words = ["Watford", "eased", "their", "relegation", "fears", "with", "a", "win",

+				"against", "a", "Charlton", "side", "who", "slipped", "further", "towards", "the",

+				"drop", "Don", "Cowie", "drilled", "in", "a", "shot", "to", "put", "the", "Hornets",

+				"ahead", "before", "Tresor", "Kandol", "ended", "a", "powerful", "run", "by",

+				"rounding", "keeper", "Scott", "Loach", "and", "slotting", "in", "to", "level"

+			];

+

+			var loaded = false;

+

+			function generateRandom() {

+				var numberOfEntries = parseInt(document.getElementById("numberOfLogEntries").value);

+				for (var i = 0; i < numberOfEntries; i++) {

+					var numberOfWords = 1 + Math.floor(10 * Math.random());

+					var entryWords = [];

+					for (var j = 0; j < numberOfWords; j++) {

+						entryWords.push(words[Math.floor(Math.random() * words.length)]);

+					}

+					var entryMessage = entryWords.join(" ");

+					var levelNum = Math.floor(Math.random() * 6);

+					switch (levelNum) {

+						case 0:

+							log.trace(entryMessage);

+							break;

+						case 1:

+							log.debug(entryMessage);

+							break;

+						case 2:

+							log.info(entryMessage);

+							break;

+						case 3:

+							log.warn(entryMessage);

+							break;

+						case 4:

+							log.error(entryMessage);

+							break;

+						case 5:

+							log.fatal(entryMessage);

+							break;

+					}

+				}

+			}

+

+			function generateObjectExpansion() {

+				var debugObj = {

+					a: {

+						b: "stuff",

+						c: 3,

+						d: {

+							e: ["a", "b", "c"]

+						}

+					},

+					f: "Things",

+					g: 5

+				};

+				log.debug(debugObj);

+			}

+

+			function generateError() {

+				try {

+					throw new Error("Made up error");

+				} catch (ex) {

+					log.error("Logging an error!", ex);

+				}

+			}

+			// ]]>

+		</script>

+	</head>

+	<body onload="loaded = true; document.getElementById('enabled').checked = true;">

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="/docs/index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="../docs/index.html">docs</a>

+					| <a class="navitem" href="../docs/quickstart.html">quick start</a>

+					| <a class="navitem" href="index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript basic demo</h1>

+				<p>

+					<em><strong>NB.</strong> Since the demo below uses pop-up windows, you will

+					need to disable any pop-up blockers you may have for it to work.</em>

+				</p>

+				<p>

+					This demo demonstrates the default logger. For more options, please see the

+					<a href="index.html">demos area</a>.

+				</p>

+				<p>

+					Enter a log message below and click on one of the buttons to log

+					your message at your desired level. You can then filter by

+					log level, toggle word-wrapping and perform text and regular

+					expression searches on the log entries.

+				</p>

+				<div class="example">

+					<input type="text" id="logText" value="Put log message here" />

+					<input type="button" value="debug" onclick="log.debug(document.getElementById('logText').value)" />

+					<input type="button" value="info" onclick="log.info(document.getElementById('logText').value)" />

+					<input type="button" value="warn" onclick="log.warn(document.getElementById('logText').value)" />

+					<input type="button" value="error" onclick="log.error(document.getElementById('logText').value)" />

+					<input type="button" value="fatal" onclick="log.fatal(document.getElementById('logText').value)" />

+					<br />

+					<input type="button" value="assert 1 equals 1" onclick="log.assert(1 === 1)" />

+					<input type="button" value="assert 1 equals 2" onclick="log.assert(1 === 2)" />

+					<br />

+					Generate <input type="text" size="5" id="numberOfLogEntries" value="50" /> random log entries

+					<input type="button" value="go" onclick="generateRandom()" />

+					<br />

+					<input type="button" value="Log exception" onclick="generateError()" />

+					<input type="button" value="Log example object" onclick="generateObjectExpansion()" />

+					<br />

+					<input type="checkbox" id="enabled" onclick="log4javascript.setEnabled(this.checked)" checked="checked" /> <label for="enabled">logging enabled</label>

+					<br />

+					<input type="text" id="groupName" value="Group name" />

+					<input type="button" value="group" onclick="log.group(document.getElementById('groupName').value)" />

+					<input type="button" value="end group" onclick="log.groupEnd()" />

+					<br />

+					<input type="text" id="timerName" value="Example timer name" />

+					<input type="button" value="start timer" onclick="log.time(document.getElementById('timerName').value)" />

+					<input type="button" value="end timer" onclick="log.timeEnd(document.getElementById('timerName').value)" />

+				</div>

+			</div>

+			<br class="clear" />

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/demos/blank.html b/planetstack/core/static/log4javascript-1.4.6/demos/blank.html
new file mode 100644
index 0000000..7e8ac56
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/demos/blank.html
@@ -0,0 +1,4 @@
+<html>

+<head><title>Blank page</title></head>

+<body></body>

+</html>
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/demos/index.html b/planetstack/core/static/log4javascript-1.4.6/demos/index.html
new file mode 100644
index 0000000..00e84ac
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/demos/index.html
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript demos</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="/docs/index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="../docs/index.html">docs</a>

+					| <a class="navitem" href="../docs/quickstart.html">quick start</a>

+					| <span class="navitem">demos</span>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript demos</h1>

+				<ul>

+					<li><a href="basic.html">Basic demo</a></li>

+					<li><a href="inpage.html">In-page console demo</a></li>

+					<li><a href="lite.html">log4javascript Lite demo</a></li>

+				</ul>

+			</div>

+			<br class="clear" />

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/demos/inpage.html b/planetstack/core/static/log4javascript-1.4.6/demos/inpage.html
new file mode 100644
index 0000000..8e47d72
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/demos/inpage.html
@@ -0,0 +1,174 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript in-page console demo</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+		<script type="text/javascript" src="../js/log4javascript_uncompressed.js"></script>

+		<script type="text/javascript">

+			// <![CDATA[

+			var log = log4javascript.getLogger("main");

+			var appender = new log4javascript.InPageAppender();

+			log.addAppender(appender);

+			log.debug("This is a debugging message from the log4javascript in-page page");

+

+			var words = ["Watford", "eased", "their", "relegation", "fears", "with", "a", "win",

+				"against", "a", "Charlton", "side", "who", "slipped", "further", "towards", "the",

+				"drop", "Don", "Cowie", "drilled", "in", "a", "shot", "to", "put", "the", "Hornets",

+				"ahead", "before", "Tresor", "Kandol", "ended", "a", "powerful", "run", "by",

+				"rounding", "keeper", "Scott", "Loach", "and", "slotting", "in", "to", "level"

+			];

+

+			var loaded = false;

+

+			function generateRandom() {

+				var numberOfEntries = parseInt(document.getElementById("numberOfLogEntries").value);

+				for (var i = 0; i < numberOfEntries; i++) {

+					var numberOfWords = 1 + Math.floor(10 * Math.random());

+					var entryWords = [];

+					for (var j = 0; j < numberOfWords; j++) {

+						entryWords.push(words[Math.floor(Math.random() * words.length)]);

+					}

+					var entryMessage = entryWords.join(" ");

+					var levelNum = Math.floor(Math.random() * 6);

+					switch (levelNum) {

+						case 0:

+							log.trace(entryMessage);

+							break;

+						case 1:

+							log.debug(entryMessage);

+							break;

+						case 2:

+							log.info(entryMessage);

+							break;

+						case 3:

+							log.warn(entryMessage);

+							break;

+						case 4:

+							log.error(entryMessage);

+							break;

+						case 5:

+							log.fatal(entryMessage);

+							break;

+					}

+				}

+			}

+			

+			var consoleVisible = true;

+			

+			function toggleConsole(button) {

+				if (consoleVisible) {

+					appender.hide();

+					button.value = "Show console";

+					consoleVisible = false;

+				} else {

+					appender.show();

+					button.value = "Hide console";

+					consoleVisible = true;

+				}

+			}

+

+			function generateObjectExpansion() {

+				var debugObj = {

+					a: {

+						b: "stuff",

+						c: 3,

+						d: {

+							e: ["a", "b", "c"]

+						}

+					},

+					f: "Things",

+					g: 5

+				};

+				log.debug(debugObj);

+			}

+

+			function generateError() {

+				try {

+					throw new Error("Made up error");

+				} catch (ex) {

+					log.error("Logging an error!", ex);

+				}

+			}

+			// ]]>

+		</script>

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="/docs/index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="../docs/index.html">docs</a>

+					| <a class="navitem" href="../docs/quickstart.html">quick start</a>

+					| <a class="navitem" href="index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript in-page console demo</h1>

+				<p>

+					This demo demonstrates an in-page logger. The example uses the default behaviour, which

+					is to place the log console in a fixed area at the bottom of the page. However, the

+					console may be placed inside any element in the page. To do this, you may specify the ID

+					of the element (even if the page has not yet loaded) or a reference to the element itself.

+				</p>

+				<p>

+					Enter a log message below and click on one of the buttons to log

+					your message at your desired level. You can then filter by

+					log level, toggle word-wrapping and perform text and regular

+					expression searches on the log entries.

+				</p>

+				<div class="example">

+					<input type="button" value="Hide console" onclick="toggleConsole(this)" />

+					<br />

+					<input type="text" id="logText" value="Put log message here" />

+					<input type="button" value="debug" onclick="log.debug(document.getElementById('logText').value)" />

+					<input type="button" value="info" onclick="log.info(document.getElementById('logText').value)" />

+					<input type="button" value="warn" onclick="log.warn(document.getElementById('logText').value)" />

+					<input type="button" value="error" onclick="log.error(document.getElementById('logText').value)" />

+					<input type="button" value="fatal" onclick="log.fatal(document.getElementById('logText').value)" />

+					<br />

+					<input type="button" value="assert 1 equals 1" onclick="log.assert(1 === 1)" />

+					<input type="button" value="assert 1 equals 2" onclick="log.assert(1 === 2)" />

+					<br />

+					Generate <input type="text" size="5" id="numberOfLogEntries" value="50" /> random log entries

+					<input type="button" value="go" onclick="generateRandom()" />

+					<br />

+					<input type="button" value="Log exception" onclick="generateError()" />

+					<input type="button" value="Log example object" onclick="generateObjectExpansion()" />

+					<br />

+					<input type="checkbox" id="enabled" onclick="log4javascript.setEnabled(this.checked)" checked="checked" /> <label for="enabled">logging enabled</label>

+					<br />

+					<input type="text" id="groupName" value="Group name" />

+					<input type="button" value="group" onclick="log.group(document.getElementById('groupName').value)" />

+					<input type="button" value="end group" onclick="log.groupEnd()" />

+					<br />

+					<input type="text" id="timerName" value="Example timer name" />

+					<input type="button" value="start timer" onclick="log.time(document.getElementById('timerName').value)" />

+					<input type="button" value="end timer" onclick="log.timeEnd(document.getElementById('timerName').value)" />

+				</div>

+			</div>

+			<br class="clear" />

+			<div id="log"></div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/demos/lite.html b/planetstack/core/static/log4javascript-1.4.6/demos/lite.html
new file mode 100644
index 0000000..a1d2dd3
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/demos/lite.html
@@ -0,0 +1,148 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript lite demo</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+		<script type="text/javascript" src="../js/log4javascript_lite.js"></script>

+		<script type="text/javascript">

+			// <![CDATA[

+			var	log = log4javascript.getDefaultLogger();

+			log.debug("This is debugging message from the log4javascript lite demo page");

+

+			var words = ["Boothroyd", "who", "took", "over", "two", "years",

+					"ago", "and", "continues", "to", "maintain", "that", "the",

+					"club", "are", "building", "for", "the", "future", "made",

+					"six", "changes", "and", "gave", "a", "first", "Premiership",

+					"start", "to", "on-loan", "Brazilian", "midfielder",

+					"Douglas", "Rinaldi", "Darius", "Henderson", "and", "Steve",

+					"Kabba", "were", "two", "of", "the", "players", "restored",

+					"to", "the", "home", "side", "and", "were", "responsible",

+					"for", "giving", "Chelsea", "an", "uncomfortable", "start",

+					"which", "set", "the", "pattern", "for", "the", "match"

+					];

+

+			var loaded = false;

+

+			function generateRandom() {

+				var numberOfEntries = parseInt(document.getElementById("numberOfLogEntries").value);

+				for (var i = 0; i < numberOfEntries; i++) {

+					var numberOfWords = 1 + Math.floor(10 * Math.random());

+					var entryWords = [];

+					for (var j = 0; j < numberOfWords; j++) {

+						entryWords.push(words[Math.floor(Math.random() * words.length)]);

+					}

+					var entryMessage = entryWords.join(" ");

+					var levelNum = Math.floor(Math.random() * 6);

+					switch (levelNum) {

+						case 0:

+							log.trace(entryMessage);

+							break;

+						case 1:

+							log.debug(entryMessage);

+							break;

+						case 2:

+							log.info(entryMessage);

+							break;

+						case 3:

+							log.warn(entryMessage);

+							break;

+						case 4:

+							log.error(entryMessage);

+							break;

+						case 5:

+							log.fatal(entryMessage);

+							break;

+					}

+				}

+			}

+

+			function generateObjectExpansion() {

+				var debugObj = {

+					a: {

+						b: "stuff",

+						c: 3,

+						d: {

+							e: ["a", "b", "c"]

+						}

+					},

+					f: "Things",

+					g: 5

+				};

+				log.debug(debugObj);

+			}

+

+			function generateError() {

+				try {

+					throw new Error("Made up error");

+				} catch (ex) {

+					log.error("Logging an error!", ex);

+				}

+			}

+			// ]]>

+		</script>

+	</head>

+	<body onload="loaded = true; document.getElementById('enabled').checked = true;">

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="/docs/index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="../docs/index.html">docs</a>

+					| <a class="navitem" href="../docs/quickstart.html">quick start</a>

+					| <a class="navitem" href="../docs/manual.html">manual</a>

+					| <a class="navitem" href="index.html">demos</a>

+					| <a class="navitem" href="http://www.timdown.co.uk/log4javascript" target="_blank">website</a>

+				</div>

+				<h1>log4javascript lite demo</h1>

+				<p>

+					<em><strong>NB.</strong> Since the demo below uses pop-up windows, you will

+					need to disable any pop-up blockers you may have for it to work.</em>

+				</p>

+				<p>

+					This demo demonstrates the lite edition of log4javascript.

+				</p>

+				<p>

+					Enter a log message below and click on one of the buttons to log

+					your message at your desired level.

+				</p>

+				<div class="example">

+					<input type="text" id="logText" value="Put log message here" />

+					<input type="button" value="trace" onclick="log.trace(document.getElementById('logText').value)" />

+					<input type="button" value="debug" onclick="log.debug(document.getElementById('logText').value)" />

+					<input type="button" value="info" onclick="log.info(document.getElementById('logText').value)" />

+					<input type="button" value="warn" onclick="log.warn(document.getElementById('logText').value)" />

+					<input type="button" value="error" onclick="log.error(document.getElementById('logText').value)" />

+					<input type="button" value="fatal" onclick="log.fatal(document.getElementById('logText').value)" />

+					<br />

+					Generate <input type="text" size="5" id="numberOfLogEntries" value="50" /> random log entries

+					<input type="button" value="go" onclick="generateRandom()" />

+					<br />

+					<input type="button" value="Log exception" onclick="generateError()" />

+					<input type="button" value="Log example object" onclick="generateObjectExpansion()" />

+					<br />

+					<input type="checkbox" id="enabled" onclick="log4javascript.setEnabled(this.checked)" checked="checked" /> <label for="enabled">logging enabled</label>

+					<br />

+				</div>

+			</div>

+			<br class="clear" />

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/backwardsincompatibilities.html b/planetstack/core/static/log4javascript-1.4.6/docs/backwardsincompatibilities.html
new file mode 100644
index 0000000..f212fd4
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/docs/backwardsincompatibilities.html
@@ -0,0 +1,90 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - backwards incompatibilities in version 1.4</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="/index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="index.html">docs</a>

+					| <a class="navitem" href="quickstart.html">quick start</a>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>Backwards incompatibilities in log4javascript 1.4</h1>

+				<ul>

+					<li>

+						Loggers are now hierarchical. This means logger names containing full stops have

+						special meaning. For example, from version 1.4 the logger named <code>myapp.ajax</code>

+						by default inherits all the appenders of the logger named <code>myapp</code>, while

+						prior to version 1.4 these loggers would be entirely independent;

+					</li>

+					<li>

+						The signature of the <code>log</code> method of <code>Logger</code> has changed.

+						However, you should not use this method directly; instead, use one of the level-specific

+						wrapper functions (<code>debug</code>, <code>info</code>, <code>error</code> etc.);

+					</li>

+					<li>

+						Appenders can no longer be configured via constructor parameters. Instead you must use

+						setter methods;

+					</li>

+					<li>

+						The format of requests sent via <code><a href="manual.html#ajaxappender">AjaxAppender</a></code>

+						has changed when using <code><a href="manual.html#jsonlayout">JsonLayout</a></code> or

+						<code><a href="manual.html#xmllayout">XmlLayout</a></code>: the formatted log messages are sent

+						as a name-value pair (with default name <code>data</code>) rather than a single unencoded string;

+					</li>

+					<li>

+						All timestamps returned by <code><a href="manual.html#xmllayout">XmlLayout</a></code>,

+						<code><a href="manual.html#jsonlayout">JsonLayout</a></code> and

+						<code><a href="manual.html#httppostdatlayout">HttpPostDataLayout</a></code> are

+						now measured in milliseconds since January 1st 1970 (previously they were returned

+						as seconds since January 1st 1970);

+					</li>

+					<li>

+						The constructors for <a href="manual.html#jsonlayout">JsonLayout</a> and

+						<a href="manual.html#httppostdatlayout">HttpPostDataLayout</a> have changed; the property names

+						used for the properties of the logging event are now set via <code>setKeys</code> rather than

+						in the constructor;

+					</li>

+					<li>

+						<code>setReadable</code> has been removed from <a href="manual.html#jsonlayout">JsonLayout</a>.

+						The <code>readable</code> property should now be set via the constructor;

+					</li>

+					<li>

+						<code>addErrorListener</code> and <code>removeErrorListener</code> removed from

+						the <code>log4javascript</code> object and replaced with the more generic

+						<code><a href="manual.html#log4javascriptaddeventlistener">addEventListener</a></code>

+						and <code>removeEventListener</code> methods. The listener functions are passed

+						different parameters.

+					</li>

+				</ul>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/distribution.html b/planetstack/core/static/log4javascript-1.4.6/docs/distribution.html
new file mode 100644
index 0000000..8f6cdfd
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/docs/distribution.html
@@ -0,0 +1,87 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en" >

+	<head>

+		<title>log4javascript 1.4 distribution</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="../index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="index.html">docs</a>

+					| <a class="navitem" href="quickstart.html">quick start</a>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript 1.4 distribution</h1>

+				<p>

+					From version 1.4 the distribution includes three different editions of log4javascript:

+				</p>

+				<ul>

+					<li>

+						<div><strong>Standard Edition</strong></div>

+						<p>

+							Equivalent to log4javascript from earlier versions and suitable for general JavaScript

+							debugging and logging (including via Ajax).

+						</p>

+					</li>

+					<li>

+						<div><strong>Production Edition</strong></div>

+						<p>

+							Designed for use in production systems where the focus is solely on logging JavaScript

+							messages back to the server. Consequently this edition omits all appenders except

+							<a href="manual.html#ajaxappender">AjaxAppender</a>, resulting in a drastically reduced

+							file size compared to the standard edition.

+						</p>

+					</li>

+					<li>

+						<div><strong>Lite Edition</strong></div>

+						<p>

+							A lightweight version of log4javascript for quick page debugging. Included is a single logger

+							using a basic pop-up window appender with a fixed layout.

+						</p>

+					</li>

+				</ul>

+				<p>

+					Each edition comes in compressed and uncompressed versions. The compressed version is

+					functionally identical to the uncompressed version but has had whitespace and comments removed

+					and therefore downloads more quickly.

+				</p>

+				<p>

+					Each edition also comes with a stub version. This contains dummy implementations of all

+					log4javacript objects and methods in the public API, making it ideal for production environments

+					where logging is not required. Replacing the main log4javascript script file with this file

+					means that log calls may be left in production code. Compressed and uncompressed versions of

+					each stub are included.

+				</p>

+				<p>

+					Finally, each edition comes with a suite of unit tests, available as HTML pages in the

+					<code>test/</code> directory. Note that these tests crash old versions (pre-3.1) of Safari. Sorry.

+				</p>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/index.html b/planetstack/core/static/log4javascript-1.4.6/docs/index.html
new file mode 100644
index 0000000..d3b3ac2
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/docs/index.html
@@ -0,0 +1,190 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript documentation</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="../index.html">log4javascript</a></h1>

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <span class="navitem">docs</span>

+					| <a class="navitem" href="quickstart.html">quick start</a>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+			</div>

+			<div id="content">

+				<h1>log4javascript 1.4 documentation</h1>

+				<div id="links">

+					<h2>Links</h2>

+					<ul>

+						<li><a href="quickstart.html">Quick start</a></li>

+						<li><a href="distribution.html">Details of the log4javascript distribution</a></li>

+						<li><a href="backwardsincompatibilities.html">Backwards incompatibilities</a></li>

+						<li><a href="whatsnew.html">What's new in this release</a></li>

+						<li><a href="../changelog.txt">Change log</a></li>

+						<li><a href="manual.html">log4javascript manual</a></li>

+						<li><a href="lite.html">log4javascript Lite</a></li>

+						<li><a href="manual_lite.html">log4javascript Lite manual</a></li>

+						<li><a href="../demos/basic.html">Basic demo</a></li>

+						<li><a href="../demos/ajax.html">Ajax demo</a></li>

+					</ul>

+				</div>

+				<div id="contents">

+					<h2>Contents</h2>

+					<ul>

+						<li><a href="#whatitis">What it is</a></li>

+						<li><a href="#whofor">Who it's for</a></li>

+						<li><a href="#previousversions">Note on previous versions</a></li>

+						<li><a href="#features">Features</a></li>

+						<li><a href="#browsers">Browser support</a></li>

+						<li><a href="#licence">Licence</a></li>

+						<li><a href="#furtherreading">Further reading</a></li>

+					</ul>

+				</div>

+				<div id="whatitis">

+					<h2>What it is</h2>

+					<p>

+						log4javascript is a JavaScript logging framework based on the Java

+						logging framework <a href="http://logging.apache.org/log4j/docs/index.html"

+						title="log4j home page (opens in new window)" target="_blank">log4j</a>.

+					</p>

+					<p>

+						log4javascript implements a subset of log4j (primarily loggers, appenders

+						and layouts) and has a few convenience methods of its own for

+						quick JavaScript development. It can be used to debug JavaScript

+						applications of all sizes, including Ajax applications.

+					</p>

+					<p>

+						If you just want to start using it, try the <a href="quickstart.html">quickstart

+						tutorial</a>.

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="whofor">

+					<h2>Who it's for</h2>

+					<p>

+						log4javascript is aimed at JavaScript developers.

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="previousversions">

+					<h2>Note on previous versions</h2>

+					<p>

+						Documentation for previous versions of log4javascript are not available here.

+						However, documentation is bundled with every previous version, all of which

+						are <a href="http://sourceforge.net/projects/log4javascript"

+							target="_blank" title="Download (opens in new window)">available to download</a>.

+					</p>

+				</div>

+				<div id="features">

+					<h2>Features</h2>

+					<ul>

+						<li>can be initialized with one JavaScript include and one line of code;</li>

+						<li>

+							by default logs to a pop-up console window with powerful search (including

+							regular expression) and filtering features. This console window can also

+							be used inline as an iframe in the main page;

+						</li>

+						<li>

+							can send log messages to the server via HTTP (Ajax, if you like);

+						</li>

+						<li>

+							highly configurable using familiar methods from log4j, including the

+							powerful <code><a href="manual.html#patternlayout">PatternLayout</a></code>

+							which gives the developer complete control over the format of the log messages.

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="browsers">

+					<h2>Browser support</h2>

+					<h3>Fully supported browsers:</h3>

+					<ul>

+						<li>All versions Firefox back to 0.6</li>

+						<li>Other Mozilla-based browsers, as far back as Netscape 7</li>

+						<li>Internet Explorer 5 and higher for Windows</li>

+						<li>Safari 1.3 and higher (untested on earlier versions)</li>

+						<li>Opera 8.01 and higher (pre- version 9 browsers have a rendering

+							bug related to scrolling that affects searching in PopUpAppender and InPageAppender)</li>

+						<li>Konqueror 3.4.3 and higher (untested on earlier versions)</li>

+						<li>Google Chrome</li>

+					</ul>

+					<h3>Partially supported browsers:</h3>

+					<ul>

+						<li>Older Mozilla-based browsers, e.g. Netscape 6.2 (generally OK except for

+							display problems searching and filtering PopUpAppender and InPageAppender)</li>

+						<li>Opera 7.0 - 8.0 (InPageAppender not supported until version 7.5, plus some display

+							problems searching PopUpAppender and InPageAppender. AjaxAppender not supported at all)</li>

+					</ul>

+					<h3>Unsupported browsers:</h3>

+					<ul>

+						<li>

+							Internet Explorer for Mac. There are no plans to make log4javascript work

+							in this browser.

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="licence">

+					<h2>Licence</h2>

+					<p>

+						log4javascript is licenced under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+							title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+						Version 2.0</a>. The Apache website has <a href="http://www.apache.org/foundation/licence-FAQ.html#WhatDoesItMEAN"

+							title="View licence (opens in new window)" target="_blank">more details</a>.

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="furtherreading">

+					<h2>Further reading</h2>

+					<p>

+						In order to gain an understanding of the ideas behind log4j and therefore log4javascript,

+						I highly recommend reading the <a href="http://logging.apache.org/log4j/docs/manual.html">short

+						introduction to log4j</a> from the log4j website. log4javascript borrows heavily from

+						log4j but does not carry over all its concepts - for example, Filters and Renderers are not

+						implemented.

+					</p>

+					<p>

+						<a href="manual.html">The full log4javascript manual</a>

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/lite.html b/planetstack/core/static/log4javascript-1.4.6/docs/lite.html
new file mode 100644
index 0000000..11b4684
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/docs/lite.html
@@ -0,0 +1,182 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en" >

+	<head>

+		<title>log4javascript 1.4 Lite</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+		<style type="text/css">

+			.visibleifabletocopy {

+				display: none;

+			}

+			

+			body.abletocopy .visibleifabletocopy {

+				display: block;

+			}

+		</style>

+		<script type="text/javascript">

+			function copyCode() {

+				if (window.clipboardData && clipboardData.setData) {

+					clipboardData.setData("Text", code);

+					alert("Code copied to clipboard.")

+				}

+			}

+			

+			var code;

+			

+			window.onload = function() {

+				var textArea = document.getElementById("codetextarea");

+				code = textArea.value;

+				textArea.select(); 

+				if (window.clipboardData && clipboardData.setData) {

+					document.body.className = "abletocopy";

+				}

+			};

+		</script>

+		<link rel="stylesheet" type="text/css" media="screen,print" href="lite.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="../index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="index.html">docs</a>

+					| <a class="navitem" href="quickstart.html">quick start</a>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript 1.4 Lite</h1>

+				<h2>Contents</h2>

+				<ul>

+					<li><a href="#intro">Introduction</a></li>

+					<li><a href="#code">Code</a></li>

+					<li><a href="#api">API</a></li>

+				</ul>

+				<div id="intro">

+					<h2>Introduction</h2>

+					<p>

+						log4javascript Lite is designed to be a basic, lightweight, cross-browser logging tool. It

+						provides functions to log messages of different severity to a pop-up window using the exactly

+						the same syntax as log4javascript.

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="code">

+					<h2>Code</h2>

+					<p>

+						You can copy the code for log4javascript Lite below:

+					</p>

+					<textarea id="codetextarea" cols="80" rows="10">

+if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}

+this.length--;return firstItem;}};}

+var log4javascript;(function(){var newLine="\r\n";function Log4JavaScript(){}

+log4javascript=new Log4JavaScript();log4javascript.version="1.4.6";log4javascript.edition="log4javascript_lite";function getExceptionMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}else{return String(ex);}}

+function getUrlFileName(url){var lastSlashIndex=Math.max(url.lastIndexOf("/"),url.lastIndexOf("\\"));return url.substr(lastSlashIndex+1);}

+function getExceptionStringRep(ex){if(ex){var exStr="Exception: "+getExceptionMessage(ex);try{if(ex.lineNumber){exStr+=" on line number "+ex.lineNumber;}

+if(ex.fileName){exStr+=" in file "+getUrlFileName(ex.fileName);}}catch(localEx){}

+if(showStackTraces&&ex.stack){exStr+=newLine+"Stack trace:"+newLine+ex.stack;}

+return exStr;}

+return null;}

+function isError(err){return(err instanceof Error);}

+function bool(obj){return Boolean(obj);}

+var enabled=(typeof log4javascript_disabled!="undefined")&&log4javascript_disabled?false:true;log4javascript.setEnabled=function(enable){enabled=bool(enable);};log4javascript.isEnabled=function(){return enabled;};var showStackTraces=false;log4javascript.setShowStackTraces=function(show){showStackTraces=bool(show);};var Level=function(level,name){this.level=level;this.name=name;};Level.prototype={toString:function(){return this.name;},equals:function(level){return this.level==level.level;},isGreaterOrEqual:function(level){return this.level>=level.level;}};Level.ALL=new Level(Number.MIN_VALUE,"ALL");Level.TRACE=new Level(10000,"TRACE");Level.DEBUG=new Level(20000,"DEBUG");Level.INFO=new Level(30000,"INFO");Level.WARN=new Level(40000,"WARN");Level.ERROR=new Level(50000,"ERROR");Level.FATAL=new Level(60000,"FATAL");Level.OFF=new Level(Number.MAX_VALUE,"OFF");log4javascript.Level=Level;function Appender(){var getConsoleHtmlLines=function(){return['<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">','<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">','<head>','<title>log4javascript</title>','<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />','<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->','<meta http-equiv="X-UA-Compatible" content="IE=7" />','<script type="text/javascript">','//<![CDATA[','var loggingEnabled=true;var messagesBeforeDocLoaded=[];function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}','function setLoggingEnabled(enable){loggingEnabled=enable;}','function scrollToLatestEntry(){var l=getLogContainer();if(typeof l.scrollTop!="undefined"){var latestLogEntry=l.lastChild;if(latestLogEntry){l.scrollTop=l.scrollHeight;}}}','function log(logLevel,formattedMessage){if(loggingEnabled){if(loaded){doLog(logLevel,formattedMessage);}else{messagesBeforeDocLoaded.push([logLevel,formattedMessage]);}}}','function doLog(logLevel,formattedMessage){var logEntry=document.createElement("div");logEntry.appendChild(document.createTextNode(formattedMessage));logEntry.className="logentry "+logLevel.name;getLogContainer().appendChild(logEntry);scrollToLatestEntry();}','function mainPageReloaded(){var separator=document.createElement("div");separator.className="separator";separator.innerHTML="&nbsp;";getLogContainer().appendChild(separator);}','var loaded=false;var logLevels=["DEBUG","INFO","WARN","ERROR","FATAL"];window.onload=function(){setLogContainerHeight();toggleLoggingEnabled();for(var i=0;i<messagesBeforeDocLoaded.length;i++){doLog(messagesBeforeDocLoaded[i][0],messagesBeforeDocLoaded[i][1]);}','messagesBeforeDocLoaded=[];loaded=true;setTimeout(setLogContainerHeight,20);};function getLogContainer(){return $("log");}','function clearLog(){getLogContainer().innerHTML="";}','function $(id){return document.getElementById(id);}','function getWindowHeight(){if(window.innerHeight){return window.innerHeight;}else if(document.documentElement&&document.documentElement.clientHeight){return document.documentElement.clientHeight;}else if(document.body){return document.body.clientHeight;}','return 0;}','function getChromeHeight(){return $("toolbar").offsetHeight;}','function setLogContainerHeight(){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";getLogContainer().style.height=""+','Math.max(0,windowHeight-getChromeHeight())+"px";}','window.onresize=function(){setLogContainerHeight();};','//]]>','</scr' + 'ipt>','<style type="text/css">','body{background-color:white;color:black;padding:0;margin:0;font-family:tahoma,verdana,arial,helvetica,sans-serif;overflow:hidden}div#toolbar{border-top:solid #ffffff 1px;border-bottom:solid #aca899 1px;background-color:#f1efe7;padding:3px 5px;font-size:68.75%}div#toolbar input.button{padding:0 5px;font-size:100%}div#log{font-family:Courier New,Courier;font-size:75%;width:100%;overflow:auto;clear:both}*.logentry{overflow:visible;white-space:pre}*.TRACE{color:#666666}*.DEBUG{color:green}*.INFO{color:#000099}*.WARN{color:#999900}*.ERROR{color:red}*.FATAL{color:#660066}div#log div.separator{background-color:#cccccc;margin:5px 0;line-height:1px}','</style>','</head>','<body id="body">','<div id="toolbar">','Options:','<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" class="stateful" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Enable logging</label>','<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="stateful button" title="Clear all log messages"  />','<input type="button" id="closeButton" value="Close" onclick="window.close()" class="stateful button" title="Close the window" />','</div>','<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>','</body>','</html>'];};var popUp=null;var popUpsBlocked=false;var popUpClosed=false;var popUpLoaded=false;var complainAboutPopUpBlocking=true;var initialized=false;var isSupported=true;var width=600;var height=400;var focusPopUp=false;var queuedLoggingEvents=new Array();function isLoaded(win){try{return bool(win.loaded);}catch(ex){return false;}}

+function finalInit(){popUpLoaded=true;appendQueuedLoggingEvents();}

+function writeHtml(doc){var lines=getConsoleHtmlLines();doc.open();for(var i=0,len=lines.length;i<len;i++){doc.writeln(lines[i]);}

+doc.close();}

+function pollConsoleWindow(){function pollConsoleWindowLoaded(){if(popUpLoaded){clearInterval(poll);}else if(bool(popUp)&&isLoaded(popUp)){clearInterval(poll);finalInit();}}

+var poll=setInterval(pollConsoleWindowLoaded,100);}

+function init(){var windowProperties="width="+width+",height="+height+",status,resizable";var windowName="log4javascriptLitePopUp"+location.host.replace(/[^a-z0-9]/gi,"_");popUp=window.open("",windowName,windowProperties);popUpClosed=false;if(popUp){if(isLoaded(popUp)){popUp.mainPageReloaded();finalInit();}else{writeHtml(popUp.document);if(isLoaded(popUp)){finalInit();}else{pollConsoleWindow();}}}else{isSupported=false;if(complainAboutPopUpBlocking){alert("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");}}

+initialized=true;}

+function safeToAppend(){if(!popUpsBlocked&&!popUpClosed){if(popUp.closed){popUpClosed=true;return false;}

+if(!popUpLoaded&&popUp.loaded){popUpLoaded=true;}}

+return!popUpsBlocked&&popUpLoaded&&!popUpClosed;}

+function padWithZeroes(num,len){var str=""+num;while(str.length<len){str="0"+str;}

+return str;}

+function padWithSpaces(str,len){while(str.length<len){str+=" ";}

+return str;}

+this.append=function(loggingEvent){if(!initialized){init();}

+queuedLoggingEvents.push(loggingEvent);if(safeToAppend()){appendQueuedLoggingEvents();}};function appendQueuedLoggingEvents(){if(safeToAppend()){while(queuedLoggingEvents.length>0){var currentLoggingEvent=queuedLoggingEvents.shift();var date=currentLoggingEvent.timeStamp;var formattedDate=padWithZeroes(date.getHours(),2)+":"+

+padWithZeroes(date.getMinutes(),2)+":"+padWithZeroes(date.getSeconds(),2);var formattedMessage=formattedDate+" "+padWithSpaces(currentLoggingEvent.level.name,5)+" - "+currentLoggingEvent.getCombinedMessages();var throwableStringRep=currentLoggingEvent.getThrowableStrRep();if(throwableStringRep){formattedMessage+=newLine+throwableStringRep;}

+popUp.log(currentLoggingEvent.level,formattedMessage);}

+if(focusPopUp){popUp.focus();}}}}

+log4javascript.Appender=Appender;function Logger(){var appender=new Appender();var loggerLevel=Level.ALL;this.log=function(level,params){if(enabled&&level.isGreaterOrEqual(this.getLevel())){var exception;var finalParamIndex=params.length-1;var lastParam=params[params.length-1];if(params.length>1&&isError(lastParam)){exception=lastParam;finalParamIndex--;}

+var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];}

+var loggingEvent=new LoggingEvent(this,new Date(),level,messages,exception);appender.append(loggingEvent);}};this.setLevel=function(level){loggerLevel=level;};this.getLevel=function(){return loggerLevel;};}

+Logger.prototype={trace:function(){this.log(Level.TRACE,arguments);},debug:function(){this.log(Level.DEBUG,arguments);},info:function(){this.log(Level.INFO,arguments);},warn:function(){this.log(Level.WARN,arguments);},error:function(){this.log(Level.ERROR,arguments);},fatal:function(){this.log(Level.FATAL,arguments);},isEnabledFor:function(level){return level.isGreaterOrEqual(this.getLevel());},isTraceEnabled:function(){return this.isEnabledFor(Level.TRACE);},isDebugEnabled:function(){return this.isEnabledFor(Level.DEBUG);},isInfoEnabled:function(){return this.isEnabledFor(Level.INFO);},isWarnEnabled:function(){return this.isEnabledFor(Level.WARN);},isErrorEnabled:function(){return this.isEnabledFor(Level.ERROR);},isFatalEnabled:function(){return this.isEnabledFor(Level.FATAL);}};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=new Logger();}

+return defaultLogger;};log4javascript.getLogger=log4javascript.getDefaultLogger;var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger();nullLogger.setLevel(Level.OFF);}

+return nullLogger;};var LoggingEvent=function(logger,timeStamp,level,messages,exception){this.logger=logger;this.timeStamp=timeStamp;this.level=level;this.messages=messages;this.exception=exception;};LoggingEvent.prototype={getThrowableStrRep:function(){return this.exception?getExceptionStringRep(this.exception):"";},getCombinedMessages:function(){return(this.messages.length===1)?this.messages[0]:this.messages.join(newLine);}};log4javascript.LoggingEvent=LoggingEvent;window.log4javascript=log4javascript;})();

+</textarea>

+					<p class="visibleifabletocopy">

+						Press this button to copy the code to the clipboard:

+						<input type="button" value="Copy" onclick="copyCode()" />

+					</p>

+					<p>

+						You can either paste the above code inside a script tag:

+					</p>

+					<pre class="code">

+&lt;script type="text/javascript"&gt;

+	... [Code here]...

+&lt;/script&gt;

+</pre>

+					<p>

+						 ... or include the <code>log4javascript_lite.js</code> included in the distribution:

+					</p>

+					<pre class="code">

+&lt;script type="text/javascript" src="log4javascript_lite.js"&gt;&lt;/script&gt;

+</pre>

+					<pre class="code">

+&lt;script type="text/javascript"&gt;

+	var log = log4javascript.getDefaultLogger();

+&lt;/script&gt;

+</pre>

+					<p>

+						Using log4javascript Lite is identical to using log4javascript with its default logger:

+					</p>

+					<pre class="code">

+&lt;script type="text/javascript"&gt;

+	var log = log4javascript.getDefaultLogger();

+	log.debug("What's going on here then?");

+&lt;/script&gt;

+</pre>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="api">

+					<h2>API</h2>

+					<p>

+						The functions available in log4javascript Lite make up a small subset of those provided

+						by log4javascript proper. Each function is <strong>named and called identically to the equivalent

+						function in log4javascript</strong>. Full details can be found in the

+						<a href="manual_lite.html">log4javascript Lite manual</a>.

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/manual.html b/planetstack/core/static/log4javascript-1.4.6/docs/manual.html
new file mode 100644
index 0000000..defac9c
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/docs/manual.html
@@ -0,0 +1,3198 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript 1.4 manual</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="index.html">docs</a>

+					| <a class="navitem" href="quickstart.html">quick start</a>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript 1.4 manual</h1>

+				<h2>Contents</h2>

+				<ul>

+					<li><a href="#intro">Introduction</a></li>

+					<li><a href="#noteaboutlog4javascript">Note about the log4javascript object</a></li>

+					<li>

+						<a href="#loggersappenderslayoutslevels">Loggers, appenders, layouts and levels</a>

+						<ul>

+							<li><a href="#configuration">Configuring appenders</a></li>

+							<li><a href="#loggersappenderslayoutslevelsexample">Example</a></li>

+						</ul>

+					</li>

+					<li><a href="#log4javascript">log4javascript static properties/methods</a></li>

+					<li><a href="#levels">Levels</a></li>

+					<li><a href="#loggers">Loggers</a></li>

+					<li>

+						<a href="#appenders">Appenders</a>

+						<ul>

+							<li><a href="#appender">Appender</a></li>

+							<li><a href="#alertappender">AlertAppender</a></li>

+							<li><a href="#ajaxappender">AjaxAppender</a></li>

+							<li><a href="#popupappender">PopUpAppender</a></li>

+							<li><a href="#inpageappender">InPageAppender</a></li>

+							<li><a href="#browserconsoleappender">BrowserConsoleAppender</a></li>

+						</ul>

+					</li>

+					<li>

+						<a href="#layouts">Layouts</a>

+						<ul>

+							<li><a href="#layout">Layout</a></li>

+							<li><a href="#nulllayout">NullLayout</a></li>

+							<li><a href="#simplelayout">SimpleLayout</a></li>

+							<li><a href="#patternlayout">PatternLayout</a></li>

+							<li><a href="#xmllayout">XmlLayout</a></li>

+							<li><a href="#jsonlayout">JsonLayout</a></li>

+							<li><a href="#httppostdatalayout">HttpPostDataLayout</a></li>

+						</ul>

+					</li>

+					<li><a href="#enabling">Enabling / disabling log4javascript</a></li>

+					<li>

+						<a href="#errorhandling">log4javascript error handling</a>

+						<ul>

+							<li><a href="#loglog">LogLog</a></li>

+						</ul>

+					</li>

+					<li><a href="#differences">Differences between log4javascript and log4j</a></li>

+				</ul>

+				<div id="intro">

+					<h2>Introduction</h2>

+					<p>

+						Anyone who has done a reasonable amount of JavaScript development will be

+						familiar with <code>alert</code> as a means of debugging. For

+						a small script, it works fine. But for anything of greater complexity than,

+						say, a rollover script its shortcomings become apparent. The most obvious problem

+						is the endless clicking of 'OK'. Another problem is that for a page

+						heavily reliant on events generated from user actions, alerts

+						can actually alter the way the page behaves. One final problem is infinite loops:

+						without alerts, the browser will notice that the script has messed

+						up and will offer the user the chance to stop the script running. With an

+						alert inside an infinite loop, you're forced to kill the browser.

+					</p>

+					<p>

+						At the other end of the scale there is

+						<a href="http://www.mozilla.org/projects/venkman/" target="_blank">Venkman</a>,

+						a full-on JavaScript debugger for Mozilla-based browsers such as Firefox. Here

+						I have to confess that I simply have not put in the time to learn how to make

+						it work well for me and I suspect I am not alone.

+					</p>

+					<p>

+						Nowadays, easily the best option for day-to-day JavaScript development is the brilliant

+						<a href="http://www.getfirebug.com" title="Firebug home page (opens in new window)"

+						   target="_blank">Firebug</a>, a Firefox plugin with built-in debugger, console, logging,

+						and profiler. It's a seriously impressive tool but by its very nature as a Firefox

+						plugin can only be used in one of the typical target browsers for mainstream web

+						development.

+					</p>

+					<p>

+						log4javascript was originally written as a cross-browser tool to ease the pain of JavaScript

+						debugging without the time investment required to use a debugger effectively. It requires

+						only a JavaScript include and one line of code to initialize with default settings.

+						Having for several years used log4j and its .NET port log4net, it was natural for me to

+						base it on log4j.

+					</p>

+					<p>

+						log4javascript is by no means the only JavaScript logging framework out there.

+						It is not even the only JavaScript implementation of log4j. It turns out the name

+						log4javascript is used by another JavaScript logging framework, and that the name log4js is

+						used by at least two other pieces of software; this version of log4javascript is unrelated

+						to any of those.

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="noteaboutlog4javascript">

+					<h2>Note about the log4javascript object</h2>

+					<p>

+						All of log4javascript's instantiable classes are accessible via the log4javascript object, which

+						acts as a namespace. Therefore references to all class names must be preceded with "log4javascript.".

+						For example:

+					</p>

+					<p>

+						<code>var popUpAppender = new log4javascript.PopUpAppender();</code>

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="loggersappenderslayoutslevels">

+					<h2>Loggers, Appenders, Layouts and Levels</h2>

+					<p>

+						A <em>logger</em> in log4javascript is the object on which log calls are

+						made. A logger may be assigned zero or more <em>appenders</em>.

+						An appender is an object that actually does the logging: for example,

+						a <code><a href="#popupappender">PopUpAppender</a></code> logs messages to

+						a pop-up console window while an <code><a href="#ajaxappender">AjaxAppender</a></code>

+						uses HTTP to send log messages back to the server. Each appender is assigned

+						a <em>layout</em>, which is responsible for formatting log messages that

+						are passed to an appender.

+					</p>

+					<p>

+						Every log message has a <em>level</em>. This is the severity of the message.

+						Available levels are <code>TRACE</code>, <code>DEBUG</code>, <code>INFO</code>,

+						<code>WARN</code>, <code>ERROR</code> and <code>FATAL</code> - these correspond to

+						the logging methods <code>trace</code>, <code>debug</code>, <code>info</code>,

+						<code>warn</code>, <code>error</code> and <code>fatal</code> of <code>Logger</code>.

+						Levels are ordered as follows: <code>TRACE</code> &lt; <code>DEBUG</code> &lt;

+						<code>INFO</code> &lt; <code>WARN</code> &lt; <code>ERROR</code> &lt;

+						<code>FATAL</code>. This means the <code>FATAL</code> is the most severe and

+						<code>TRACE</code> the least. Also included are levels called <code>ALL</code>

+						and <code>OFF</code> intended to enable or disable all logging respectively.

+					</p>

+					<p>

+						Both loggers and appenders also have threshold levels (by default, <code>DEBUG</code>

+						for loggers and <code>ALL</code> for appenders).

+						Setting a level to either a logger or an appender disables log messages of severity

+						lower than that level. For instance, if a level of <code>INFO</code> is set on a

+						logger then only log messages of severity <code>INFO</code> or greater will be logged,

+						meaning <code>DEBUG</code> and <code>TRACE</code> messages will not be logged. If the

+						same logger had two appenders, one of level <code>DEBUG</code> and one of level

+						<code>WARN</code> then the first appender will still only log messages of

+						<code>INFO</code> or greater while the second appender will only log messages of level

+						<code>WARN</code> or greater.

+					</p>

+					<p>

+						This allows the developer fine control over which messages get logged where.

+					</p>

+					<div id="configuration">

+						<h3>Configuring appenders</h3>

+						<p>

+							From version 1.4, <strong>configuring appenders is only possible via configuration

+							methods</strong>. As the number of configuration options increases it becomes increasingly

+							undesirable to use constructor parameters, so support for it has been dropped.

+						</p>

+					</div>

+					<div id="loggersappenderslayoutslevelsexample">

+						<h3>Example</h3>

+						<p>

+							<strong>NB.</strong> The Ajax side of this example relies on having

+							server-side processing in place.

+						</p>

+						<p>

+							First, log4javascript is initialized, and a logger (actually the

+							anonymous logger) is assigned to a variable called <code>log</code>:

+						</p>

+						<pre class="code">

+&lt;script type="text/javascript" src="log4javascript.js"&gt;&lt;/script&gt;

+&lt;script type="text/javascript"&gt;

+	//&lt;![CDATA[

+	var log = log4javascript.getLogger();

+</pre>

+						<p>

+							<code>log</code> does not yet have any appenders, so a call to <code>log.debug()</code>

+							will do nothing as yet. For this example we will use a

+							<code><a href="#popupappender">PopUpAppender</a></code> for debugging purposes.

+							Since the lifespan of the messages displayed in the pop-up is only going to be the

+							same as that of the window, a <code><a href="#patternlayout">PatternLayout</a></code>

+							is used that displays the time of the message and not the date (note that this is

+							also true of PopUpAppender's default layout). The format of the string passed into

+							PatternLayout is explained <a href="#patternlayout">below</a>.

+						</p>

+						<pre class="code">

+	var popUpAppender = new log4javascript.PopUpAppender();

+	var popUpLayout = new log4javascript.PatternLayout("%d{HH:mm:ss} %-5p - %m%n");

+	popUpAppender.setLayout(popUpLayout);

+	log.addAppender(popUpAppender);

+</pre>

+						<p>

+							Suppose that we also want to send log messages to the server, but limited to

+							error messages only. To achieve this we use an

+							<code><a href="#ajaxappender">AjaxAppender</a></code>. Note that if no layout is

+							specified then for convenience a default layout is used; in the case of

+							AjaxAppender, that is <code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>,

+							which formats log messages as a standard HTTP POST string from which a simple

+							server-side script (not provided with log4javascript) will be able to extract

+							posted parameters. This is fine for our purposes:

+						</p>

+						<pre class="code">

+	var ajaxAppender = new log4javascript.AjaxAppender("myloggingservlet.do");

+	ajaxAppender.setThreshold(log4javascript.Level.<code>ERROR</code>);

+	log.addAppender(ajaxAppender);

+</pre>

+						<p>

+							Finally, some test log messages and the closing script tag:

+						</p>

+						<pre class="code">

+	log.debug("Debugging message (appears in pop-up)");

+	log.error("Error message (appears in pop-up and in server log)");

+	//]]&gt;

+&lt;/script&gt;

+</pre>

+						<p>

+							The full script:

+						</p>

+						<pre class="code">

+&lt;script type="text/javascript" src="log4javascript.js"&gt;&lt;/script&gt;

+&lt;script type="text/javascript"&gt;

+	//&lt;![CDATA[

+	var log = log4javascript.getLogger();

+	var popUpAppender = new log4javascript.PopUpAppender();

+	var popUpLayout = new log4javascript.PatternLayout("%d{HH:mm:ss} %-5p - %m%n");

+	popUpAppender.setLayout(popUpLayout);

+	log.addAppender(popUpAppender);

+	var ajaxAppender = new log4javascript.AjaxAppender("myloggingservlet.do");

+	ajaxAppender.setThreshold(log4javascript.Level.ERROR);

+	log.addAppender(ajaxAppender);

+	log.debug("Debugging message (appears in pop-up)");

+	log.error("Error message (appears in pop-up and in server log)");

+	//]]&gt;

+&lt;/script&gt;

+</pre>

+						<p>

+							<a href="../examples/example_manual.html" title="View example (opens in new window)"

+								target="_blank">See this example in action</a> (opens in new window)

+						</p>

+					</div>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="log4javascript">

+					<h2>log4javascript static properties/methods</h2>

+					<h4>Properties</h4>

+					<ul class="propertieslist">

+						<li class="property">

+							<div class="name">version</div>

+							<div class="summary">

+								The version number of your copy of log4javascript.

+							</div>

+						</li>

+						<li class="property">

+							<div class="name">edition</div>

+							<div class="summary">

+								The edition of your copy of log4javascript.

+							</div>

+						</li>

+						<li class="property">

+							<div class="name">logLog</div>

+							<div class="summary">

+								log4javascript's internal logging object. <a href="#loglog">See below for more details</a>.

+							</div>

+						</li>

+					</ul>

+					<h4>Methods</h4>

+					<ul class="propertieslist">

+						<li class="method">

+							<div class="name">getLogger</div>

+							<div class="methodsignature"><code>Logger <strong>getLogger</strong>([String <em>loggerName</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">loggerName</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								<p>

+									Returns a logger with the specified name, creating it if a logger with that name does not

+									already exist. If no name is specified, a logger is returned with name <code>[anonymous]</code>, and

+									subsequent calls to <code>getLogger()</code> (with no logger name specified) will return

+									this same logger object.

+								</p>

+								<p>

+									Note that the names <code>[anonymous]</code>, <code>[default]</code>, <code>[null]</code>

+									and <code>root</code> are reserved for

+									the anonymous logger, default logger, null logger and root logger respectively.

+								</p>

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getDefaultLogger</div>

+							<div class="methodsignature"><code>Logger <strong>getDefaultLogger</strong>()</code></div>

+							<div class="summary">

+								Convenience method that returns the default logger. The default logger

+								has a single appender: a <code><a href="#popupappender">PopUpAppender</a></code>

+								with the default layout, width and height, and with <code>focusPopUp</code> set to false

+								and <code>lazyInit</code>, <code>useOldPopUp</code> and

+								<code>complainAboutPopUpBlocking</code> all set to true.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getNullLogger</div>

+							<div class="methodsignature"><code>Logger <strong>getNullLogger</strong>()</code></div>

+							<div class="summary">

+								Returns an empty logger with no appenders. Useful for disabling all logging.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getRootLogger</div>

+							<div class="methodsignature"><code>Logger <strong>getRootLogger</strong>()</code></div>

+							<div class="summary">

+								Returns the root logger from which all other loggers derive.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">resetConfiguration</div>

+							<div class="methodsignature"><code>void <strong>resetConfiguration</strong>()</code></div>

+							<div class="summary">

+								Resets the all loggers to their default level.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">setEnabled</div>

+							<div class="methodsignature"><code>void <strong>setEnabled</strong>(Boolean <em>enabled</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">enabled</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Enables or disables all logging, depending on <code>enabled</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns true or false depending on whether logging is enabled.

+							</div>

+						</li>

+						<li class="method" id="log4javascriptaddeventlistener">

+							<div class="name">addEventListener</div>

+							<div class="methodsignature"><code>void <strong>addEventListener</strong>(String <em>eventType</em>, Function <em>listener</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">eventType</code>

+								</li>

+								<li class="param">

+									<code class="paramname">listener</code>

+								</li>

+							</ul>

+							<div class="summary">

+								<p>

+									Adds a function to be called when an event of the type specified occurs in log4javascript.

+									Supported event types are <code>load</code> (occurs once the page has loaded) and

+									<code>error</code>.

+								</p>

+								<p>

+									Each listener is pased three paramaters:

+								</p>

+								<ul>

+									<li><code>sender</code>. The object that raised the event (i.e. the log4javascript object);</li>

+									<li><code>eventType</code>. The type of the event;</li>

+									<li>

+										<code>eventArgs</code>. An object containing of event-specific arguments. For the <code>error</code> event,

+										this is an object with properties <code>message</code> and <code>exception</code>. For the <code>load</code>

+										event this is an empty object.

+									</li>

+								</ul>

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">removeEventListener</div>

+							<div class="methodsignature"><code>void <strong>removeEventListener</strong>(String <em>eventType</em>, Function <em>listener</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">eventType</code>

+								</li>

+								<li class="param">

+									<code class="paramname">listener</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Removes the event listener function supplied for the event of the type specified.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">dispatchEvent</div>

+							<div class="methodsignature"><code>void <strong>dispatchEvent</strong>(String <em>eventType</em>, Object <em>eventArgs</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">eventType</code>

+								</li>

+								<li class="param">

+									<code class="paramname">eventArgs</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Raises an event of type <code>eventType</code> on the <code>log4javascript</code> object.

+								Each of the listeners for this type of event (registered via <code>addEventListener</code>)

+								is called and passed <code>eventArgs</code> as the third parameter.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">setEventTypes</div>

+							<div class="methodsignature"><code>void <strong>setEventTypes</strong>(Array <em>eventTypes</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">eventTypes</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Used internally to specify the types of events that the <code>log4javascript</code> object can raise.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">setShowStackTraces</div>

+							<div class="methodsignature"><code>void <strong>setShowStackTraces</strong>(Boolean <em>show</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">show</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Enables or disables displaying of error stack traces, depending on <code>show</code>.

+								By default, stack traces are not displayed. (Only works in Firefox)

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">evalInScope</div>

+							<div class="methodsignature"><code>Object <strong>evalInScope</strong>(String <em>expr</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">expr</code>

+								</li>

+							</ul>

+							<div class="summary">

+								This evaluates the given expression in the log4javascript scope, thus allowing

+								scripts to access internal log4javascript variables and functions. This was written

+								for the purposes of automated testing but could be used by custom extensions to

+								log4javascript.

+							</div>

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="levels">

+					<h2>Levels</h2>

+					<p>

+						Levels are available as static properties of the <code>log4javascript.Level</code>

+						object. In ascending order of severity:

+					</p>

+					<ol>

+						<li><code>log4javascript.Level.ALL</code></li>

+						<li><code>log4javascript.Level.TRACE</code></li>

+						<li><code>log4javascript.Level.DEBUG</code></li>

+						<li><code>log4javascript.Level.INFO</code></li>

+						<li><code>log4javascript.Level.WARN</code></li>

+						<li><code>log4javascript.Level.ERROR</code></li>

+						<li><code>log4javascript.Level.FATAL</code></li>

+						<li><code>log4javascript.Level.OFF</code></li>

+					</ol>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="loggers">

+					<h2>Loggers</h2>

+					<p>

+						It is possible to have multiple loggers in log4javascript. For example, you

+						may wish to have a logger for debugging purposes that logs messages to a

+						pop-up window and a separate logger that reports any client-side application

+						errors to the server via Ajax.

+					</p>

+					<div id="loggerhierarchy">

+						<h3>Logger hierarchy and appender additivity</h3>

+						<p>

+							From version 1.4, log4javascript has hierarchical loggers, implemented in the same way

+							as log4j. In summary, you specify a logger's parent logger by means of a dot between the

+							parent logger name and the child logger name. Therefore the logger <code>tim.app.security</code>

+							inherits from <code>tim.app</code>, which in turn inherits from <code>tim</code> which,

+							finally, inherits from the root logger.

+						</p>

+						<p>

+							What inheritance means for a logger is that in the absence of a threshold level set

+							specifically on the logger it inherits its level from its parent; also, a logger inherits

+							all its parent's appenders (this is known as <em>appender additivity</em> in log4j. This

+							behaviour can be enabled or disabled via <code>setAdditivity()</code>. See below). In the

+							above example, if the root logger has a level of <code>DEBUG</code> and one appender,

+							each of the loggers <code>tim.app.security</code>, <code>tim.app</code> and <code>tim</code> would

+							inherit the root level's appender. If, say, <code>tim.app</code>'s threshold level was set

+							to <code>WARN</code>, <code>tim</code>'s effective level would remain at <code>DEBUG</code>

+							(inherited from the root logger) while <code>tim.app.security</code>'s effective level would

+							be <code>WARN</code>, inherited from <code>tim.app</code>. The important thing to note is

+							that appenders accumulate down the logger hierarchy while levels are simply inherited from

+							the nearest ancestor with a threshold level set.

+						</p>

+						<p>

+							For a detailed explanation of the logger hierarchy, see the

+							<a href="http://logging.apache.org/log4j/docs/manual.html" target="_blank"

+							   title="Log4j manual (opens in new window)">log4j manual</a>.

+						</p>

+					</div>

+					<p><strong>Notes</strong></p>

+					<ul>

+						<li>

+							It is not possible to instantiate loggers directly. Instead you must use

+							one of the methods of the <code>log4javascript</code> object: <code>getLogger</code>,

+							<code>getRootLogger</code>, <code>getDefaultLogger</code> or <code>getNullLogger</code>.

+						</li>

+					</ul>

+					<h4>Logger methods</h4>

+					<ul class="propertieslist">

+						<li class="method">

+							<div class="name">addAppender</div>

+							<div class="methodsignature"><code>void <strong>addAppender</strong>(Appender <em>appender</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">appender</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Adds the given appender.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">removeAppender</div>

+							<div class="methodsignature"><code>void <strong>removeAppender</strong>(Appender <em>appender</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">appender</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Removes the given appender.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">removeAllAppenders</div>

+							<div class="methodsignature"><code>void <strong>removeAllAppenders</strong>()</code></div>

+							<div class="summary">

+								Clears all appenders for the current logger.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">setLevel</div>

+							<div class="methodsignature"><code>void <strong>setLevel</strong>(Level <em>level</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">level</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Sets the level. Log messages of a lower level than <code>level</code> will not be logged.

+								Default value is <code>DEBUG</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getLevel</div>

+							<div class="methodsignature"><code>Level <strong>getLevel</strong>()</code></div>

+							<div class="summary">

+								Returns the level explicitly set for this logger or <code>null</code> if none has been set.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getEffectiveLevel</div>

+							<div class="methodsignature"><code>Level <strong>getEffectiveLevel</strong>()</code></div>

+							<div class="summary">

+								Returns the level at which the logger is operating. This is either the level explicitly

+								set on the logger or, if no level has been set, the effective level of the logger's parent.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">setAdditivity</div>

+							<div class="methodsignature"><code>void <strong>setAdditivity</strong>(Boolean <em>additivity</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">additivity</code>

+								</li>

+							</ul>

+							<div class="summary">

+								<p>

+									Sets whether appender additivity is enabled (the default) or disabled. If set to false, this

+									particular logger will not inherit any appenders form its ancestors. Any descendant of this

+									logger, however, will inherit from its ancestors as normal, unless its own additivity is

+									explicitly set to false.

+								</p>

+								<p>

+									Default value is <code>true</code>.

+								</p>

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getAdditivity</div>

+							<div class="methodsignature"><code>Level <strong>getLevel</strong>()</code></div>

+							<div class="summary">

+								Returns whether additivity is enabled for this logger.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">log</div>

+							<div class="methodsignature"><code>void <strong>log</strong>(Level <em>level</em>, Object <em>params</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">level</code>

+								</li>

+								<li class="param">

+									<code class="paramname">params</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Generic logging method used by wrapper methods such as <code>debug</code>,

+								<code>error</code> etc.

+							</div>

+							<p><strong>Notes</strong></p>

+							<ul>

+								<li>

+									The signature of this method has changed in 1.4.

+								</li>

+							</ul>

+						</li>

+						<li class="method">

+							<div class="name">trace</div>

+							<div class="methodsignature"><code>void <strong>trace</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>TRACE</code>.

+							</div>

+							<p><strong>Notes</strong></p>

+							<ul>

+								<li>

+									Logging of multiple messages in one call is new in 1.4.

+								</li>

+							</ul>

+						</li>

+						<li class="method">

+							<div class="name">debug</div>

+							<div class="methodsignature"><code>void <strong>debug</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>DEBUG</code>.

+							</div>

+							<p><strong>Notes</strong></p>

+							<ul>

+								<li>

+									Logging of multiple messages in one call is new in 1.4.

+								</li>

+							</ul>

+						</li>

+						<li class="method">

+							<div class="name">info</div>

+							<div class="methodsignature"><code>void <strong>info</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>INFO</code>.

+							</div>

+							<p><strong>Notes</strong></p>

+							<ul>

+								<li>

+									Logging of multiple messages in one call is new in 1.4.

+								</li>

+							</ul>

+						</li>

+						<li class="method">

+							<div class="name">warn</div>

+							<div class="methodsignature"><code>void <strong>warn</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>WARN</code>.

+							</div>

+							<p><strong>Notes</strong></p>

+							<ul>

+								<li>

+									Logging of multiple messages in one call is new in 1.4.

+								</li>

+							</ul>

+						</li>

+						<li class="method">

+							<div class="name">error</div>

+							<div class="methodsignature"><code>void <strong>error</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>ERROR</code>.

+							</div>

+							<p><strong>Notes</strong></p>

+							<ul>

+								<li>

+									Logging of multiple messages in one call is new in 1.4.

+								</li>

+							</ul>

+						</li>

+						<li class="method">

+							<div class="name">fatal</div>

+							<div class="methodsignature"><code>void <strong>fatal</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>FATAL</code>.

+							</div>

+							<p><strong>Notes</strong></p>

+							<ul>

+								<li>

+									Logging of multiple messages in one call is new in 1.4.

+								</li>

+							</ul>

+						</li>

+						<li class="method">

+							<div class="name">isEnabledFor</div>

+							<div class="methodsignature"><code>Boolean <strong>isEnabledFor</strong>(Level <em>level</em>, Error <em>exception</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">level</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Returns whether the logger is enabled for the specified level. 

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isTraceEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isTraceEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>TRACE</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isDebugEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isDebugEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>DEBUG</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isInfoEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isInfoEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>INFO</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isWarnEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isWarnEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>WARN</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isErrorEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isErrorEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>ERROR</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isFatalEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isFatalEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>FATAL</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">group</div>

+							<div class="methodsignature"><code>void <strong>group</strong>(String <em>name</em>, Boolean <em>initiallyExpanded</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">name</code>

+								</li>

+								<li class="param">

+									<code class="paramname">initiallyExpanded</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Starts a new group of log messages. In appenders that support grouping (currently

+								<code><a href="#popupappender">PopUpAppender</a></code> and

+								<code><a href="#inpageappender">InPageAppender</a></code>), a group appears as an expandable

+								section in the console, labelled with the <code>name</code> specified.

+								Specifying <code>initiallyExpanded</code> determines whether the

+								group starts off expanded (the default is <code>true</code>). Groups may be nested.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">groupEnd</div>

+							<div class="methodsignature"><code>void <strong>groupEnd</strong>()</code></div>

+							<div class="summary">

+								Ends the current group. If there is no group then this function has no effect.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">time</div>

+							<div class="methodsignature"><code>void <strong>time</strong>(String <em>name</em>, Level <em>level</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">name</code>

+								</li>

+								<li class="param">

+									<code class="paramname">level</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Starts a timer with name <code>name</code>. When the timer is ended with a

+								call to <code>timeEnd</code> using the same name, the amount of time that

+								has elapsed in milliseconds since the timer was started is logged at level

+								<code>level</code>. If not level is supplied, the level defaults to <code>INFO</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">timeEnd</div>

+							<div class="methodsignature"><code>void <strong>timeEnd</strong>(String <em>name</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">name</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Ends the timer with name <code>name</code> and logs the time elapsed.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">assert</div>

+							<div class="methodsignature"><code>void <strong>assert</strong>(Object <em>expr</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">expr</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Asserts the given expression is <code>true</code> or evaluates to <code>true</code>.

+								If so, nothing is logged. If not, an error is logged at the <code>ERROR</code> level.

+							</div>

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="appenders">

+					<h2>Appenders</h2>

+					<div id="appender">

+						<h3>Appender</h3>

+						<p>

+							There are methods common to all appenders, as listed below.

+						</p>

+						<h4>Methods</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">doAppend</div>

+								<div class="methodsignature"><code>void <strong>doAppend</strong>(LoggingEvent <em>loggingEvent</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">loggingEvent</code>

+									</li>

+								</ul>

+								<div class="summary">

+									<p>

+										Checks the logging event's level is at least as severe as the appender's

+										threshold and calls the appender's <code>append</code> method if so.

+									</p>

+									<p>

+										This method should not in general be used directly or overridden.

+									</p>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">append</div>

+								<div class="methodsignature"><code>void <strong>append</strong>(LoggingEvent <em>loggingEvent</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">loggingEvent</code>

+									</li>

+								</ul>

+								<div class="summary">

+									Appender-specific method to append a log message. Every appender object should implement

+									this method.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setLayout</div>

+								<div class="methodsignature"><code>void <strong>setLayout</strong>(Layout <em>layout</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">layout</code>

+									</li>

+								</ul>

+								<div class="summary">

+									Sets the appender's layout.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getLayout</div>

+								<div class="methodsignature"><code>Layout <strong>getLayout</strong>()</code></div>

+								<div class="summary">

+									Returns the appender's layout.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setThreshold</div>

+								<div class="methodsignature"><code>void <strong>setThreshold</strong>(Level <em>level</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">level</code>

+									</li>

+								</ul>

+								<div class="summary">

+									Sets the appender's threshold. Log messages of level less severe than this

+									threshold will not be logged.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getThreshold</div>

+								<div class="methodsignature"><code>Level <strong>getThreshold</strong>()</code></div>

+								<div class="summary">

+									Returns the appender's threshold.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">toString</div>

+								<div class="methodsignature"><code>string <strong>toString</strong>()</code></div>

+								<div class="summary">

+									Returns a string representation of the appender. Every appender object should implement

+									this method.

+								</div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="alertappender">

+						<h3>AlertAppender</h3>

+						<p class="editions">Editions: <strong>Standard</strong></p>

+						<p>

+							Displays a log message as a JavaScript alert.

+						</p>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">AlertAppender</div>

+								<div class="methodsignature"><code><strong>AlertAppender</strong>()</code></div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="ajaxappender">

+						<h3>AjaxAppender</h3>

+						<p class="editions">Editions: <strong>Standard, Production</strong></p>

+						<p>

+							A flexible appender that asynchronously  sends log messages to a server via HTTP

+							(Ajax, if you insist, though the 'x' of Ajax only comes into play in any form if you use an

+							<code><a href="#xmllayout">XmlLayout</a></code>).

+						</p>

+						<p>

+							The default configuration is to send each log message as a separate HTTP post

+							request to the server using an <code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>,

+							without waiting for a response before sending any subsequent requests. However,

+							an <code>AjaxAppender</code> may be configured to do any one of or combinations of the following:

+						</p>

+						<ul>

+							<li>

+								send log messages in batches (if the selected layout supports it - particularly suited

+								to <code>AjaxAppender</code> are <code><a href="#jsonlayout">JsonLayout</a></code> and

+								<code><a href="#xmllayout">XmlLayout</a></code>, both of which allow batching);

+							</li>

+							<li>

+								wait for a response from a previous request before sending the next log message / batch

+								of messages;

+							</li>

+							<li>

+								send all queued log messages at timed intervals.

+							</li>

+						</ul>

+						<p><strong>Notes</strong></p>

+						<ul>

+							<li>

+								AjaxAppender relies on the <code>XMLHttpRequest</code> object. It also requires

+								the presence of correctly implemented <code>setRequestHeader</code> method on

+								this object, which rules out Opera prior to version 8.01. If your browser does not

+								support the necessary objects then one alert will display to explain why it

+								doesn't work, after which the appender will silently switch off.

+							</li>

+							<li>

+								In AjaxAppender only, <code>setLayout</code> may not be called after the first

+								message has been logged.

+							</li>

+							<li>

+								The default layout is <code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>.

+							</li>

+							<li>

+								From version 1.4, log message data is always sent as one or more name/value pairs.

+								In the case of <code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>, data

+								is sent the same as in previous versions. For other layouts such as

+								<code><a href="#jsonlayout">JsonLayout</a></code> and

+								<code><a href="#xmllayout">XmlLayout</a></code>, the formatted log message is posted as

+								the value of a parameter called <code>data</code>, though this may be changed via

+								<code>setPostVarName</code>.

+							</li>

+							<li>

+								From version 1.4, log message timestamps are sent as standard JavaScript times, i.e.

+								the number of milliseconds since 00:00:00 UTC on January 1, 1970.

+							</li>

+							<li>

+								<p>

+									Also from version 1.4, any outstanding log messages may optionally be sent when the

+									main page unloads (i.e. user follows a link, closes the window or refreshes the

+									page). This behaviour may be enabled using <code>setSendAllOnUnload</code>; see

+									below.

+								</p>

+								<p>

+									This behaviour is dependent on <code>window.onbeforeunload</code>; unfortunately,

+									Opera does not always raise this event, so this feature does not work reliably in

+									Opera.

+								</p>

+							</li>

+						</ul>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">AjaxAppender</div>

+								<div class="methodsignature">

+									<code><strong>AjaxAppender</strong>(String <em>url</em>)</code>

+								</div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">url</code>

+										<div>

+											The URL to which log messages should be sent. Note that this is subject

+											to the usual Ajax restrictions: the URL should be in the same domain as that

+											of the page making the request.

+										</div>

+									</li>

+								</ul>

+							</li>

+						</ul>

+						<h4>Methods</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">setSendAllOnUnload</div>

+								<div class="methodsignature"><code>void <strong>setSendAllOnUnload</strong>(Boolean <em>sendAllOnUnload</em>)</code></div>

+								<div class="summary">

+									<p>

+										[<em>not available after first message logged</em>]

+									</p>

+									<p>

+										Whether to send all remaining unsent log messages to the server when the page

+										unloads.

+									</p>

+									<p>

+										Since version 1.4.3, the default value is <code>false</code>. Previously the

+										default was <code>true</code>.

+									</p>

+									<p><strong>Notes</strong></p>

+									<ul>

+										<li>

+											This feature was found not to work prior to version 1.4.3 in WebKit

+											browsers (e.g. Google Chrome, Safari). As a result, a workaround was

+											implemented in 1.4.3 which has the unfortunate side effect of popping up a

+											confirmation dialog to the user if there are any log messages to send when

+											the page unloads. As a result, this feature is now obtrusive for the user

+											and is therefore disabled by default.

+										</li>

+										<li>

+											This feature does not work in any version of Opera.

+										</li>

+									</ul>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isSendAllOnUnload</div>

+								<div class="methodsignature"><code>Boolean <strong>isSendAllOnUnload</strong>()</code></div>

+								<div class="summary">

+									Returns whether all remaining unsent log messages are sent to the server when the page unloads.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setPostVarName</div>

+								<div class="methodsignature"><code>void <strong>setPostVarName</strong>(String <em>postVarName</em>)</code></div>

+								<div class="summary">

+									<p>

+										[<em>not available after first message logged</em>]

+									</p>

+									<p>

+										Sets the post variable name whose value will the formatted log message(s) for

+										each request.

+									</p>

+									<p>

+										Default value is <code>data</code>.

+									</p>

+									<p><strong>Notes</strong></p>

+									<ul>

+										<li>

+											This has no effect if the current layout is an

+											<code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>.

+										</li>

+									</ul>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getPostVarName</div>

+								<div class="methodsignature"><code>String <strong>getPostVarName</strong>()</code></div>

+								<div class="summary">

+									Returns the post variable name whose value will the formatted log message(s) for

+									each request.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setTimed</div>

+								<div class="methodsignature"><code>void <strong>setTimed</strong>(Boolean <em>timed</em>)</code></div>

+								<div class="summary">

+									<p>

+										[<em>not available after first message logged</em>]

+									</p>

+									<p>

+										Whether to send log messages to the server at regular, timed intervals.

+									</p>

+									<p>

+										Default value is <code>false</code>.

+									</p>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isTimed</div>

+								<div class="methodsignature"><code>Boolean <strong>isTimed</strong>()</code></div>

+								<div class="summary">

+									Returns whether log messages are sent to the server at regular, timed intervals.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setWaitForResponse</div>

+								<div class="methodsignature"><code>void <strong>setWaitForResponse</strong>(Boolean <em>waitForResponse</em>)</code></div>

+								<div class="summary">

+									<p>

+										[<em>not available after first message logged</em>]

+									</p>

+									<p>

+										Sets whether to wait for a response from a previous HTTP request from this

+										appender before sending the next log message / batch of messages.

+									</p>

+									<p>

+										Default value is <code>false</code>.

+									</p>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isWaitForResponse</div>

+								<div class="methodsignature"><code>Boolean <strong>isWaitForResponse</strong>()</code></div>

+								<div class="summary">

+									Returns whether the appender waits for a response from a previous HTTP request from this

+									appender before sending the next log message / batch of messages.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setBatchSize</div>

+								<div class="methodsignature"><code>void <strong>setBatchSize</strong>(Number <em>batchSize</em>)</code></div>

+								<div class="summary">

+									<p>

+										[<em>not available after first message logged</em>]

+									</p>

+									<p>

+										Sets the number of log messages to send in each request. If not specified,

+										defaults to <code>1</code>.

+									</p>

+									<p><strong>Notes</strong></p>

+									<ul>

+										<li>

+											Setting this to a number greater than 1 means that the appender will wait

+											until it has forwarded that many valid log messages before sending any more.

+											This also means that if the page unloads for any reason and <code>sendAllOnUnload</code>

+											is not set to <code>true</code>, any log messages waiting in the queue will not be sent.

+										</li>

+										<li>

+											If batching is used in conjunction with timed sending of log messages,

+											messages will still be sent in batches of size <code>batchSize</code>,

+											regardless of how many log messages are queued by the time the timed

+											sending is invoked. Incomplete batches will not be sent except when the

+											page unloads, if <code>sendAllOnUnload</code> is set to <code>true</code>.

+										</li>

+									</ul>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getBatchSize</div>

+								<div class="methodsignature"><code>Number <strong>getBatchSize</strong>()</code></div>

+								<div class="summary">

+									Returns the number of log messages sent in each request. See above for more details.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setTimerInterval</div>

+								<div class="methodsignature"><code>void <strong>setTimerInterval</strong>(Number <em>timerInterval</em>)</code></div>

+								<div class="summary">

+									<p>

+										[<em>not available after first message logged</em>]

+									</p>

+									<p>

+										Sets the length of time in milliseconds between each sending of queued log

+										messages.

+									</p>

+									<p><strong>Notes</strong></p>

+									<ul>

+										<li>

+											<code>timerInterval</code> only has an effect in conjunction with

+											<code>timed</code> (set by <code>setTimed()</code>. If <code>timed</code>

+											is set to false then <code>timerInterval</code> has no effect.

+										</li>

+										<li>

+											Each time the queue of log messages or batches of messages is cleared,

+											the countdown to the next sending only starts once the final request

+											has been sent (and, if <code>waitForResponse</code> is set to <code>true</code>,

+											the final response received). This means that the actual interval at

+											which the queue of messages is cleared cannot be fixed.

+										</li>

+									</ul>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getTimerInterval</div>

+								<div class="methodsignature"><code>Number <strong>getTimerInterval</strong>()</code></div>

+								<div class="summary">

+									Returns the length of time in milliseconds between each sending of queued log

+									messages. See above for more details.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setRequestSuccessCallback</div>

+								<div class="methodsignature"><code>void <strong>setRequestSuccessCallback</strong>(Function <em>requestSuccessCallback</em>)</code></div>

+								<div class="summary">

+									<p>

+										Sets the function that is called whenever a successful request is made, called at the

+										point at which the response is received. This feature can be used to confirm

+										whether a request has been successful and act accordingly.

+									</p>

+									<p>

+										A single parameter, <code>xmlHttp</code>, is passed to the callback function.

+										This is the XMLHttpRequest object that performed the request.

+									</p>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setFailCallback</div>

+								<div class="methodsignature"><code>void <strong>setFailCallback</strong>(Function <em>failCallback</em>)</code></div>

+								<div class="summary">

+									<p>

+										Sets the function that is called whenever any kind of failure occurs in the appender,

+										including browser deficiencies or configuration errors (e.g. supplying a

+										non-existent URL to the appender). This feature can be used to handle

+										AjaxAppender-specific errors.

+									</p>

+									<p>

+										A single parameter, <code>message</code>, is passed to the callback function.

+										This is the error-specific message that caused the failure.

+									</p>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setSessionId</div>

+								<div class="methodsignature"><code>void <strong>setSessionId</strong>(String <em>sessionId</em>)</code></div>

+								<div class="summary">

+									Sets the session id sent to the server each time a request is made.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getSessionId</div>

+								<div class="methodsignature"><code>String <strong>getSessionId</strong>()</code></div>

+								<div class="summary">

+									Returns the session id sent to the server each time a request is made.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">addHeader</div>

+								<div class="methodsignature"><code>void <strong>addHeader</strong>(String <em>name</em>,

+									String <em>value</em>)</code></div>

+								<div class="summary">

+									<p>

+										Adds an HTTP header that is sent with each request.

+									</p>

+									<p>

+										<strong>Since: 1.4.3</strong>

+									</p>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getHeaders</div>

+								<div class="methodsignature"><code>Array <strong>getHeaders</strong>()</code></div>

+								<div class="summary">

+									Returns an array of the additional headers that are sent with each HTTP request.

+									Each array item is an object with properties <code>name</code> and

+									<code>value</code>.

+									<p>

+										<strong>Since: 1.4.3</strong>

+									</p>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">sendAll</div>

+								<div class="methodsignature"><code>void <strong>sendAll</strong>()</code></div>

+								<div class="summary">

+									Sends all log messages in the queue. If log messages are batched then only completed

+									batches are sent.

+								</div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="popupappender">

+						<h3>PopUpAppender</h3>

+						<p class="editions">Editions: <strong>Standard</strong></p>

+						<p>

+							Logs messages to a pop-up console window (note: you will need to disable pop-up

+							blockers to use it). The pop-up displays a list of all log messages, and has

+							the following features:

+						</p>

+						<ul>

+							<li>log messages are colour-coded by severity;</li>

+							<li>log messages are displayed in a monospace font to allow easy readability;</li>

+							<li>switchable wrap mode to allow wrapping of long lines</li>

+							<li>all whitespace in log messages is honoured (except in wrap mode);</li>

+							<li>filters to show and hide messages of a particular level;</li>

+							<li>

+								search facility that allows searching of log messages as you type, with the

+								following features:

+								<ul>

+									<li>supports regular expressions;</li>

+									<li>case sensitive or insensitive matching;</li>

+									<li>buttons to navigate through all the matches;</li>

+									<li>switch to highlight all matches;</li>

+									<li>switch to filter out all log messages that contain no matches;</li>

+									<li>switch to enable or disable the search;</li>

+									<li>search is dynamically applied to every log message as it is added to the console.</li>

+								</ul>

+							</li>

+							<li>switch to toggle between logging from the top down and from the bottom up;</li>

+							<li>switch to turn automatic scrolling when a new message is logged on and off;</li>

+							<li>switch to turn off all logging to the pop-up (useful if a timer is generating unwanted log messages);</li>

+							<li>optional configurable limit to the number of log message that are displayed. If

+								set and this limit is reached, each new log message will cause the oldest one to

+								be discarded;</li>

+							<li>grouped log messages. Groups may be nested and each has a button to show or hide the log messages in that group;</li>

+							<li>clear button to allow user to delete all current log messages.</li>

+							<li>

+								command prompt with up/down arrow history. Command line functions may be added

+								to the appender. Several command line functions are built in:

+								<ul class="propertieslist">

+									<li class="method">

+										<div class="methodsignature"><code><strong>$</strong>(String <em>id</em>)</code></div>

+										<div class="summary">

+											Prints a string representation of a single element with the id supplied.

+										</div>

+									</li>

+									<li class="method">

+										<div class="methodsignature"><code><strong>dir</strong>(Object <em>obj</em>)</code></div>

+										<div class="summary">

+											Prints a list of a properties of the object supplied.

+										</div>

+									</li>

+									<li class="method">

+										<div class="methodsignature"><code><strong>dirxml</strong>(HTMLElement <em>el</em>)</code></div>

+										<div class="summary">

+											Prints the XML source code of an HTML or XML element

+										</div>

+									</li>

+									<li class="method">

+										<div class="methodsignature"><code><strong>cd</strong>(Object <em>win</em>)</code></div>

+										<div class="summary">

+											Changes the scope of execution of commands to the named frame or window (either a

+											window/frame name or a reference to a window object may be supplied).

+										</div>

+									</li>

+									<li class="method">

+										<div class="methodsignature"><code><strong>clear</strong>()</code></div>

+										<div class="summary">

+											Clears the console.

+										</div>

+									</li>

+									<li class="method">

+										<div class="methodsignature"><code><strong>keys</strong>(Object <em>obj</em>)</code></div>

+										<div class="summary">

+											Prints a list of the names of all properties of the object supplied.

+										</div>

+									</li>

+									<li class="method">

+										<div class="methodsignature"><code><strong>values</strong>(Object <em>obj</em>)</code></div>

+										<div class="summary">

+											Prints a list of the values of all properties of the object supplied.

+										</div>

+									</li>

+									<li class="method">

+										<div class="methodsignature"><code><strong>expansionDepth</strong>(Number <em>depth</em>)</code></div>

+										<div class="summary">

+											Sets the number of levels of expansion of objects that are displayed by

+											the command line. The default value is 1.

+										</div>

+									</li>

+								</ul>

+							</li>

+						</ul>

+						<p><strong>Notes</strong></p>

+						<ul>

+							<li>

+								<p>

+									The default layout for this appender is <code><a href="#patternlayout">PatternLayout</a></code>

+									with pattern string

+								</p>

+								<p>

+									<code>%d{HH:mm:ss} %-5p - %m{1}%n</code>

+								</p>

+							</li>

+						</ul>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">PopUpAppender</div>

+								<div class="methodsignature">

+							   		<code><strong>PopUpAppender</strong>([Boolean <em>lazyInit</em>,

+									Boolean <em>initiallyMinimized</em>, Boolean <em>useDocumentWrite</em>,

+									Number <em>width</em>, Number <em>height</em>])</code>

+								</div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">lazyInit</code>

+										[<em>optional</em>]

+										<div>

+											Set this to <code>true</code> to open the pop-up only when the first log

+											message reaches the appender. Otherwise, the pop-up window opens as soon as the

+											appender is created. If not specified, defaults to <code>false</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">initiallyMinimized</code>

+										[<em>optional</em>]

+										<div>

+											<p>

+												Whether the console window should start off hidden / minimized.

+												If not specified, defaults to <code>false</code>.

+											</p>

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">useDocumentWrite</code>

+										[<em>optional</em>]

+										<div>

+											<p>

+												Specifies how the console window is created. By default, the console window is

+												created dynamically using <code>document</code>'s <code>write</code> method. This has the

+												advantage of keeping all the code in one single JavaScript file. However, if your

+												page sets <code>document.domain</code> then the browser prevents script access to

+												a window unless it too has the same value set for <code>document.domain</code>. To

+												get round this issue, you can set <code>useDocumentWrite</code> to <code>false</code>

+												and log4javascript will instead use the external HTML file <code>console.html</code>

+												(or <code>console_uncompressed.html</code> if you're using an uncompressed version of

+												log4javascript.js), which must be placed in the same directory as your log4javascript.js file.

+											</p>

+											<p>

+												Note that if <code>useDocumentWrite</code> is set to <code>true</code>, the old pop-up

+												window will always be closed and a new one created whenever the page is refreshed, even

+												if <code>setUseOldPopUp(true)</code> has been called.

+											</p>

+											<p>

+												In general it's simpler to use the <code>document.write</code> method, so unless your

+												page needs to set <code>document.domain</code>, <code>useDocumentWrite</code> should

+												be set to <code>true</code>.

+											</p>

+											<p>

+												If not specified, defaults to <code>true</code>.

+											</p>

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">width</code>

+										[<em>optional</em>]

+										<div>

+											The outer width in pixels of the pop-up window. If not specified,

+											defaults to <code>600</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">height</code>

+										[<em>optional</em>]

+										<div>

+											The outer height in pixels of the pop-up window. If not specified,

+											defaults to <code>400</code>.

+										</div>

+									</li>

+								</ul>

+							</li>

+						</ul>

+						<h4>Methods</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">isInitiallyMinimized</div>

+								<div class="methodsignature"><code>Boolean <strong>isInitiallyMinimized</strong>()</code></div>

+								<div class="summary">

+									Returns whether the console window starts off hidden / minimized.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setInitiallyMinimized</div>

+								<div class="methodsignature"><code>void <strong>setInitiallyMinimized</strong>(Boolean <em>initiallyMinimized</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets whether the console window should start off hidden / minimized.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isFocusPopUp</div>

+								<div class="methodsignature"><code>Boolean <strong>isFocusPopUp</strong>()</code></div>

+								<div class="summary">

+									Returns whether the pop-up window is focussed (i.e. brought it to the front)

+									when a new log message is added. Default value is <code>false</code>.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setFocusPopUp</div>

+								<div class="methodsignature"><code>void <strong>setFocusPopUp</strong>(Boolean <em>focusPopUp</em>)</code></div>

+								<div class="summary">

+									Sets whether to focus the pop-up window (i.e. bring it to the front)

+									when a new log message is added.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isUseOldPopUp</div>

+								<div class="methodsignature"><code>Boolean <strong>isUseOldPopUp</strong>()</code></div>

+								<div class="summary">

+									<p>

+										Returns whether the same pop-up window is used if the main page is

+										reloaded. If set to <code>true</code>, when the page is reloaded

+										a line is drawn in the pop-up and subsequent log messages are added

+										to the same pop-up. Otherwise, a new pop-up window is created that

+										replaces the original pop-up. If not specified, defaults to

+										<code>true</code>.

+									</p>

+									<p><strong>Notes</strong></p>

+									<ul>

+										<li>

+											In Internet Explorer 5, the browser prevents this from working

+											properly, so a new pop-up window is always created when the main

+											page reloads. Also, the original pop-up does not get closed.

+										</li>

+									</ul>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setUseOldPopUp</div>

+								<div class="methodsignature"><code>void <strong>setUseOldPopUp</strong>(Boolean <em>useOldPopUp</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets whether to use the same pop-up window if the main page is reloaded.

+									See <code>isUseOldPopUp</code> above for details.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isComplainAboutPopUpBlocking</div>

+								<div class="methodsignature"><code>Boolean <strong>isComplainAboutPopUpBlocking</strong>()</code></div>

+								<div class="summary">

+									Returns whether an alert is shown to the user when the pop-up window

+									cannot be created as a result of a pop-up blocker. Default value is <code>true</code>.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setComplainAboutPopUpBlocking</div>

+								<div class="methodsignature"><code>void <strong>setComplainAboutPopUpBlocking</strong>(Boolean <em>complainAboutPopUpBlocking</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets whether to announce to show an alert to the user when the pop-up window

+									cannot be created as a result of a pop-up blocker.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isNewestMessageAtTop</div>

+								<div class="methodsignature"><code>Boolean <strong>isNewestMessageAtTop</strong>()</code></div>

+								<div class="summary">

+									Returns whether new log messages are displayed at the top of the pop-up window.

+									Default value is <code>false</code> (i.e. log messages are appended to the bottom of the window).

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setNewestMessageAtTop</div>

+								<div class="methodsignature"><code>void <strong>setNewestMessageAtTop</strong>(Boolean <em>newestMessageAtTop</em>)</code></div>

+								<div class="summary">

+									Sets whether to display new log messages at the top inside the pop-up window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isScrollToLatestMessage</div>

+								<div class="methodsignature"><code>Boolean <strong>isScrollToLatestMessage</strong>()</code></div>

+								<div class="summary">

+									Returns whether the pop-up window scrolls to display the latest log message when a new message

+									is logged. Default value is <code>true</code>.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setScrollToLatestMessage</div>

+								<div class="methodsignature"><code>void <strong>setScrollToLatestMessage</strong>(Boolean <em>scrollToLatestMessage</em>)</code></div>

+								<div class="summary">

+									Sets whether to scroll the pop-up window to display the latest log message when a new message

+									is logged.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isReopenWhenClosed</div>

+								<div class="methodsignature"><code>Boolean <strong>isReopenWhenClosed</strong>()</code></div>

+								<div class="summary">

+									Returns whether the pop-up window reopens automatically after being closed when a new log message is logged.

+									Default value is <code>false</code>.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setReopenWhenClosed</div>

+								<div class="methodsignature"><code>void <strong>setReopenWhenClosed</strong>(Boolean <em>reopenWhenClosed</em>)</code></div>

+								<div class="summary">

+									Sets whether to reopen the pop-up window automatically after being closed when a new log message is logged.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getWidth</div>

+								<div class="methodsignature"><code>Number <strong>getWidth</strong>()</code></div>

+								<div class="summary">

+									Returns the outer width in pixels of the pop-up window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setWidth</div>

+								<div class="methodsignature"><code>void <strong>setWidth</strong>(Number <em>width</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets the outer width in pixels of the pop-up window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getHeight</div>

+								<div class="methodsignature"><code>Number <strong>getHeight</strong>()</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Returns the outer height in pixels of the pop-up window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setHeight</div>

+								<div class="methodsignature"><code>void <strong>setHeight</strong>(Number <em>height</em>)</code></div>

+								<div class="summary">

+									Sets the outer height in pixels of the pop-up window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getMaxMessages</div>

+								<div class="methodsignature"><code>Number <strong>getMaxMessages</strong>()</code></div>

+								<div class="summary">

+									Returns the largest number of log messages that are displayed and stored

+									by the the console. Once reached, a new log message wil cause the

+									oldest message to be discarded.  Default value is <code>null</code>, which means no

+									limit is applied.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setMaxMessages</div>

+								<div class="methodsignature"><code>void <strong>setMaxMessages</strong>(Number <em>maxMessages</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets the largest number of messages displayed and stored by the console window. Set

+									this to <code>null</code> to make this number unlimited.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isShowCommandLine</div>

+								<div class="methodsignature"><code>Boolean <strong>isShowCommandLine</strong>()</code></div>

+								<div class="summary">

+									Returns whether the console includes a command line.

+									Default value is <code>true</code>.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setShowCommandLine</div>

+								<div class="methodsignature"><code>void <strong>setShowCommandLine</strong>(Boolean <em>showCommandLine</em>)</code></div>

+								<div class="summary">

+									Sets whether the console includes a command line.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getCommandLineObjectExpansionDepth</div>

+								<div class="methodsignature"><code>Number <strong>getCommandLineObjectExpansionDepth</strong>()</code></div>

+								<div class="summary">

+									Returns the number of levels to expand when an object value is logged to the console.

+									Each property of an object above this threshold will be expanded if it is itself an object

+									or array, otherwise its string representation will be displayed. Default value is 1 (i.e.

+									the properties of the object logged will be displayed in their string representation but

+									not expanded).

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setCommandLineObjectExpansionDepth:</div>

+								<div class="methodsignature"><code>void <strong>setCommandLineObjectExpansionDepth</strong>(Number <em>expansionDepth</em>)</code></div>

+								<div class="summary">

+									Sets the number of levels to expand when an object value is logged to the console.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getCommandWindow</div>

+								<div class="methodsignature"><code>Window <strong>getCommandWindow</strong>()</code></div>

+								<div class="summary">

+									Returns a reference to the window in which commands typed into the command line

+									are currently being executed.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setCommandWindow</div>

+								<div class="methodsignature"><code>void <strong>setCommandWindow</strong>(Window <em>commandWindow</em>)</code></div>

+								<div class="summary">

+									Sets the window in which commands typed into the command line are executed.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getCommandLayout</div>

+								<div class="methodsignature"><code>Number <strong>getCommandLayout</strong>()</code></div>

+								<div class="summary">

+									Returns the layout used to format the output for commands typed into the command line.

+									The default value is a <code><a href="#patternlayout">PatternLayout</a></code> with

+									pattern string <code>%m</code>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setCommandLayout</div>

+								<div class="methodsignature"><code>void <strong>setCommandLayout</strong>(Layout <em>commandLayout</em>)</code></div>

+								<div class="summary">

+									Sets the layout used to format the output for commands typed into the command line.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">clear</div>

+								<div class="methodsignature"><code>void <strong>clear</strong>()</code></div>

+								<div class="summary">

+									Clears all messages from the console window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">close</div>

+								<div class="methodsignature"><code>void <strong>close</strong>()</code></div>

+								<div class="summary">

+									Closes the pop-up window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">show</div>

+								<div class="methodsignature"><code>void <strong>show</strong>()</code></div>

+								<div class="summary">

+									Opens the pop-up window, if not already open.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">hide</div>

+								<div class="methodsignature"><code>void <strong>hide</strong>()</code></div>

+								<div class="summary">

+									Closes the pop-up window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">focus</div>

+								<div class="methodsignature"><code>void <strong>focus</strong>()</code></div>

+								<div class="summary">

+									Brings the console window to the top and gives it the focus.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">focusCommandLine</div>

+								<div class="methodsignature"><code>void <strong>focusCommandLine</strong>()</code></div>

+								<div class="summary">

+									Brings the console window to the top and gives the focus to the command line.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">focusSearch</div>

+								<div class="methodsignature"><code>void <strong>focusSearch</strong>()</code></div>

+								<div class="summary">

+									Brings the console window to the top and gives the focus to the search box.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">evalCommandAndAppend</div>

+								<div class="methodsignature"><code>void <strong>evalCommandAndAppend</strong>(String <em>expr</em>)</code></div>

+								<div class="summary">

+									Evaluates the expression and appends the result to the console.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">addCommandLineFunction</div>

+								<div class="methodsignature"><code>void <strong>addCommandLineFunction</strong>(String <em>functionName</em>, Function <em>commandLineFunction</em>)</code></div>

+								<div class="summary">

+									<p>

+										Adds a function with the name specified to the list of functions available on the command line.

+										This feature may be used to add custom functions to the command line.

+									</p>

+									<p>

+										When you call the function on the command line, <code>commandLineFunction</code> is executed with the

+										following three parameters:

+									</p>

+									<ul>

+										<li><em>appender</em>. A reference to the appender in which the command was executed;</li>

+										<li><em>args</em>.

+											An array-like list of parameters passed into the function on the command line

+											(actually a reference to the <code>arguments</code> object representing the parameters passed

+											into the function by the user);</li>

+										<li><em>returnValue</em>. This is an object with two properties that allow the function to control

+											how the result is displayed:

+											<ul>

+												<li><em>appendResult</em>. A boolean value that determines whether the returned value from this

+													function is appended to the console. The default value is <code>true</code>;</li>

+												<li><em>isError</em>. A boolean value that specifies whether the output of this function

+													should be displayed as an error. The default value is <code>false</code>.</li>

+											</ul>

+										</li>

+									</ul>

+									<p>

+										The value returned by the function is formatted by the command layout and appended to the console.

+									</p>

+								</div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="inpageappender">

+						<h3>InPageAppender</h3>

+						<p class="editions">Editions: <strong>Standard</strong></p>

+						<p>

+							Logs messages to a console window in the page. The console is identical

+							to that used by the <code><a href="#popupappender">PopUpAppender</a></code>, except

+							for the absence of a 'Close' button.

+						</p>

+						<p><strong>Notes</strong></p>

+						<ul>

+							<li>

+								Prior to log4javascript 1.3, InPageAppender was known as InlineAppender.

+								For the sake of backwards compatibility, InlineAppender is still included in

+								1.3 and later as an alias for InPageAppender.

+							</li>

+							<li>

+								<p>

+									The default layout for this appender is <code><a href="#patternlayout">PatternLayout</a></code>

+									with pattern string

+								</p>

+								<p>

+									<code>%d{HH:mm:ss} %-5p - %m{1}%n</code>

+								</p>

+							</li>

+						</ul>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">InPageAppender</div>

+								<div class="methodsignature">

+									<code><strong>InPageAppender</strong>(HTMLElement <em>container</em>[,

+									Boolean <em>lazyInit</em>, Boolean <em>initiallyMinimized</em>,

+									Boolean <em>useDocumentWrite</em>, String <em>width</em>, String <em>height</em>])</code>

+								</div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">container</code>

+										<div>

+											The container element for the console window. This should be an HTML element.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">lazyInit</code>

+										[<em>optional</em>]

+										<div>

+											Set this to <code>true</code> to create the console only when the first log

+											message reaches the appender. Otherwise, the console is initialized as soon as the

+											appender is created. If not specified, defaults to <code>true</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">initiallyMinimized</code>

+										[<em>optional</em>]

+										<div>

+											<p>

+												Whether the console window should start off hidden / minimized.

+												If not specified, defaults to <code>false</code>.

+											</p>

+											<p><strong>Notes</strong></p>

+											<ul>

+												<li>

+													In Safari (and possibly other browsers) hiding an <code>iframe</code>

+													resets its document, thus destroying the console window.

+												</li>

+											</ul>

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">useDocumentWrite</code>

+										[<em>optional</em>]

+										<div>

+											<p>

+												Specifies how the console window is created. By default, the console window is

+												created dynamically using <code>document</code>'s <code>write</code> method. This has the

+												advantage of keeping all the code in one single JavaScript file. However, if your

+												page sets <code>document.domain</code> then the browser prevents script access to

+												a window unless it too has the same value set for <code>document.domain</code>. To

+												get round this issue, you can set <code>useDocumentWrite</code> to <code>false</code>

+												and log4javascript will instead use the external HTML file <code>console.html</code>

+												(or <code>console_uncompressed.html</code> if you're using an uncompressed version of

+												log4javascript.js), which must be placed in the same directory as your log4javascript.js file.

+											</p>

+											<p>

+												In general it's simpler to use the <code>document.write</code> method, so unless your

+												page needs to set <code>document.domain</code>, <code>useDocumentWrite</code> should

+												be set to <code>true</code>.

+											</p>

+											<p>

+												If not specified, defaults to <code>true</code>.

+											</p>

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">width</code>

+										[<em>optional</em>]

+										<div>

+											The width of the console window. Any valid CSS length may be used. If not

+											specified, defaults to <code>100%</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">height</code>

+										[<em>optional</em>]

+										<div>

+											The height of the console window. Any valid CSS length may be used. If not

+											specified, defaults to <code>250px</code>.

+										</div>

+									</li>

+								</ul>

+							</li>

+						</ul>

+						<h4>Methods</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">addCssProperty</div>

+								<div class="methodsignature"><code>void <strong>addCssProperty</strong>(String <em>name</em>, String <em>value</em>)</code></div>

+								<div class="summary">

+									Sets a CSS style property on the HTML element containing the console iframe.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isVisible</div>

+								<div class="methodsignature"><code>Boolean <strong>isVisible</strong>()</code></div>

+								<div class="summary">

+									Returns whether the console window is currently visible.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isInitiallyMinimized</div>

+								<div class="methodsignature"><code>Boolean <strong>isInitiallyMinimized</strong>()</code></div>

+								<div class="summary">

+									Returns whether the console window starts off hidden / minimized.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setInitiallyMinimized</div>

+								<div class="methodsignature"><code>void <strong>setInitiallyMinimized</strong>(Boolean <em>initiallyMinimized</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets whether the console window should start off hidden / minimized.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isNewestMessageAtTop</div>

+								<div class="methodsignature"><code>Boolean <strong>isNewestMessageAtTop</strong>()</code></div>

+								<div class="summary">

+									Returns whether new log messages are displayed at the top of the console window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setNewestMessageAtTop</div>

+								<div class="methodsignature"><code>void <strong>setNewestMessageAtTop</strong>(Boolean <em>newestMessageAtTop</em>)</code></div>

+								<div class="summary">

+									Sets whether to display new log messages at the top inside the console window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isScrollToLatestMessage</div>

+								<div class="methodsignature"><code>Boolean <strong>isScrollToLatestMessage</strong>()</code></div>

+								<div class="summary">

+									Returns whether the pop-up window scrolls to display the latest log message when a new message

+									is logged.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setScrollToLatestMessage</div>

+								<div class="methodsignature"><code>void <strong>setScrollToLatestMessage</strong>(Boolean <em>scrollToLatestMessage</em>)</code></div>

+								<div class="summary">

+									Sets whether to scroll the console window to display the latest log message when a new message

+									is logged.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getWidth</div>

+								<div class="methodsignature"><code>String <strong>getWidth</strong>()</code></div>

+								<div class="summary">

+									Returns the outer width of the console window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setWidth</div>

+								<div class="methodsignature"><code>void <strong>setWidth</strong>(String <em>width</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets the outer width of the console window. Any valid CSS length may be used.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getHeight</div>

+								<div class="methodsignature"><code>String <strong>getHeight</strong>()</code></div>

+								<div class="summary">

+									Returns the outer height of the console window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setHeight</div>

+								<div class="methodsignature"><code>void <strong>setHeight</strong>(String <em>height</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets the outer height of the console window. Any valid CSS length may be used.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getMaxMessages</div>

+								<div class="methodsignature"><code>Number <strong>getMaxMessages</strong>()</code></div>

+								<div class="summary">

+									Returns the largest number of messages displayed and stored by the console window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setMaxMessages</div>

+								<div class="methodsignature"><code>void <strong>setMaxMessages</strong>(Number <em>maxMessages</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets the largest number of messages displayed and stored by the console window. Set

+									this to <code>null</code> to make this number unlimited.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isShowCommandLine</div>

+								<div class="methodsignature"><code>Boolean <strong>isShowCommandLine</strong>()</code></div>

+								<div class="summary">

+									Returns whether the console includes a command line.

+									Default value is <code>true</code>.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setShowCommandLine</div>

+								<div class="methodsignature"><code>void <strong>setShowCommandLine</strong>(Boolean <em>showCommandLine</em>)</code></div>

+								<div class="summary">

+									Sets whether the console includes a command line.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getCommandLineObjectExpansionDepth</div>

+								<div class="methodsignature"><code>Number <strong>getCommandLineObjectExpansionDepth</strong>()</code></div>

+								<div class="summary">

+									Returns the number of levels to expand when an object value is logged to the console.

+									Each property of an object above this threshold will be expanded if it is itself an object

+									or array, otherwise its string representation will be displayed. Default value is 1 (i.e.

+									the properties of the object logged will be displayed in their string representation but

+									not expanded).

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setCommandLineObjectExpansionDepth:</div>

+								<div class="methodsignature"><code>void <strong>setCommandLineObjectExpansionDepth</strong>(Number <em>expansionDepth</em>)</code></div>

+								<div class="summary">

+									Sets the number of levels to expand when an object value is logged to the console.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getCommandWindow</div>

+								<div class="methodsignature"><code>Window <strong>getCommandWindow</strong>()</code></div>

+								<div class="summary">

+									Returns a reference to the window in which commands typed into the command line

+									are currently being executed.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setCommandWindow</div>

+								<div class="methodsignature"><code>void <strong>setCommandWindow</strong>(Window <em>commandWindow</em>)</code></div>

+								<div class="summary">

+									Sets the window in which commands typed into the command line are executed.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getCommandLayout</div>

+								<div class="methodsignature"><code>Number <strong>getCommandLayout</strong>()</code></div>

+								<div class="summary">

+									Returns the layout used to format the output for commands typed into the command line.

+									The default value is a <code><a href="#patternlayout">PatternLayout</a></code> with

+									pattern string <code>%m</code>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setCommandLayout</div>

+								<div class="methodsignature"><code>void <strong>setCommandLayout</strong>(Layout <em>commandLayout</em>)</code></div>

+								<div class="summary">

+									Sets the layout used to format the output for commands typed into the command line.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">clear</div>

+								<div class="methodsignature"><code>void <strong>clear</strong>()</code></div>

+								<div class="summary">

+									Clears all messages from the console window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">show</div>

+								<div class="methodsignature"><code>void <strong>show</strong>()</code></div>

+								<div class="summary">

+									<p>

+										Shows / unhides the console window.

+									</p>

+									<p><strong>Notes</strong></p>

+									<ul>

+										<li>

+											In Safari (and possibly other browsers), hiding an <code>iframe</code>

+											resets its document, thus destroying the console window.

+										</li>

+									</ul>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">hide</div>

+								<div class="methodsignature"><code>void <strong>hide</strong>()</code></div>

+								<div class="summary">

+									<p>

+										Hides / minimizes the console window.

+									</p>

+									<p><strong>Notes</strong></p>

+									<ul>

+										<li>

+											In Safari (and possibly other browsers), hiding an <code>iframe</code>

+											resets its document, thus destroying the console window.

+										</li>

+									</ul>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">close</div>

+								<div class="methodsignature"><code>void <strong>close</strong>()</code></div>

+								<div class="summary">

+									Removes the console window iframe from the main document.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">focus</div>

+								<div class="methodsignature"><code>void <strong>focus</strong>()</code></div>

+								<div class="summary">

+									Brings the console window to the top and gives it the focus.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">focusCommandLine</div>

+								<div class="methodsignature"><code>void <strong>focusCommandLine</strong>()</code></div>

+								<div class="summary">

+									Brings the console window to the top and gives the focus to the command line.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">focusSearch</div>

+								<div class="methodsignature"><code>void <strong>focusSearch</strong>()</code></div>

+								<div class="summary">

+									Brings the console window to the top and gives the focus to the search box.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">evalCommandAndAppend</div>

+								<div class="methodsignature"><code>void <strong>evalCommandAndAppend</strong>(String <em>expr</em>)</code></div>

+								<div class="summary">

+									Evaluates the expression and appends the result to the console.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">addCommandLineFunction</div>

+								<div class="methodsignature"><code>void <strong>addCommandLineFunction</strong>(String <em>functionName</em>, Function <em>commandLineFunction</em>)</code></div>

+								<div class="summary">

+									<p>

+										Adds a function with the name specified to the list of functions available on the command line.

+										This feature may be used to add custom functions to the command line.

+									</p>

+									<p>

+										When you call the function on the command line, <code>commandLineFunction</code> is executed with the

+										following three parameters:

+									</p>

+									<ul>

+										<li><em>appender</em>. A reference to the appender in which the command was executed;</li>

+										<li><em>args</em>.

+											An array-like list of parameters passed into the function on the command line

+											(actually a reference to an <code>arguments</code> object);</li>

+										<li><em>returnValue</em>. This is an object with two properties that allow the function to control

+											how the result is displayed:

+											<ul>

+												<li><em>appendResult</em>. A boolean value that determines whether the returned value from this

+													function is appended to the console. The default value is <code>true</code>;</li>

+												<li><em>isError</em>. A boolean value that specifies whether the output of this function

+													should be displayed as an error. The default value is <code>false</code>.</li>

+											</ul>

+										</li>

+									</ul>

+									<p>

+										The value returned by the function is formatted by the command layout and appended to the console.

+									</p>

+								</div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="browserconsoleappender">

+						<h3>BrowserConsoleAppender</h3>

+						<p class="editions">Editions: <strong>Standardl</strong></p>

+						<p>

+							Writes log messages to the browser's built-in console, if present. This only works

+							currently in Safari, Opera and Firefox with the excellent

+							<a href="http://www.getfirebug.com" title="Firebug home page (opens in new window)"

+							target="_blank">Firebug</a> extension installed.

+						</p>

+						<p><strong>Notes</strong></p>

+						<ul>

+							<li>

+								As of log4javascript 1.3, the default threshold for this appender is <code>DEBUG</code>

+								as opposed to <code>WARN</code> as it was previously;

+							</li>

+							<li>

+								<p>

+									As of version 1.3, log4javascript has explicit support for Firebug's logging. This includes

+									the following mapping of log4javascript's log levels onto Firebug's:

+								</p>

+								<ul>

+									<li>log4javascript <code>TRACE</code>, <code>DEBUG</code> -&gt; Firebug <code>debug</code></li>

+									<li>log4javascript <code>INFO</code> -&gt; Firebug <code>info</code></li>

+									<li>log4javascript <code>WARN</code> -&gt; Firebug <code>warn</code></li>

+									<li>log4javascript <code>ERROR</code>, <code>FATAL</code> -&gt; Firebug <code>error</code></li>

+								</ul>

+								<p>

+									... and the ability to pass objects into Firebug and take advantage of its object inspection.

+									This is because the default layout is now <code><a href="#nulllayout">NullLayout</a></code>,

+									which performs no formatting on an object.

+								</p>

+							</li>

+						</ul>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">BrowserConsoleAppender</div>

+								<div class="methodsignature"><code><strong>BrowserConsoleAppender</strong>()</code></div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+				</div>

+				<div id="layouts">

+					<h2>Layouts</h2>

+					<div id="layout">

+						<h3>Layout</h3>

+						<p>

+							There are a few methods common to all layouts:

+						</p>

+						<h4>Methods</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">format</div>

+								<div class="methodsignature"><code>String <strong>format</strong>(LoggingEvent <em>loggingEvent</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">loggingEvent</code>

+									</li>

+								</ul>

+								<div class="summary">

+									Formats the log message. You should override this method in your own layouts.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">ignoresThrowable</div>

+								<div class="methodsignature"><code>Boolean <strong>ignoresThrowable</strong>()</code></div>

+								<div class="summary">

+									Returns whether the layout ignores an error object in a logging event passed

+									to its <code>format</code> method.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getContentType</div>

+								<div class="methodsignature"><code>String <strong>getContentType</strong>()</code></div>

+								<div class="summary">

+									Returns the content type of the output of the layout.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">allowBatching</div>

+								<div class="methodsignature"><code>Boolean <strong>allowBatching</strong>()</code></div>

+								<div class="summary">

+									Returns whether the layout's output is suitable for batching.

+									<code><a href="#jsonlayout">JsonLayout</a></code> and <code><a href="#xmllayout">XmlLayout</a></code>

+									are the only built-in layouts that return true for this method.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getDataValues</div>

+								<div class="methodsignature"><code>Array <strong>getDataValues</strong>(LoggingEvent <em>loggingEvent</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">loggingEvent</code>

+									</li>

+								</ul>

+								<div class="summary">

+									Used internally by log4javascript in constructing formatted output for some layouts.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setKeys</div>

+								<div class="methodsignature"><code>void <strong>setKeys</strong>(String <em>loggerKey</em>,

+									String <em>timeStampKey</em>, String <em>levelKey</em>, String <em>messageKey</em>,

+									String <em>exceptionKey</em>, String <em>urlKey</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">loggerKey</code>

+										<div>

+											Parameter to use for the log message's logger name. Default is <code>logger</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">timeStampKey</code>

+										<div>

+											Parameter to use for the log message's timestamp.  Default is <code>timestamp</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">levelKey</code>

+										<div>

+											Parameter to use for the log message's level. Default is <code>level</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">messageKey</code>

+										<div>

+											Parameter to use for the message itself. Default is <code>message</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">exceptionKey</code>

+										<div>

+											Parameter to use for the log message's error (exception). Default is <code>exception</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">urlKey</code>

+										<div>

+											Parameter to use for the current page URL. Default is <code>url</code>.

+										</div>

+									</li>

+								</ul>

+								<div class="summary">

+									This method is used to change the default keys used to create formatted name-value pairs

+									for the properties of a log message, for layouts that do this. These layouts are

+									<code><a href="#jsonlayout">JsonLayout</a></code> and

+									<code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setCustomField</div>

+								<div class="methodsignature"><code>void <strong>setCustomField</strong>(String <em>name</em>,

+									String <em>value</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">name</code>

+										<div>

+											Name of the custom property you wish to be included in the formmtted output.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">value</code>

+										<div>

+											Value of the custom property you wish to be included in the formatted output.

+										</div>

+									</li>

+								</ul>

+								<div class="summary">

+									Some layouts (<code><a href="#jsonlayout">JsonLayout</a></code>,

+									<code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>,

+									<code><a href="#patternlayout">PatternLayout</a></code> and

+									<code><a href="#xmllayout">XmlLayout</a></code>) allow you to set

+									custom fields (e.g. a session id to send to the server) to the

+									formatted output. Use this method to set a custom field. If there

+									is already a custom field with the specified name, its value will

+									be updated with <code>value</code>.

+								</div>

+								<p><strong>Notes</strong></p>

+								<ul>

+									<li>

+										<p>

+											From version 1.4, the custom field value may be a function. In this

+											case, the function is run at the time the layout's format method is called,

+											with the following two parameters:

+										</p>

+										<ul>

+											<li><em>layout</em>. A reference to the layout being used;</li>

+											<li><em>loggingEvent</em>. A reference to the logging event being formatted.</li>

+										</ul>

+									</li>

+								</ul>

+							</li>

+							<li class="method">

+								<div class="name">hasCustomFields</div>

+								<div class="methodsignature"><code>Boolean <strong>hasCustomFields</strong>()</code></div>

+								<div class="summary">

+									Returns whether the layout has any custom fields.

+								</div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="nulllayout">

+						<h3>NullLayout</h3>

+						<p class="editions">Editions: <strong>All</strong></p>

+						<p>

+							The most basic layout. NullLayout's <code>format()</code> methods performs no

+							formatting at all and simply returns the message logged.

+						</p>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">NullLayout</div>

+								<div class="methodsignature"><code><strong>NullLayout</strong>()</code></div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="simplelayout">

+						<h3>SimpleLayout</h3>

+						<p class="editions">Editions: <strong>Standard, Production</strong></p>

+						<p>

+							Provides basic formatting. SimpleLayout consists of the level of the log statement,

+							followed by " - " and then the log message itself. For example,

+						</p>

+						<p><code>DEBUG - Hello world</code></p>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">SimpleLayout</div>

+								<div class="methodsignature"><code><strong>SimpleLayout</strong>()</code></div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="patternlayout">

+						<h3>PatternLayout</h3>

+						<p class="editions">Editions: <strong>All</strong></p>

+						<p>

+							Provides a flexible way of formatting a log message by means of a conversion pattern

+							string. The behaviour of this layout is a full implementation of <code>PatternLayout</code>

+							in log4j, with the exception of the set of conversion characters - log4javascript's is

+							necessarily a subset of that of log4j with a few additions of its own, since many of

+							the conversion characters in log4j only make sense in the context of Java.

+						</p>

+						<p>

+							The conversion pattern consists of literal text interspersed with special strings starting with

+							a % symbol called <em>conversion specifiers</em>. A conversion specifier consists of the

+							% symbol, a conversion character (possible characters are listed below) and

+							<em>format modifiers</em>. For full documentation of the conversion pattern, see

+							<a href="http://logging.apache.org/log4j/docs/api/org/apache/log4j/PatternLayout.html" target="_blank">log4j's

+							documentation</a>. Below is a list of all conversion characters available in log4javascript.

+						</p>

+						<h4>Conversion characters</h4>

+						<table border="1" cellspacing="0">

+							<thead>

+								<tr>

+									<th>Conversion Character</th>

+									<th>Effect</th>

+								</tr>

+							</thead>

+							<tbody>

+								<tr>

+									<td>a</td>

+									<td>

+										<p>

+											Outputs log messages specified as an array.

+										</p>

+										<p>

+											Behaves exactly like <code>%m</code>, except that multiple log messages are

+											assumed to have been specified in the logging call as an array rather than

+											as multiple parameters.

+										</p>

+										<p>

+											<strong>Since: 1.4</strong>

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>c</td>

+									<td>

+										<p>

+											Outputs the logger name.

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>d</td>

+									<td>

+										<p>

+											Outputs the date of the logging event. The date conversion specifier

+											may be followed by a date format specifier enclosed between braces. For

+											example, <code>%d{HH:mm:ss,SSS}</code> or

+											<code>%d{dd MMM yyyy HH:mm:ss,SSS}</code>. If no date

+											format specifier is given then ISO8601 format is assumed.

+										</p>

+										<p>

+											The date format specifier is the same as that used by Java's

+											<code><a href="http://java.sun.com/j2se/1.5.0/docs/api/java/text/SimpleDateFormat.html"

+												target="_blank">SimpleDateFormat</a></code>. log4javascript

+											includes a full implementation of SimpleDateFormat's

+											<code>format</code> method, with the exception of the pattern letter

+											'z', (string representation of the timezone) for which the information

+											is not available in JavaScript.

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>f</td>

+									<td>

+										<p>

+											Outputs the value of a custom field set on the layout. If present, the specifier gives

+											the index in the array of custom fields to use; otherwise, the first custom field in the

+											array is used.

+										</p>

+										<p>

+											<strong>Since: 1.3</strong>

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>m</td>

+									<td>

+										<p>

+											Outputs the log messages of the logging event (i.e. the log

+											messages supplied by the client code).

+										</p>

+										<p>

+											As of version 1.4, multiple log messages may be supplied to logging calls.

+											<code>%m</code> displays each log message (using the rules below) one after

+											another, separated by spaces. 

+										</p>

+										<p>

+											As of version 1.3, an object may be specified as the log message and will

+											be expanded to show its properties in the output, provided that a specifier

+											containing the number of levels to expand is provided. If no specifier is

+											provided then the message will be treated as a string regardless of its type.

+											For example, <code>%m{1}</code> will display an expansion of the object one

+											level deep, i.e. each property of the object will be displayed but if the

+											property value is itself an object it will not be expanded and will appear

+											as <code>[object Object]</code>.

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>n</td>

+									<td>

+										<p>

+											Outputs a line separator.

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>p</td>

+									<td>

+										<p>

+											Outputs the level of the logging event.

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>r</td>

+									<td>

+										<p>

+											Outputs the number of milliseconds since log4javascript was initialized.

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>%</td>

+									<td>

+										<p>

+											The sequence %% outputs a single percent sign.

+										</p>

+									</td>

+								</tr>

+							</tbody>

+						</table>

+						<h4>Static properties</h4>

+						<ul class="propertieslist">

+							<li class="property">

+								<div class="name">TTCC_CONVERSION_PATTERN</div>

+								<div class="summary">

+									Built-in conversion pattern, equivalent to <code>%r %p %c - %m%n</code>.

+								</div>

+							</li>

+							<li class="property">

+								<div class="name">DEFAULT_CONVERSION_PATTERN</div>

+								<div class="summary">

+									Built-in conversion pattern, equivalent to <code>%m%n</code>.

+								</div>

+							</li>

+							<li class="property">

+								<div class="name">ISO8601_DATEFORMAT</div>

+								<div class="summary">

+									Built-in date format (and also the default), equivalent to

+									<code>yyyy-MM-dd HH:mm:ss,SSS</code>.

+								</div>

+							</li>

+							<li class="property">

+								<div class="name">DATETIME_DATEFORMAT</div>

+								<div class="summary">

+									Built-in date format, equivalent to <code>dd MMM YYYY HH:mm:ss,SSS</code>.

+								</div>

+							</li>

+							<li class="property">

+								<div class="name">ABSOLUTETIME_DATEFORMAT</div>

+								<div class="summary">

+									Built-in date format, equivalent to <code>HH:mm:ss,SSS</code>.

+								</div>

+							</li>

+						</ul>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">PatternLayout</div>

+								<div class="methodsignature"><code><strong>PatternLayout</strong>(String <em>pattern</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">pattern</code>

+										<div>

+											The conversion pattern string to use.

+										</div>

+									</li>

+								</ul>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="xmllayout">

+						<h3>XmlLayout</h3>

+						<p class="editions">Editions: <strong>Standard, Production</strong></p>

+						<p>

+							Based on log4j's <code>XmlLayout</code>, this layout formats a log message as a

+							fragment of XML. An example of the format of the fragment is as follows:

+						</p>

+						<pre>

+&lt;log4javascript:event logger="[default]" timestamp="1201048234203" level="ERROR"&gt;

+&lt;log4javascript:message&gt;&lt;![CDATA[Big problem!]]&gt;&lt;/log4javascript:message&gt;

+&lt;log4javascript:exception&gt;&lt;![CDATA[Nasty error on line number 1

+	in file http://log4javascript.org/test.html]]&gt;&lt;/log4javascript:exception&gt;

+&lt;/log4javascript:event&gt;

+</pre>

+						<p><strong>Notes</strong></p>

+						<ul>

+							<li>

+								This layout supports batching of log messages when used in an

+								<code><a href="#ajaxappender">AjaxAppender</a></code>. A batch of

+								messages is simply concatenated to form a string of several XML

+								frgaments similar to that above.

+							</li>

+							<li>

+								The <code>&lt;log4javascript:exception&gt;</code> element is only present if an

+								exception was passed into the original log call.

+							</li>

+							<li>

+								As of version 1.4, timestamps are returned as milliseconds since midnight of

+								January 1, 1970 rather than seconds as in previous versions. This allows finer

+								measurement of the time a logging event occurred and is also the JavaScript

+								<code>Date</code> object's standard measurement.

+							</li>

+							<li>

+								Also as of version 1.4, multiple messages may be specified as separate parameters

+								in a single logging call. In <code>XmlLayout</code>, multiple messages may be

+								formatted as a single combined message or may be formated as several

+								<code>&lt;log4javascript:message&gt;</code> elements inside one

+								<code>&lt;log4javascript:messages&gt;</code> element as shown below:

+								<br />

+								<pre>

+&lt;log4javascript:event logger="[default]" timestamp="1201048234203" level="ERROR"&gt;

+&lt;log4javascript:messages&gt;

+	&lt;log4javascript:message&gt;&lt;![CDATA[Big problem!]]&gt;&lt;/log4javascript:message&gt;

+	&lt;log4javascript:message&gt;&lt;![CDATA[Value of x when this error

+		occurred: 3]]&gt;&lt;/log4javascript:message&gt;

+&lt;/log4javascript:messages&gt;

+&lt;log4javascript:exception&gt;&lt;![CDATA[Nasty error on line number 1

+	in file http://log4javascript.org/test.html]]&gt;&lt;/log4javascript:exception&gt;

+&lt;/log4javascript:event&gt;

+</pre>

+							</li>

+							<li>

+								As of version 1.3, custom fields may be added to the output. Each field will

+								add a tag of the following form inside the <code>&lt;log4javascript:event&gt;</code>

+								tag:

+								<br />

+								<pre>

+&lt;log4javascript:customfield name="sessionid"&gt;&lt;![CDATA[1234]]&gt;&lt;/log4javascript:customfield&gt;

+</pre>

+							</li>

+						</ul>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">XmlLayout</div>

+								<div class="methodsignature"><code><strong>XmlLayout</strong>([Boolean <em>combineMessages</em>])</code></div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">combineMessages</code>

+										<div>

+											Whether or not to format multiple log messages as a combined single

+											<code>&lt;log4javascript:message&gt;</code> element

+											composed of each individual message separated by line breaks or to include

+											a <code>&lt;log4javascript:message&gt;</code> element for each message inside

+											one <code>&lt;log4javascript:messages&gt;</code> element.

+											If not specified, defaults to <code>true</code>.

+										</div>

+									</li>

+								</ul>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="jsonlayout">

+						<h3>JsonLayout</h3>

+						<p class="editions">Editions: <strong>Standard, Production</strong></p>

+						<p>

+							Formats a logging event into JavaScript Object Notation (JSON).

+							JSON is a subset of JavaScript's object literal syntax, meaning that log

+							messages formatted with this layout can be interpreted directly by JavaScript

+							and converted into objects. See

+							<a href="http://json.org/" target="_blank" title="json.org (opens in new window)">json.org</a> for more details

+							about JSON.

+						</p>

+						<p>Example:</p>

+						<pre>

+{

+	"logger": "[default]",

+	"timeStamp": 1201048234203,

+	"level": "ERROR",

+	"url": "http://log4javascript.org/test.html",

+	"message": "Big problem!",

+	"exception": "Nasty error on line number 1 in file

+		http://log4javascript.org/test.html"

+}

+</pre>

+						<p>

+							The <code>exception</code> property is only present if an exception was passed

+							into the original log call.

+						</p>

+						<p><strong>Notes</strong></p>

+						<ul>

+							<li>

+								This layout supports batching of log messages when used in an

+								<code><a href="#ajaxappender">AjaxAppender</a></code>. When sent singly

+								the layout formats the log message as a single JavaScript object literal;

+								when sent as a batch, the messages are formatted as an array literal whose

+								elements are log message objects.

+							</li>

+							<li>

+								<p>

+									As of version 1.3, custom fields may be added to the output. Each field will

+									add a property of the following form to the main object literal:

+								</p>

+								<pre>

+	"sessionid": 1234

+</pre>

+							</li>

+							<li>

+								From version 1.4, the variable names used for log event properties such as

+								the message, timestamp and exception are specified using the <code>setKeys()</code>

+								method of <code><a href="#layout">Layout</a></code>.

+							</li>

+							<li>

+								<p>

+									Also as of version 1.4, multiple messages may be specified as separate parameters

+									in a single logging call. In <code>JsonLayout</code>, multiple messages may be

+									formatted as a single combined message or may be formated as an array of messages

+									as shown below:

+								</p>

+								<pre>

+{

+	"logger": "[default]",

+	"timeStamp": 1201048234203,

+	"level": "ERROR",

+	"url": "http://log4javascript.org/test.html",

+	"message": [

+		"Big problem!",

+		"Value of x when this error occurred: 3"

+	],

+	"exception": "Nasty error on line number 1 in file

+		http://log4javascript.org/test.html"

+}

+</pre>

+							</li>

+						</ul>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">JsonLayout</div>

+								<div class="methodsignature"><code><strong>JsonLayout</strong>([Boolean <em>readable</em>, Boolean <em>combineMessages</em>])</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">readable</code>

+										<div>

+											Whether or not to format each log message with line breaks and tabs.

+											If not specified, defaults to <code>false</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">combineMessages</code>

+										<div>

+											Whether or not to format multiple log messages as a combined single

+											<code>message</code> property composed of each individual message separated by line

+											breaks or to format multiple messages as an array.

+											If not specified, defaults to <code>true</code>.

+										</div>

+									</li>

+								</ul>

+							</li>

+						</ul>

+						<h4>Methods</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">isReadable</div>

+								<div class="methodsignature"><code>Boolean <strong>isReadable</strong>()</code></div>

+								<div class="summary">

+									Returns whether or not to each log message is formatted with line breaks and tabs.

+								</div>

+								<p><strong>Notes</strong></p>

+								<ul>

+									<li>

+										<p>

+											<code>setReadable</code> has been removed in version 1.4. This property can

+											be set via the constructor.

+										</p>

+									</li>

+								</ul>

+							</li>

+						</ul>

+					</div>

+					<div id="httppostdatalayout">

+						<h3>HttpPostDataLayout</h3>

+						<p class="editions">Editions: <strong>Standard, Production</strong></p>

+						<p>

+							Formats the log message as a simple URL-encoded string from which a simple

+							server-side script may extract parameters such as the log message, severity

+							and timestamp. This is the default layout for

+							<code><a href="#ajaxappender">AjaxAppender</a></code>.

+						</p>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">HttpPostDataLayout</div>

+								<div class="methodsignature"><code><strong>HttpPostDataLayout</strong>()</code></div>

+							</li>

+						</ul>

+						<p><strong>Notes</strong></p>

+						<ul>

+							<li>

+								As of version 1.3, custom fields may be added to the output. Each field will

+								be added as a parameter to the post data.

+							</li>

+							<li>

+								From version 1.4, the variable names used for log event properties such as

+								the message, timestamp and exception are specified using the <code>setKeys()</code>

+								method of <code><a href="#layout">Layout</a></code>.

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+				</div>

+				<div id="enabling">

+					<h2>Enabling / disabling log4javascript</h2>

+					<p>

+						All logging can be enabled or disabled in log4javascript in a number of ways:

+					</p>

+					<ul>

+						<li>

+							At any time, you can call

+							<code>log4javascript.setEnabled(<em>enabled</em>)</code>. This will

+							enable or disable all logging, depending on whether <code>enabled</code>

+							is set to <code>true</code> or <code>false</code>.

+						</li>

+						<li>

+							<p>

+								Assign a value to the global variable <code>log4javascript_disabled</code>.

+								The idea of this is so that you can enable or disable logging for a whole site by

+								including a JavaScript file in all your pages, and allowing this file to be

+								included <strong>before</strong> log4javascript.js to guarantee that no logging

+								can take place without having to alter log4javascript.js itself. Your included

+								.js file would include a single line such as the following:

+							</p>

+							<p>

+								<code>var log4javascript_disabled = true;</code>

+							</p>

+						</li>

+						<li>

+							Assign your logger object a value of <code>log4javascript.getNullLogger()</code>.

+						</li>

+						<li>

+							Replace your copy of log4javascript_x.js with stubs/log4javascript_x.js, provided in the

+							distribution. This file has a stub version of each of the functions and methods

+							in the log4javascript API and can simply be dropped in in place of the main file.

+							The compressed version of the stub is typically 15 times smaller than the

+							compressed version of the main file.

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="errorhandling">

+					<h2>log4javascript error handling</h2>

+					<p>

+						log4javascript has a single rudimentary logger-like object of its own to handle

+						messages generated by log4javascript itself. This logger is called <code>LogLog</code>

+						and is accessed via <code>log4javascript.logLog</code>.

+					</p>

+					<div id="loglog">

+						<h4>Methods</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">setQuietMode</div>

+								<div class="methodsignature"><code>void <strong>setQuietMode</strong>(Boolean <em>quietMode</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">quietMode</code>

+										<div>

+											Whether to turn quiet mode on or off.

+										</div>

+									</li>

+								</ul>

+								<div class="summary">

+									Sets whether <code>LogLog</code> is in quiet mode or not. In quiet mode, no

+									messages sent to <code>LogLog</code> have any visible effect. By default,

+									quiet mode is switched off.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setAlertAllErrors</div>

+								<div class="methodsignature"><code>void <strong>setAlertAllErrors</strong>(Boolean <em>alertAllErrors</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">showAllErrors</code>

+										<div>

+											Whether to show all errors or just the first.

+										</div>

+									</li>

+								</ul>

+								<div class="summary">

+									Sets how many errors <code>LogLog</code> will display alerts for. By default,

+									only the first error encountered generates an alert to the user. If you turn

+									all errors on by supplying <code>true</code> to this method then all errors

+									will generate alerts.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">debug</div>

+								<div class="methodsignature"><code>void <strong>debug</strong>(String <em>message</em>[, Error <em>exception</em>])</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">message</code>

+									</li>

+									<li class="param">

+										<code class="paramname">exception</code>

+										[<em>optional</em>]

+									</li>

+								</ul>

+								<div class="summary">

+									Logs a debugging message to an in-memory list. This implementation is new in version 1.4.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">displayDebug</div>

+								<div class="methodsignature"><code>void <strong>displayDebug</strong>()</code></div>

+								<div class="summary">

+									Displays an alert of all debugging messages. This method is new in version 1.4.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">warn</div>

+								<div class="methodsignature"><code>void <strong>warn</strong>(String <em>message</em>[, Error <em>exception</em>])</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">message</code>

+									</li>

+									<li class="param">

+										<code class="paramname">exception</code>

+										[<em>optional</em>]

+									</li>

+								</ul>

+								<div class="summary">

+									Currently has no effect.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">error</div>

+								<div class="methodsignature"><code>void <strong>error</strong>(String <em>message</em>[, Error <em>exception</em>])</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">message</code>

+									</li>

+									<li class="param">

+										<code class="paramname">exception</code>

+										[<em>optional</em>]

+									</li>

+								</ul>

+								<div class="summary">

+									Generates an alert to the user if and only if the error is the first one

+									encountered and <code>setAlertAllErrors(true)</code> has not been called.

+								</div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+				</div>

+				<div id="differences">

+					<h2>Differences between log4javascript and log4j</h2>

+					<p>

+						For the sake of keeping log4javascript as light and useful as possible, many

+						of the features of log4j that seem over-complex or inappropriate for

+						JavaScript have not been implemented. These include:

+					</p>

+					<ul>

+						<li>Filters</li>

+						<li>Configurators</li>

+						<li>Renderers</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+  				</div>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/manual_lite.html b/planetstack/core/static/log4javascript-1.4.6/docs/manual_lite.html
new file mode 100644
index 0000000..74e5a7d
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/docs/manual_lite.html
@@ -0,0 +1,383 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript 1.4 Lite manual</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="index.html">docs</a>

+					| <a class="navitem" href="quickstart.html">quick start</a>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript 1.4 Lite manual</h1>

+				<h2>Contents</h2>

+				<ul>

+					<li><a href="#intro">Introduction</a></li>

+					<li><a href="#log4javascript">log4javascript static properties/methods</a></li>

+					<li><a href="#levels">Levels</a></li>

+					<li><a href="#loggers">Loggers</a></li>

+					<li><a href="#enabling">Enabling / disabling log4javascript Lite</a></li>

+				</ul>

+				<div id="intro">

+					<h2>Introduction</h2>

+					<p>

+						log4javascript Lite is designed to be a basic, lightweight, cross-browser logging tool. It

+						provides functions to log messages of different severity to a pop-up window using the exactly

+						the same syntax as log4javascript. It is designed for situations when the key requirement is just

+						to display logging messages without needing all the features of the standard version of

+						log4javascript. 

+					</p>

+					<p>

+						Below is the complete list of functions and properties available in log4javascript Lite.

+						They make up a small subset of those provided by the standard version of

+						log4javascript. Each function is <strong>named and called identically to the equivalent

+						function in log4javascript</strong>. Please refer to the

+						<a href="manual.html">log4javascript manual</a> for a detailed explanation

+						of all the concepts alluded to in this document.

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="log4javascript">

+					<h2>log4javascript static properties/methods</h2>

+					<h4>Properties</h4>

+					<ul class="propertieslist">

+						<li class="property">

+							<div class="name">version</div>

+							<div class="summary">

+								The version number of your copy of log4javascript.

+							</div>

+						</li>

+						<li class="property">

+							<div class="name">edition</div>

+							<div class="summary">

+								The edition of your copy of log4javascript ("log4javascript_lite" in this case").

+							</div>

+						</li>

+					</ul>

+					<h4>Methods</h4>

+					<ul class="propertieslist">

+						<li class="method">

+							<div class="name">getDefaultLogger</div>

+							<div class="methodsignature"><code>Logger <strong>getDefaultLogger</strong>()</code></div>

+							<div class="summary">

+								Returns the default and only logger (apart from the null logger). The default logger

+								logs to a simple pop-up window.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getNullLogger</div>

+							<div class="methodsignature"><code>Logger <strong>getNullLogger</strong>()</code></div>

+							<div class="summary">

+								Returns an empty logger. Useful for disabling all logging.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">setEnabled</div>

+							<div class="methodsignature"><code>void <strong>setEnabled</strong>(Boolean <em>enabled</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">enabled</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Enables or disables all logging, depending on <code>enabled</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns true or false depending on whether logging is enabled.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">setShowStackTraces</div>

+							<div class="methodsignature"><code>void <strong>setShowStackTraces</strong>(Boolean <em>show</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">show</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Enables or disables displaying of error stack traces, depending on <code>show</code>.

+								By default, stack traces are not displayed. (Only works in Firefox)

+							</div>

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="levels">

+					<h2>Levels</h2>

+					<p>

+						Levels are available as static properties of the <code>log4javascript.Level</code>

+						object. In ascending order of severity:

+					</p>

+					<ol>

+						<li><code>log4javascript.Level.ALL</code></li>

+						<li><code>log4javascript.Level.TRACE</code></li>

+						<li><code>log4javascript.Level.DEBUG</code></li>

+						<li><code>log4javascript.Level.INFO</code></li>

+						<li><code>log4javascript.Level.WARN</code></li>

+						<li><code>log4javascript.Level.ERROR</code></li>

+						<li><code>log4javascript.Level.FATAL</code></li>

+						<li><code>log4javascript.Level.NONE</code></li>

+					</ol>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="loggers">

+					<h2>Loggers</h2>

+					<p>

+						There are only two loggers in log4javascript Lite: the default logger obtained

+						by calling <code>log4javascript.getDefaultLogger()</code> and the empty logger

+						returned by <code>log4javascript.getNullLogger()</code>.

+					</p>

+					<h4>Logger methods</h4>

+					<ul class="propertieslist">

+						<li class="method">

+							<div class="name">setLevel</div>

+							<div class="methodsignature"><code>void <strong>setLevel</strong>(Level <em>level</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">level</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Sets the level. Log messages of a lower level than <code>level</code> will not be logged.

+								Default value is <code>ALL</code> (unlike in log4javascript, where the default level is

+								<code>DEBUG</code>).

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getLevel</div>

+							<div class="methodsignature"><code>Level <strong>getLevel</strong>()</code></div>

+							<div class="summary">

+								Returns the level for this logger.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">trace</div>

+							<div class="methodsignature"><code>void <strong>trace</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>TRACE</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">debug</div>

+							<div class="methodsignature"><code>void <strong>debug</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>DEBUG</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">info</div>

+							<div class="methodsignature"><code>void <strong>info</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>INFO</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">warn</div>

+							<div class="methodsignature"><code>void <strong>warn</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>WARN</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">error</div>

+							<div class="methodsignature"><code>void <strong>error</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>ERROR</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">fatal</div>

+							<div class="methodsignature"><code>void <strong>fatal</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>FATAL</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isEnabledFor</div>

+							<div class="methodsignature"><code>Boolean <strong>isEnabledFor</strong>(Level <em>level</em>, Error <em>exception</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">level</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Returns whether the logger is enabled for the specified level. 

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isTraceEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isTraceEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>TRACE</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isDebugEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isDebugEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>DEBUG</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isInfoEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isInfoEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>INFO</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isWarnEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isWarnEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>WARN</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isErrorEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isErrorEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>ERROR</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isFatalEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isFatalEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>FATAL</code> messages.

+							</div>

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="enabling">

+					<h2>Enabling / disabling log4javascript Lite</h2>

+					<p>

+						All logging can be enabled or disabled in log4javascript Lite in a number of ways:

+					</p>

+					<ul>

+						<li>

+							At any time, you can call

+							<code>log4javascript.setEnabled(<em>enabled</em>)</code>. This will

+							enable or disable all logging, depending on whether <code>enabled</code>

+							is set to <code>true</code> or <code>false</code>.

+						</li>

+						<li>

+							Assign your logger object a value of <code>log4javascript.getNullLogger()</code>.

+						</li>

+						<li>

+							Replace your copy of log4javascript_lite.js with stubs/log4javascript_lite.js, provided in the

+							distribution. This file has a stub version of each of the functions and methods

+							in the log4javascript Lite API and can simply be dropped in in place of the main file.

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/quickstart.html b/planetstack/core/static/log4javascript-1.4.6/docs/quickstart.html
new file mode 100644
index 0000000..3bffff5
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/docs/quickstart.html
@@ -0,0 +1,230 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript quick start tutorial</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="index.html">docs</a>

+					| <span class="navitem">quick start</span>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript quick start tutorial</h1>

+				<h2>Three step guide</h2>

+				<ol>

+					<li>

+						<h3>Download the code</h3>

+						<p>

+							Unzip the distribution and copy log4javascript.js into the desired

+							location. No other files are necessary.

+						</p>

+					</li>

+					<li>

+						<h3>Initialize log4javascript in your web page</h3>

+						<p>

+							Include log4javascript.js in your page using the code below. This

+							code assumes log4javascript is stored in the same directory as

+							your web page.

+						</p>

+						<pre class="code">

+&lt;script type="text/javascript" src="log4javascript.js"&gt;&lt;/script&gt;

+&lt;script type="text/javascript"&gt;

+	var log = log4javascript.getDefaultLogger();

+&lt;/script&gt;

+</pre>

+						<p>

+							The default logger uses a <code><a href="manual.html#popupappender">PopUpAppender</a></code>

+							which opens a pop-up window. By default, this window will open when the first

+							log message is written. For this to work, you will need to disable any pop-up blockers

+							you may have.

+						</p>

+					</li>

+					<li>

+						<h3>Include logging statements in your code</h3>

+						<p>

+							You have six logging methods at your disposal, depending on the severity

+							of the message you wish to log. By default, all messages are logged

+							in the pop-up window. The logging methods are:

+						</p>

+						<ul>

+							<li><code>log.trace(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>

+							<li><code>log.debug(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>

+							<li><code>log.info(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>

+							<li><code>log.warn(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>

+							<li><code>log.error(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>

+							<li><code>log.fatal(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>

+						</ul>

+						<p>

+							And that's it, log away. Below are some examples of common types of logging.

+						</p>

+					</li>

+				</ol>

+				<h2>Logging examples</h2>

+				<ol>

+					<li>

+						<h3>A simple logging message string</h3>

+						<pre class="code">

+	log.info("Hello world");

+</pre>

+displays

+						<pre class="console info">

+19:52:03 INFO  - Hello world

+</pre>

+					</li>

+					<li>

+						<h3>Logging an error with a message</h3>

+						<pre class="code">

+	try {

+		throw new Error("Faking something going wrong!");

+	} catch (e) {

+		log.error("An error occurred", e);

+	}

+</pre>

+displays

+						<pre class="console error">

+19:52:32 ERROR - An error occurred

+Exception: Faking something going wrong! on line number 80 in file basic.html

+</pre>

+					</li>

+					<li>

+						<h3>Logging multiple messages with one logging call</h3>

+						<pre class="code">

+	var a = "Hello";

+	var b = 3;

+	log.debug(a, b);

+</pre>

+displays

+						<pre class="console debug">

+19:53:05 DEBUG  - Hello 3

+</pre>

+					</li>

+					<li>

+						<h3>Logging an object</h3>

+						<p>Logging an object:</p>

+						<pre class="code">

+	var obj = new Object();

+	obj.name = "Octopus";

+	obj.tentacles = 8;

+	log.info(obj);

+</pre>

+displays

+						<pre class="console info">

+19:53:17 INFO  - {

+	name: Octopus,

+	tentacles: 8

+}

+</pre>

+					</li>

+				</ol>

+				<h2>Tweaking the default logger</h2>

+				<p>

+					The default logger is fine as a starting point, but what if you want the default logger

+					with a few different options (say, bringing the pop-up to the front whenever a log message is

+					logged, or having new log messages appear at the top of the pop-up rather than the bottom)?

+				</p>

+				<p>

+					In this case, you will need to create a new logger, then create a

+					<code><a href="manual.html#popupappender">PopUpAppender</a></code>, set options

+					on it, and add it to the logger:

+				</p>

+				<pre class="code">

+&lt;script type="text/javascript" src="log4javascript.js"&gt;&lt;/script&gt;

+&lt;script type="text/javascript"&gt;

+	// Create the logger

+	var log = log4javascript.getLogger();

+

+	// Create a PopUpAppender with default options

+	var popUpAppender = new log4javascript.PopUpAppender();

+

+	// Change the desired configuration options

+	popUpAppender.setFocusPopUp(true);

+	popUpAppender.setNewestMessageAtTop(true);

+

+	// Add the appender to the logger

+	log.addAppender(popUpAppender);

+

+	// Test the logger

+	log.debug("Hello world!");

+&lt;/script&gt;

+</pre>

+				<p>

+					<a href="../examples/example_quickstart_1.html" title="View example (opens in new window)"

+						target="_blank">See this example in action</a> (opens in new window)

+				</p>

+				<p>

+					Refer to the manual for more information about

+					<a href="manual.html#configuration">configuring appenders</a> and more

+					details about <code><a href="manual.html#popupappender">PopUpAppender</a></code>.

+				</p>

+				<h2>Sending log messages to the server</h2>

+				<p>

+					For this you will need to use an <code><a href="manual.html#ajaxappender">AjaxAppender</a></code>

+					as follows:

+				</p>

+				<pre class="code">

+	var ajaxAppender = new log4javascript.AjaxAppender(<em>URL</em>);

+	log.addAppender(ajaxAppender);

+</pre>

+				<p>

+					Now your log messages will appear in the pop-up window and be sent

+					asynchronously to the URL you specify in the form of HTTP post parameters.

+					No server-side code to process these requests is provided with log4javascript.

+				</p>

+				<p>

+					See <code><a href="manual.html#ajaxappender">AjaxAppender</a></code> for more details

+					on formatting log messages.

+				</p>

+				<h2>Changing the format of log messages</h2>

+				<p>

+					Using a <code><a href="manual.html#layouts">Layout</a></code>, you can

+					format log messages however you like. For example:

+				</p>

+				<pre class="code">

+	var log = log4javascript.getLogger("mylogger");

+	var popUpAppender = new log4javascript.PopUpAppender();

+	var layout = new log4javascript.PatternLayout("[%-5p] %m");

+	popUpAppender.setLayout(layout);

+</pre>

+				<p>A call to</p>

+				<pre class="code">

+	log.debug("Hello world");

+</pre>

+				<p>will now result in output in the pop-up window of </p>

+				<pre class="console debug">

+[DEBUG] Hello world

+</pre>

+				<p>

+					See <code><a href="manual.html#patternlayout">PatternLayout</a></code> for more details

+					on formatting log messages.

+				</p>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/whatsnew.html b/planetstack/core/static/log4javascript-1.4.6/docs/whatsnew.html
new file mode 100644
index 0000000..6e4e06f
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/docs/whatsnew.html
@@ -0,0 +1,86 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - what's new in version 1.4</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="index.html">docs</a>

+					| <a class="navitem" href="quickstart.html">quick start</a>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript - what's new in version 1.4</h1>

+				<ul>

+					<li>

+						log4javascript now comes in three different editions: Standard, Production

+						and Lite. <a href="distribution.html">Full details here</a>.

+					</li>

+					<li>

+						Loggers are now hierarchical and work exactly the same as log4j loggers.

+						This means that a logger with no level set on it inherits its level from its parent,

+						and inherits all of its parents appenders.

+					</li>

+					<li>

+						The logging console used by <code><a href="manual.html#popupappender">PopUpAppender</a></code> and

+						<code><a href="manual.html#inpageappender">InPageAppender</a></code>now has a command line, featuring

+						a command history navigated with the up and down arrow keys and a number of built-in command line

+						functions.

+					</li>

+					<li>

+						It is now possible to specify multiple messages in a single log call.

+					</li>

+					<li>

+						Log messages may be grouped in the logging console.

+					</li>

+					<li>

+						Built-in timers.

+					</li>

+					<li>

+						Improved <code><a href="manual.html#ajaxappender">AjaxAppender</a></code>, with the ability

+						to send all pending log calls to the server when navigating away from a page. Timestamps now

+						include milliseconds. All log messages or batches of log messages are now posted as

+						name-value pairs.

+					</li>

+					<li>

+						Support for IE8 beta 2.

+					</li>

+					<li>

+						Many minor enhancements and bug fixes. See the <a href="../changelog.txt">change log</a> for full

+						details.

+					</li>

+				</ul>

+				<p>

+					Please note that there are a few minor <a href="backwardsincompatibilities.html">incompatibilities

+					with earlier versions of log4javascript</a>.

+				</p>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/examples/demo.html b/planetstack/core/static/log4javascript-1.4.6/examples/demo.html
new file mode 100644
index 0000000..118b879
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/examples/demo.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript demo redirect</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="noindex" />

+		<meta http-equiv="refresh" content="0; url=../demos/basic.html" />

+	</head>

+	<body>

+		This page has been replaced by <a href="/demos/basic.html">the basic demo page</a>.

+		Please use this link if you are not redirected automatically.

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/examples/example_manual.html b/planetstack/core/static/log4javascript-1.4.6/examples/example_manual.html
new file mode 100644
index 0000000..68189e3
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/examples/example_manual.html
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript example from  manual</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<script type="text/javascript" src="../js/log4javascript.js"></script>

+		<script type="text/javascript">

+			//<![CDATA[

+			var log = log4javascript.getLogger();

+			var popUpAppender = new log4javascript.PopUpAppender();

+			var popUpLayout = new log4javascript.PatternLayout("%d{HH:mm:ss} %-5p - %m%n");

+			popUpAppender.setLayout(popUpLayout);

+			log.addAppender(popUpAppender);

+			var ajaxAppender = new log4javascript.AjaxAppender("myloggingservlet.do");

+			ajaxAppender.setThreshold(log4javascript.Level.ERROR);

+			log.addAppender(ajaxAppender);

+			log.debug("Debugging message (appears in pop-up)");

+			log.error("Error message (appears in pop-up and in server log)");

+			//]]>

+		</script>

+	</head>

+	<body>

+		<h1>log4javascript example from  manual</h1>

+

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/examples/example_quickstart_1.html b/planetstack/core/static/log4javascript-1.4.6/examples/example_quickstart_1.html
new file mode 100644
index 0000000..3ae4a9f
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/examples/example_quickstart_1.html
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript quick start example 1</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<script type="text/javascript" src="../js/log4javascript.js"></script>

+		<script type="text/javascript">

+			//<![CDATA[

+			// Create the logger

+			var log = log4javascript.getLogger(); 

+		

+			// Create a PopUpAppender with default options

+			var popUpAppender = new log4javascript.PopUpAppender();

+			

+			// Change the desired configuration options

+			popUpAppender.setFocusPopUp(true);

+			popUpAppender.setNewestMessageAtTop(true);

+			

+			// Add the appender to the logger

+			log.addAppender(popUpAppender);

+			

+			// Test the logger

+			log.debug("Hello world!");

+			//]]>

+		</script>

+	</head>

+	<body>

+		<h1>log4javascript quick start example 1</h1>

+	

+	

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/examples/myloggingservlet.do b/planetstack/core/static/log4javascript-1.4.6/examples/myloggingservlet.do
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/examples/myloggingservlet.do
diff --git a/planetstack/core/static/log4javascript-1.4.6/js/console.html b/planetstack/core/static/log4javascript-1.4.6/js/console.html
new file mode 100644
index 0000000..476d272
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/console.html
@@ -0,0 +1,263 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+<head>

+<title>log4javascript</title>

+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

+<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->

+<meta http-equiv="X-UA-Compatible" content="IE=7" />

+<script type="text/javascript">var isIe = false, isIePre7 = false;</script>

+<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->

+<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->

+<script type="text/javascript">

+//<![CDATA[

+var loggingEnabled=true;var logQueuedEventsTimer=null;var logEntries=[];var logEntriesAndSeparators=[];var logItems=[];var renderDelay=100;var unrenderedLogItemsExist=false;var rootGroup,currentGroup=null;var loaded=false;var currentLogItem=null;var logMainContainer;function copyProperties(obj,props){for(var i in props){obj[i]=props[i];}}

+function LogItem(){}

+LogItem.prototype={mainContainer:null,wrappedContainer:null,unwrappedContainer:null,group:null,appendToLog:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].appendToLog();}

+this.group.update();},doRemove:function(doUpdate,removeFromGroup){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].remove();}

+this.unwrappedElementContainer=null;this.wrappedElementContainer=null;this.mainElementContainer=null;}

+if(this.group&&removeFromGroup){this.group.removeChild(this,doUpdate);}

+if(this===currentLogItem){currentLogItem=null;}},remove:function(doUpdate,removeFromGroup){this.doRemove(doUpdate,removeFromGroup);},render:function(){},accept:function(visitor){visitor.visit(this);},getUnwrappedDomContainer:function(){return this.group.unwrappedElementContainer.contentDiv;},getWrappedDomContainer:function(){return this.group.wrappedElementContainer.contentDiv;},getMainDomContainer:function(){return this.group.mainElementContainer.contentDiv;}};LogItem.serializedItemKeys={LOG_ENTRY:0,GROUP_START:1,GROUP_END:2};function LogItemContainerElement(){}

+LogItemContainerElement.prototype={appendToLog:function(){var insertBeforeFirst=(newestAtTop&&this.containerDomNode.hasChildNodes());if(insertBeforeFirst){this.containerDomNode.insertBefore(this.mainDiv,this.containerDomNode.firstChild);}else{this.containerDomNode.appendChild(this.mainDiv);}}};function SeparatorElementContainer(containerDomNode){this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="separator";this.mainDiv.innerHTML="&nbsp;";}

+SeparatorElementContainer.prototype=new LogItemContainerElement();SeparatorElementContainer.prototype.remove=function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;};function Separator(){this.rendered=false;}

+Separator.prototype=new LogItem();copyProperties(Separator.prototype,{render:function(){var containerDomNode=this.group.contentDiv;if(isIe){this.unwrappedElementContainer=new SeparatorElementContainer(this.getUnwrappedDomContainer());this.wrappedElementContainer=new SeparatorElementContainer(this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new SeparatorElementContainer(this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}

+this.content=this.formattedMessage;this.rendered=true;}});function GroupElementContainer(group,containerDomNode,isRoot,isWrapped){this.group=group;this.containerDomNode=containerDomNode;this.isRoot=isRoot;this.isWrapped=isWrapped;this.expandable=false;if(this.isRoot){if(isIe){this.contentDiv=logMainContainer.appendChild(document.createElement("div"));this.contentDiv.id=this.isWrapped?"log_wrapped":"log_unwrapped";}else{this.contentDiv=logMainContainer;}}else{var groupElementContainer=this;this.mainDiv=document.createElement("div");this.mainDiv.className="group";this.headingDiv=this.mainDiv.appendChild(document.createElement("div"));this.headingDiv.className="groupheading";this.expander=this.headingDiv.appendChild(document.createElement("span"));this.expander.className="expander unselectable greyedout";this.expander.unselectable=true;var expanderText=this.group.expanded?"-":"+";this.expanderTextNode=this.expander.appendChild(document.createTextNode(expanderText));this.headingDiv.appendChild(document.createTextNode(" "+this.group.name));this.contentDiv=this.mainDiv.appendChild(document.createElement("div"));var contentCssClass=this.group.expanded?"expanded":"collapsed";this.contentDiv.className="groupcontent "+contentCssClass;this.expander.onclick=function(){if(groupElementContainer.group.expandable){groupElementContainer.group.toggleExpanded();}};}}

+GroupElementContainer.prototype=new LogItemContainerElement();copyProperties(GroupElementContainer.prototype,{toggleExpanded:function(){if(!this.isRoot){var oldCssClass,newCssClass,expanderText;if(this.group.expanded){newCssClass="expanded";oldCssClass="collapsed";expanderText="-";}else{newCssClass="collapsed";oldCssClass="expanded";expanderText="+";}

+replaceClass(this.contentDiv,newCssClass,oldCssClass);this.expanderTextNode.nodeValue=expanderText;}},remove:function(){if(!this.isRoot){this.headingDiv=null;this.expander.onclick=null;this.expander=null;this.expanderTextNode=null;this.contentDiv=null;this.containerDomNode=null;this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;}},reverseChildren:function(){var node=null;var childDomNodes=[];while((node=this.contentDiv.firstChild)){this.contentDiv.removeChild(node);childDomNodes.push(node);}

+while((node=childDomNodes.pop())){this.contentDiv.appendChild(node);}},update:function(){if(!this.isRoot){if(this.group.expandable){removeClass(this.expander,"greyedout");}else{addClass(this.expander,"greyedout");}}},clear:function(){if(this.isRoot){this.contentDiv.innerHTML="";}}});function Group(name,isRoot,initiallyExpanded){this.name=name;this.group=null;this.isRoot=isRoot;this.initiallyExpanded=initiallyExpanded;this.elementContainers=[];this.children=[];this.expanded=initiallyExpanded;this.rendered=false;this.expandable=false;}

+Group.prototype=new LogItem();copyProperties(Group.prototype,{addChild:function(logItem){this.children.push(logItem);logItem.group=this;},render:function(){if(isIe){var unwrappedDomContainer,wrappedDomContainer;if(this.isRoot){unwrappedDomContainer=logMainContainer;wrappedDomContainer=logMainContainer;}else{unwrappedDomContainer=this.getUnwrappedDomContainer();wrappedDomContainer=this.getWrappedDomContainer();}

+this.unwrappedElementContainer=new GroupElementContainer(this,unwrappedDomContainer,this.isRoot,false);this.wrappedElementContainer=new GroupElementContainer(this,wrappedDomContainer,this.isRoot,true);this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{var mainDomContainer=this.isRoot?logMainContainer:this.getMainDomContainer();this.mainElementContainer=new GroupElementContainer(this,mainDomContainer,this.isRoot,false);this.elementContainers=[this.mainElementContainer];}

+this.rendered=true;},toggleExpanded:function(){this.expanded=!this.expanded;for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].toggleExpanded();}},expand:function(){if(!this.expanded){this.toggleExpanded();}},accept:function(visitor){visitor.visitGroup(this);},reverseChildren:function(){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].reverseChildren();}}},update:function(){var previouslyExpandable=this.expandable;this.expandable=(this.children.length!==0);if(this.expandable!==previouslyExpandable){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].update();}}},flatten:function(){var visitor=new GroupFlattener();this.accept(visitor);return visitor.logEntriesAndSeparators;},removeChild:function(child,doUpdate){array_remove(this.children,child);child.group=null;if(doUpdate){this.update();}},remove:function(doUpdate,removeFromGroup){for(var i=0,len=this.children.length;i<len;i++){this.children[i].remove(false,false);}

+this.children=[];this.update();if(this===currentGroup){currentGroup=this.group;}

+this.doRemove(doUpdate,removeFromGroup);},serialize:function(items){items.push([LogItem.serializedItemKeys.GROUP_START,this.name]);for(var i=0,len=this.children.length;i<len;i++){this.children[i].serialize(items);}

+if(this!==currentGroup){items.push([LogItem.serializedItemKeys.GROUP_END]);}},clear:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clear();}}});function LogEntryElementContainer(){}

+LogEntryElementContainer.prototype=new LogItemContainerElement();copyProperties(LogEntryElementContainer.prototype,{remove:function(){this.doRemove();},doRemove:function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;this.contentElement=null;this.containerDomNode=null;},setContent:function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=content;}},setSearchMatch:function(isMatch){var oldCssClass=isMatch?"searchnonmatch":"searchmatch";var newCssClass=isMatch?"searchmatch":"searchnonmatch";replaceClass(this.mainDiv,newCssClass,oldCssClass);},clearSearch:function(){removeClass(this.mainDiv,"searchmatch");removeClass(this.mainDiv,"searchnonmatch");}});function LogEntryWrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.mainDiv.className="logentry wrapped "+this.logEntry.level;this.contentElement=this.mainDiv;}

+LogEntryWrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryWrappedElementContainer.prototype.setContent=function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=wrappedContent;}};function LogEntryUnwrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry unwrapped "+this.logEntry.level;this.pre=this.mainDiv.appendChild(document.createElement("pre"));this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.pre.className="unwrapped";this.contentElement=this.pre;}

+LogEntryUnwrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryUnwrappedElementContainer.prototype.remove=function(){this.doRemove();this.pre=null;};function LogEntryMainElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry nonielogentry "+this.logEntry.level;this.contentElement=this.mainDiv.appendChild(document.createElement("span"));this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));}

+LogEntryMainElementContainer.prototype=new LogEntryElementContainer();function LogEntry(level,formattedMessage){this.level=level;this.formattedMessage=formattedMessage;this.rendered=false;}

+LogEntry.prototype=new LogItem();copyProperties(LogEntry.prototype,{render:function(){var logEntry=this;var containerDomNode=this.group.contentDiv;if(isIe){this.formattedMessage=this.formattedMessage.replace(/\r\n/g,"\r");this.unwrappedElementContainer=new LogEntryUnwrappedElementContainer(this,this.getUnwrappedDomContainer());this.wrappedElementContainer=new LogEntryWrappedElementContainer(this,this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new LogEntryMainElementContainer(this,this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}

+this.content=this.formattedMessage;this.rendered=true;},setContent:function(content,wrappedContent){if(content!=this.content){if(isIe&&(content!==this.formattedMessage)){content=content.replace(/\r\n/g,"\r");}

+for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setContent(content,wrappedContent);}

+this.content=content;}},getSearchMatches:function(){var matches=[];var i,len;if(isIe){var unwrappedEls=getElementsByClass(this.unwrappedElementContainer.mainDiv,"searchterm","span");var wrappedEls=getElementsByClass(this.wrappedElementContainer.mainDiv,"searchterm","span");for(i=0,len=unwrappedEls.length;i<len;i++){matches[i]=new Match(this.level,null,unwrappedEls[i],wrappedEls[i]);}}else{var els=getElementsByClass(this.mainElementContainer.mainDiv,"searchterm","span");for(i=0,len=els.length;i<len;i++){matches[i]=new Match(this.level,els[i]);}}

+return matches;},setSearchMatch:function(isMatch){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setSearchMatch(isMatch);}},clearSearch:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clearSearch();}},accept:function(visitor){visitor.visitLogEntry(this);},serialize:function(items){items.push([LogItem.serializedItemKeys.LOG_ENTRY,this.level,this.formattedMessage]);}});function LogItemVisitor(){}

+LogItemVisitor.prototype={visit:function(logItem){},visitParent:function(logItem){if(logItem.group){logItem.group.accept(this);}},visitChildren:function(logItem){for(var i=0,len=logItem.children.length;i<len;i++){logItem.children[i].accept(this);}},visitLogEntry:function(logEntry){this.visit(logEntry);},visitSeparator:function(separator){this.visit(separator);},visitGroup:function(group){this.visit(group);}};function GroupFlattener(){this.logEntriesAndSeparators=[];}

+GroupFlattener.prototype=new LogItemVisitor();GroupFlattener.prototype.visitGroup=function(group){this.visitChildren(group);};GroupFlattener.prototype.visitLogEntry=function(logEntry){this.logEntriesAndSeparators.push(logEntry);};GroupFlattener.prototype.visitSeparator=function(separator){this.logEntriesAndSeparators.push(separator);};window.onload=function(){if(location.search){var queryBits=unescape(location.search).substr(1).split("&"),nameValueBits;for(var i=0,len=queryBits.length;i<len;i++){nameValueBits=queryBits[i].split("=");if(nameValueBits[0]=="log4javascript_domain"){document.domain=nameValueBits[1];break;}}}

+logMainContainer=$("log");if(isIePre7){addClass(logMainContainer,"oldIe");}

+rootGroup=new Group("root",true);rootGroup.render();currentGroup=rootGroup;setCommandInputWidth();setLogContainerHeight();toggleLoggingEnabled();toggleSearchEnabled();toggleSearchFilter();toggleSearchHighlight();applyFilters();checkAllLevels();toggleWrap();toggleNewestAtTop();toggleScrollToLatest();renderQueuedLogItems();loaded=true;$("command").value="";$("command").autocomplete="off";$("command").onkeydown=function(evt){evt=getEvent(evt);if(evt.keyCode==10||evt.keyCode==13){evalCommandLine();stopPropagation(evt);}else if(evt.keyCode==27){this.value="";this.focus();}else if(evt.keyCode==38&&commandHistory.length>0){currentCommandIndex=Math.max(0,currentCommandIndex-1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}else if(evt.keyCode==40&&commandHistory.length>0){currentCommandIndex=Math.min(commandHistory.length-1,currentCommandIndex+1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}};$("command").onkeypress=function(evt){evt=getEvent(evt);if(evt.keyCode==38&&commandHistory.length>0&&evt.preventDefault){evt.preventDefault();}};$("command").onkeyup=function(evt){evt=getEvent(evt);if(evt.keyCode==27&&evt.preventDefault){evt.preventDefault();this.focus();}};document.onkeydown=function keyEventHandler(evt){evt=getEvent(evt);switch(evt.keyCode){case 69:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){evalLastCommand();cancelKeyEvent(evt);return false;}

+break;case 75:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusSearch();cancelKeyEvent(evt);return false;}

+break;case 40:case 76:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusCommandLine();cancelKeyEvent(evt);return false;}

+break;}};setTimeout(setLogContainerHeight,20);setShowCommandLine(showCommandLine);doSearch();};window.onunload=function(){if(mainWindowExists()){appender.unload();}

+appender=null;};function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}

+function setLoggingEnabled(enable){loggingEnabled=enable;}

+var appender=null;function setAppender(appenderParam){appender=appenderParam;}

+function setShowCloseButton(showCloseButton){$("closeButton").style.display=showCloseButton?"inline":"none";}

+function setShowHideButton(showHideButton){$("hideButton").style.display=showHideButton?"inline":"none";}

+var newestAtTop=false;function LogItemContentReverser(){}

+LogItemContentReverser.prototype=new LogItemVisitor();LogItemContentReverser.prototype.visitGroup=function(group){group.reverseChildren();this.visitChildren(group);};function setNewestAtTop(isNewestAtTop){var oldNewestAtTop=newestAtTop;var i,iLen,j,jLen;newestAtTop=Boolean(isNewestAtTop);if(oldNewestAtTop!=newestAtTop){var visitor=new LogItemContentReverser();rootGroup.accept(visitor);if(currentSearch){var currentMatch=currentSearch.matches[currentMatchIndex];var matchIndex=0;var matches=[];var actOnLogEntry=function(logEntry){var logEntryMatches=logEntry.getSearchMatches();for(j=0,jLen=logEntryMatches.length;j<jLen;j++){matches[matchIndex]=logEntryMatches[j];if(currentMatch&&logEntryMatches[j].equals(currentMatch)){currentMatchIndex=matchIndex;}

+matchIndex++;}};if(newestAtTop){for(i=logEntries.length-1;i>=0;i--){actOnLogEntry(logEntries[i]);}}else{for(i=0,iLen=logEntries.length;i<iLen;i++){actOnLogEntry(logEntries[i]);}}

+currentSearch.matches=matches;if(currentMatch){currentMatch.setCurrent();}}else if(scrollToLatest){doScrollToLatest();}}

+$("newestAtTop").checked=isNewestAtTop;}

+function toggleNewestAtTop(){var isNewestAtTop=$("newestAtTop").checked;setNewestAtTop(isNewestAtTop);}

+var scrollToLatest=true;function setScrollToLatest(isScrollToLatest){scrollToLatest=isScrollToLatest;if(scrollToLatest){doScrollToLatest();}

+$("scrollToLatest").checked=isScrollToLatest;}

+function toggleScrollToLatest(){var isScrollToLatest=$("scrollToLatest").checked;setScrollToLatest(isScrollToLatest);}

+function doScrollToLatest(){var l=logMainContainer;if(typeof l.scrollTop!="undefined"){if(newestAtTop){l.scrollTop=0;}else{var latestLogEntry=l.lastChild;if(latestLogEntry){l.scrollTop=l.scrollHeight;}}}}

+var closeIfOpenerCloses=true;function setCloseIfOpenerCloses(isCloseIfOpenerCloses){closeIfOpenerCloses=isCloseIfOpenerCloses;}

+var maxMessages=null;function setMaxMessages(max){maxMessages=max;pruneLogEntries();}

+var showCommandLine=false;function setShowCommandLine(isShowCommandLine){showCommandLine=isShowCommandLine;if(loaded){$("commandLine").style.display=showCommandLine?"block":"none";setCommandInputWidth();setLogContainerHeight();}}

+function focusCommandLine(){if(loaded){$("command").focus();}}

+function focusSearch(){if(loaded){$("searchBox").focus();}}

+function getLogItems(){var items=[];for(var i=0,len=logItems.length;i<len;i++){logItems[i].serialize(items);}

+return items;}

+function setLogItems(items){var loggingReallyEnabled=loggingEnabled;loggingEnabled=true;for(var i=0,len=items.length;i<len;i++){switch(items[i][0]){case LogItem.serializedItemKeys.LOG_ENTRY:log(items[i][1],items[i][2]);break;case LogItem.serializedItemKeys.GROUP_START:group(items[i][1]);break;case LogItem.serializedItemKeys.GROUP_END:groupEnd();break;}}

+loggingEnabled=loggingReallyEnabled;}

+function log(logLevel,formattedMessage){if(loggingEnabled){var logEntry=new LogEntry(logLevel,formattedMessage);logEntries.push(logEntry);logEntriesAndSeparators.push(logEntry);logItems.push(logEntry);currentGroup.addChild(logEntry);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}

+logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}

+function renderQueuedLogItems(){logQueuedEventsTimer=null;var pruned=pruneLogEntries();var initiallyHasMatches=currentSearch?currentSearch.hasMatches():false;for(var i=0,len=logItems.length;i<len;i++){if(!logItems[i].rendered){logItems[i].render();logItems[i].appendToLog();if(currentSearch&&(logItems[i]instanceof LogEntry)){currentSearch.applyTo(logItems[i]);}}}

+if(currentSearch){if(pruned){if(currentSearch.hasVisibleMatches()){if(currentMatchIndex===null){setCurrentMatchIndex(0);}

+displayMatches();}else{displayNoMatches();}}else if(!initiallyHasMatches&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}}

+if(scrollToLatest){doScrollToLatest();}

+unrenderedLogItemsExist=false;}

+function pruneLogEntries(){if((maxMessages!==null)&&(logEntriesAndSeparators.length>maxMessages)){var numberToDelete=logEntriesAndSeparators.length-maxMessages;var prunedLogEntries=logEntriesAndSeparators.slice(0,numberToDelete);if(currentSearch){currentSearch.removeMatches(prunedLogEntries);}

+var group;for(var i=0;i<numberToDelete;i++){group=logEntriesAndSeparators[i].group;array_remove(logItems,logEntriesAndSeparators[i]);array_remove(logEntries,logEntriesAndSeparators[i]);logEntriesAndSeparators[i].remove(true,true);if(group.children.length===0&&group!==currentGroup&&group!==rootGroup){array_remove(logItems,group);group.remove(true,true);}}

+logEntriesAndSeparators=array_removeFromStart(logEntriesAndSeparators,numberToDelete);return true;}

+return false;}

+function group(name,startExpanded){if(loggingEnabled){initiallyExpanded=(typeof startExpanded==="undefined")?true:Boolean(startExpanded);var newGroup=new Group(name,false,initiallyExpanded);currentGroup.addChild(newGroup);currentGroup=newGroup;logItems.push(newGroup);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}

+logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}

+function groupEnd(){currentGroup=(currentGroup===rootGroup)?rootGroup:currentGroup.group;}

+function mainPageReloaded(){currentGroup=rootGroup;var separator=new Separator();logEntriesAndSeparators.push(separator);logItems.push(separator);currentGroup.addChild(separator);}

+function closeWindow(){if(appender&&mainWindowExists()){appender.close(true);}else{window.close();}}

+function hide(){if(appender&&mainWindowExists()){appender.hide();}}

+var mainWindow=window;var windowId="log4javascriptConsoleWindow_"+new Date().getTime()+"_"+(""+Math.random()).substr(2);function setMainWindow(win){mainWindow=win;mainWindow[windowId]=window;if(opener&&closeIfOpenerCloses){pollOpener();}}

+function pollOpener(){if(closeIfOpenerCloses){if(mainWindowExists()){setTimeout(pollOpener,500);}else{closeWindow();}}}

+function mainWindowExists(){try{return(mainWindow&&!mainWindow.closed&&mainWindow[windowId]==window);}catch(ex){}

+return false;}

+var logLevels=["TRACE","DEBUG","INFO","WARN","ERROR","FATAL"];function getCheckBox(logLevel){return $("switch_"+logLevel);}

+function getIeWrappedLogContainer(){return $("log_wrapped");}

+function getIeUnwrappedLogContainer(){return $("log_unwrapped");}

+function applyFilters(){for(var i=0;i<logLevels.length;i++){if(getCheckBox(logLevels[i]).checked){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}

+updateSearchFromFilters();}

+function toggleAllLevels(){var turnOn=$("switch_ALL").checked;for(var i=0;i<logLevels.length;i++){getCheckBox(logLevels[i]).checked=turnOn;if(turnOn){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}}

+function checkAllLevels(){for(var i=0;i<logLevels.length;i++){if(!getCheckBox(logLevels[i]).checked){getCheckBox("ALL").checked=false;return;}}

+getCheckBox("ALL").checked=true;}

+function clearLog(){rootGroup.clear();currentGroup=rootGroup;logEntries=[];logItems=[];logEntriesAndSeparators=[];doSearch();}

+function toggleWrap(){var enable=$("wrap").checked;if(enable){addClass(logMainContainer,"wrap");}else{removeClass(logMainContainer,"wrap");}

+refreshCurrentMatch();}

+var searchTimer=null;function scheduleSearch(){try{clearTimeout(searchTimer);}catch(ex){}

+searchTimer=setTimeout(doSearch,500);}

+function Search(searchTerm,isRegex,searchRegex,isCaseSensitive){this.searchTerm=searchTerm;this.isRegex=isRegex;this.searchRegex=searchRegex;this.isCaseSensitive=isCaseSensitive;this.matches=[];}

+Search.prototype={hasMatches:function(){return this.matches.length>0;},hasVisibleMatches:function(){if(this.hasMatches()){for(var i=0;i<this.matches.length;i++){if(this.matches[i].isVisible()){return true;}}}

+return false;},match:function(logEntry){var entryText=String(logEntry.formattedMessage);var matchesSearch=false;if(this.isRegex){matchesSearch=this.searchRegex.test(entryText);}else if(this.isCaseSensitive){matchesSearch=(entryText.indexOf(this.searchTerm)>-1);}else{matchesSearch=(entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase())>-1);}

+return matchesSearch;},getNextVisibleMatchIndex:function(){for(var i=currentMatchIndex+1;i<this.matches.length;i++){if(this.matches[i].isVisible()){return i;}}

+for(i=0;i<=currentMatchIndex;i++){if(this.matches[i].isVisible()){return i;}}

+return-1;},getPreviousVisibleMatchIndex:function(){for(var i=currentMatchIndex-1;i>=0;i--){if(this.matches[i].isVisible()){return i;}}

+for(var i=this.matches.length-1;i>=currentMatchIndex;i--){if(this.matches[i].isVisible()){return i;}}

+return-1;},applyTo:function(logEntry){var doesMatch=this.match(logEntry);if(doesMatch){logEntry.group.expand();logEntry.setSearchMatch(true);var logEntryContent;var wrappedLogEntryContent;var searchTermReplacementStartTag="<span class=\"searchterm\">";var searchTermReplacementEndTag="<"+"/span>";var preTagName=isIe?"pre":"span";var preStartTag="<"+preTagName+" class=\"pre\">";var preEndTag="<"+"/"+preTagName+">";var startIndex=0;var searchIndex,matchedText,textBeforeMatch;if(this.isRegex){var flags=this.isCaseSensitive?"g":"gi";var capturingRegex=new RegExp("("+this.searchRegex.source+")",flags);var rnd=(""+Math.random()).substr(2);var startToken="%%s"+rnd+"%%";var endToken="%%e"+rnd+"%%";logEntryContent=logEntry.formattedMessage.replace(capturingRegex,startToken+"$1"+endToken);logEntryContent=escapeHtml(logEntryContent);var result;var searchString=logEntryContent;logEntryContent="";wrappedLogEntryContent="";while((searchIndex=searchString.indexOf(startToken,startIndex))>-1){var endTokenIndex=searchString.indexOf(endToken,searchIndex);matchedText=searchString.substring(searchIndex+startToken.length,endTokenIndex);textBeforeMatch=searchString.substring(startIndex,searchIndex);logEntryContent+=preStartTag+textBeforeMatch+preEndTag;logEntryContent+=searchTermReplacementStartTag+preStartTag+matchedText+

+preEndTag+searchTermReplacementEndTag;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+

+matchedText+searchTermReplacementEndTag;}

+startIndex=endTokenIndex+endToken.length;}

+logEntryContent+=preStartTag+searchString.substr(startIndex)+preEndTag;if(isIe){wrappedLogEntryContent+=searchString.substr(startIndex);}}else{logEntryContent="";wrappedLogEntryContent="";var searchTermReplacementLength=searchTermReplacementStartTag.length+

+this.searchTerm.length+searchTermReplacementEndTag.length;var searchTermLength=this.searchTerm.length;var searchTermLowerCase=this.searchTerm.toLowerCase();var logTextLowerCase=logEntry.formattedMessage.toLowerCase();while((searchIndex=logTextLowerCase.indexOf(searchTermLowerCase,startIndex))>-1){matchedText=escapeHtml(logEntry.formattedMessage.substr(searchIndex,this.searchTerm.length));textBeforeMatch=escapeHtml(logEntry.formattedMessage.substring(startIndex,searchIndex));var searchTermReplacement=searchTermReplacementStartTag+

+preStartTag+matchedText+preEndTag+searchTermReplacementEndTag;logEntryContent+=preStartTag+textBeforeMatch+preEndTag+searchTermReplacement;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+

+matchedText+searchTermReplacementEndTag;}

+startIndex=searchIndex+searchTermLength;}

+var textAfterLastMatch=escapeHtml(logEntry.formattedMessage.substr(startIndex));logEntryContent+=preStartTag+textAfterLastMatch+preEndTag;if(isIe){wrappedLogEntryContent+=textAfterLastMatch;}}

+logEntry.setContent(logEntryContent,wrappedLogEntryContent);var logEntryMatches=logEntry.getSearchMatches();this.matches=this.matches.concat(logEntryMatches);}else{logEntry.setSearchMatch(false);logEntry.setContent(logEntry.formattedMessage,logEntry.formattedMessage);}

+return doesMatch;},removeMatches:function(logEntries){var matchesToRemoveCount=0;var currentMatchRemoved=false;var matchesToRemove=[];var i,iLen,j,jLen;for(i=0,iLen=this.matches.length;i<iLen;i++){for(j=0,jLen=logEntries.length;j<jLen;j++){if(this.matches[i].belongsTo(logEntries[j])){matchesToRemove.push(this.matches[i]);if(i===currentMatchIndex){currentMatchRemoved=true;}}}}

+var newMatch=currentMatchRemoved?null:this.matches[currentMatchIndex];if(currentMatchRemoved){for(i=currentMatchIndex,iLen=this.matches.length;i<iLen;i++){if(this.matches[i].isVisible()&&!array_contains(matchesToRemove,this.matches[i])){newMatch=this.matches[i];break;}}}

+for(i=0,iLen=matchesToRemove.length;i<iLen;i++){array_remove(this.matches,matchesToRemove[i]);matchesToRemove[i].remove();}

+if(this.hasVisibleMatches()){if(newMatch===null){setCurrentMatchIndex(0);}else{var newMatchIndex=0;for(i=0,iLen=this.matches.length;i<iLen;i++){if(newMatch===this.matches[i]){newMatchIndex=i;break;}}

+setCurrentMatchIndex(newMatchIndex);}}else{currentMatchIndex=null;displayNoMatches();}}};function getPageOffsetTop(el,container){var currentEl=el;var y=0;while(currentEl&&currentEl!=container){y+=currentEl.offsetTop;currentEl=currentEl.offsetParent;}

+return y;}

+function scrollIntoView(el){var logContainer=logMainContainer;if(!$("wrap").checked){var logContainerLeft=logContainer.scrollLeft;var logContainerRight=logContainerLeft+logContainer.offsetWidth;var elLeft=el.offsetLeft;var elRight=elLeft+el.offsetWidth;if(elLeft<logContainerLeft||elRight>logContainerRight){logContainer.scrollLeft=elLeft-(logContainer.offsetWidth-el.offsetWidth)/2;}}

+var logContainerTop=logContainer.scrollTop;var logContainerBottom=logContainerTop+logContainer.offsetHeight;var elTop=getPageOffsetTop(el)-getToolBarsHeight();var elBottom=elTop+el.offsetHeight;if(elTop<logContainerTop||elBottom>logContainerBottom){logContainer.scrollTop=elTop-(logContainer.offsetHeight-el.offsetHeight)/2;}}

+function Match(logEntryLevel,spanInMainDiv,spanInUnwrappedPre,spanInWrappedDiv){this.logEntryLevel=logEntryLevel;this.spanInMainDiv=spanInMainDiv;if(isIe){this.spanInUnwrappedPre=spanInUnwrappedPre;this.spanInWrappedDiv=spanInWrappedDiv;}

+this.mainSpan=isIe?spanInUnwrappedPre:spanInMainDiv;}

+Match.prototype={equals:function(match){return this.mainSpan===match.mainSpan;},setCurrent:function(){if(isIe){addClass(this.spanInUnwrappedPre,"currentmatch");addClass(this.spanInWrappedDiv,"currentmatch");var elementToScroll=$("wrap").checked?this.spanInWrappedDiv:this.spanInUnwrappedPre;scrollIntoView(elementToScroll);}else{addClass(this.spanInMainDiv,"currentmatch");scrollIntoView(this.spanInMainDiv);}},belongsTo:function(logEntry){if(isIe){return isDescendant(this.spanInUnwrappedPre,logEntry.unwrappedPre);}else{return isDescendant(this.spanInMainDiv,logEntry.mainDiv);}},setNotCurrent:function(){if(isIe){removeClass(this.spanInUnwrappedPre,"currentmatch");removeClass(this.spanInWrappedDiv,"currentmatch");}else{removeClass(this.spanInMainDiv,"currentmatch");}},isOrphan:function(){return isOrphan(this.mainSpan);},isVisible:function(){return getCheckBox(this.logEntryLevel).checked;},remove:function(){if(isIe){this.spanInUnwrappedPre=null;this.spanInWrappedDiv=null;}else{this.spanInMainDiv=null;}}};var currentSearch=null;var currentMatchIndex=null;function doSearch(){var searchBox=$("searchBox");var searchTerm=searchBox.value;var isRegex=$("searchRegex").checked;var isCaseSensitive=$("searchCaseSensitive").checked;var i;if(searchTerm===""){$("searchReset").disabled=true;$("searchNav").style.display="none";removeClass(document.body,"searching");removeClass(searchBox,"hasmatches");removeClass(searchBox,"nomatches");for(i=0;i<logEntries.length;i++){logEntries[i].clearSearch();logEntries[i].setContent(logEntries[i].formattedMessage,logEntries[i].formattedMessage);}

+currentSearch=null;setLogContainerHeight();}else{$("searchReset").disabled=false;$("searchNav").style.display="block";var searchRegex;var regexValid;if(isRegex){try{searchRegex=isCaseSensitive?new RegExp(searchTerm,"g"):new RegExp(searchTerm,"gi");regexValid=true;replaceClass(searchBox,"validregex","invalidregex");searchBox.title="Valid regex";}catch(ex){regexValid=false;replaceClass(searchBox,"invalidregex","validregex");searchBox.title="Invalid regex: "+(ex.message?ex.message:(ex.description?ex.description:"unknown error"));return;}}else{searchBox.title="";removeClass(searchBox,"validregex");removeClass(searchBox,"invalidregex");}

+addClass(document.body,"searching");currentSearch=new Search(searchTerm,isRegex,searchRegex,isCaseSensitive);for(i=0;i<logEntries.length;i++){currentSearch.applyTo(logEntries[i]);}

+setLogContainerHeight();if(currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}else{displayNoMatches();}}}

+function updateSearchFromFilters(){if(currentSearch){if(currentSearch.hasMatches()){if(currentMatchIndex===null){currentMatchIndex=0;}

+var currentMatch=currentSearch.matches[currentMatchIndex];if(currentMatch.isVisible()){displayMatches();setCurrentMatchIndex(currentMatchIndex);}else{currentMatch.setNotCurrent();var nextVisibleMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextVisibleMatchIndex>-1){setCurrentMatchIndex(nextVisibleMatchIndex);displayMatches();}else{displayNoMatches();}}}else{displayNoMatches();}}}

+function refreshCurrentMatch(){if(currentSearch&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(currentMatchIndex);}}

+function displayMatches(){replaceClass($("searchBox"),"hasmatches","nomatches");$("searchBox").title=""+currentSearch.matches.length+" matches found";$("searchNav").style.display="block";setLogContainerHeight();}

+function displayNoMatches(){replaceClass($("searchBox"),"nomatches","hasmatches");$("searchBox").title="No matches found";$("searchNav").style.display="none";setLogContainerHeight();}

+function toggleSearchEnabled(enable){enable=(typeof enable=="undefined")?!$("searchDisable").checked:enable;$("searchBox").disabled=!enable;$("searchReset").disabled=!enable;$("searchRegex").disabled=!enable;$("searchNext").disabled=!enable;$("searchPrevious").disabled=!enable;$("searchCaseSensitive").disabled=!enable;$("searchNav").style.display=(enable&&($("searchBox").value!=="")&&currentSearch&&currentSearch.hasVisibleMatches())?"block":"none";if(enable){removeClass($("search"),"greyedout");addClass(document.body,"searching");if($("searchHighlight").checked){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}

+if($("searchFilter").checked){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}

+$("searchDisable").checked=!enable;}else{addClass($("search"),"greyedout");removeClass(document.body,"searching");removeClass(logMainContainer,"searchhighlight");removeClass(logMainContainer,"searchfilter");}

+setLogContainerHeight();}

+function toggleSearchFilter(){var enable=$("searchFilter").checked;if(enable){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}

+refreshCurrentMatch();}

+function toggleSearchHighlight(){var enable=$("searchHighlight").checked;if(enable){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}}

+function clearSearch(){$("searchBox").value="";doSearch();}

+function searchNext(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var nextMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextMatchIndex>currentMatchIndex||confirm("Reached the end of the page. Start from the top?")){setCurrentMatchIndex(nextMatchIndex);}}}

+function searchPrevious(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var previousMatchIndex=currentSearch.getPreviousVisibleMatchIndex();if(previousMatchIndex<currentMatchIndex||confirm("Reached the start of the page. Continue from the bottom?")){setCurrentMatchIndex(previousMatchIndex);}}}

+function setCurrentMatchIndex(index){currentMatchIndex=index;currentSearch.matches[currentMatchIndex].setCurrent();}

+function addClass(el,cssClass){if(!hasClass(el,cssClass)){if(el.className){el.className+=" "+cssClass;}else{el.className=cssClass;}}}

+function hasClass(el,cssClass){if(el.className){var classNames=el.className.split(" ");return array_contains(classNames,cssClass);}

+return false;}

+function removeClass(el,cssClass){if(hasClass(el,cssClass)){var existingClasses=el.className.split(" ");var newClasses=[];for(var i=0,len=existingClasses.length;i<len;i++){if(existingClasses[i]!=cssClass){newClasses[newClasses.length]=existingClasses[i];}}

+el.className=newClasses.join(" ");}}

+function replaceClass(el,newCssClass,oldCssClass){removeClass(el,oldCssClass);addClass(el,newCssClass);}

+function getElementsByClass(el,cssClass,tagName){var elements=el.getElementsByTagName(tagName);var matches=[];for(var i=0,len=elements.length;i<len;i++){if(hasClass(elements[i],cssClass)){matches.push(elements[i]);}}

+return matches;}

+function $(id){return document.getElementById(id);}

+function isDescendant(node,ancestorNode){while(node!=null){if(node===ancestorNode){return true;}

+node=node.parentNode;}

+return false;}

+function isOrphan(node){var currentNode=node;while(currentNode){if(currentNode==document.body){return false;}

+currentNode=currentNode.parentNode;}

+return true;}

+function escapeHtml(str){return str.replace(/&/g,"&amp;").replace(/[<]/g,"&lt;").replace(/>/g,"&gt;");}

+function getWindowWidth(){if(window.innerWidth){return window.innerWidth;}else if(document.documentElement&&document.documentElement.clientWidth){return document.documentElement.clientWidth;}else if(document.body){return document.body.clientWidth;}

+return 0;}

+function getWindowHeight(){if(window.innerHeight){return window.innerHeight;}else if(document.documentElement&&document.documentElement.clientHeight){return document.documentElement.clientHeight;}else if(document.body){return document.body.clientHeight;}

+return 0;}

+function getToolBarsHeight(){return $("switches").offsetHeight;}

+function getChromeHeight(){var height=getToolBarsHeight();if(showCommandLine){height+=$("commandLine").offsetHeight;}

+return height;}

+function setLogContainerHeight(){if(logMainContainer){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";logMainContainer.style.height=""+

+Math.max(0,windowHeight-getChromeHeight())+"px";}}

+function setCommandInputWidth(){if(showCommandLine){$("command").style.width=""+Math.max(0,$("commandLineContainer").offsetWidth-

+($("evaluateButton").offsetWidth+13))+"px";}}

+window.onresize=function(){setCommandInputWidth();setLogContainerHeight();};if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}

+return this.length;};}

+if(!Array.prototype.pop){Array.prototype.pop=function(){if(this.length>0){var val=this[this.length-1];this.length=this.length-1;return val;}};}

+if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}

+this.length=this.length-1;return firstItem;}};}

+if(!Array.prototype.splice){Array.prototype.splice=function(startIndex,deleteCount){var itemsAfterDeleted=this.slice(startIndex+deleteCount);var itemsDeleted=this.slice(startIndex,startIndex+deleteCount);this.length=startIndex;var argumentsArray=[];for(var i=0,len=arguments.length;i<len;i++){argumentsArray[i]=arguments[i];}

+var itemsToAppend=(argumentsArray.length>2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i<len;i++){this.push(itemsToAppend[i]);}

+return itemsDeleted;};}

+function array_remove(arr,val){var index=-1;for(var i=0,len=arr.length;i<len;i++){if(arr[i]===val){index=i;break;}}

+if(index>=0){arr.splice(index,1);return index;}else{return false;}}

+function array_removeFromStart(array,numberToRemove){if(Array.prototype.splice){array.splice(0,numberToRemove);}else{for(var i=numberToRemove,len=array.length;i<len;i++){array[i-numberToRemove]=array[i];}

+array.length=array.length-numberToRemove;}

+return array;}

+function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}

+return false;}

+function getErrorMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}

+return""+ex;}

+function moveCaretToEnd(input){if(input.setSelectionRange){input.focus();var length=input.value.length;input.setSelectionRange(length,length);}else if(input.createTextRange){var range=input.createTextRange();range.collapse(false);range.select();}

+input.focus();}

+function stopPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}}

+function getEvent(evt){return evt?evt:event;}

+function getTarget(evt){return evt.target?evt.target:evt.srcElement;}

+function getRelatedTarget(evt){if(evt.relatedTarget){return evt.relatedTarget;}else if(evt.srcElement){switch(evt.type){case"mouseover":return evt.fromElement;case"mouseout":return evt.toElement;default:return evt.srcElement;}}}

+function cancelKeyEvent(evt){evt.returnValue=false;stopPropagation(evt);}

+function evalCommandLine(){var expr=$("command").value;evalCommand(expr);$("command").value="";}

+function evalLastCommand(){if(lastCommand!=null){evalCommand(lastCommand);}}

+var lastCommand=null;var commandHistory=[];var currentCommandIndex=0;function evalCommand(expr){if(appender){appender.evalCommandAndAppend(expr);}else{var prefix=">>> "+expr+"\r\n";try{log("INFO",prefix+eval(expr));}catch(ex){log("ERROR",prefix+"Error: "+getErrorMessage(ex));}}

+if(expr!=commandHistory[commandHistory.length-1]){commandHistory.push(expr);if(appender){appender.storeCommandHistory(commandHistory);}}

+currentCommandIndex=(expr==commandHistory[currentCommandIndex])?currentCommandIndex+1:commandHistory.length;lastCommand=expr;}

+//]]>

+</script>

+<style type="text/css">

+body{background-color:white;color:black;padding:0;margin:0;font-family:tahoma,verdana,arial,helvetica,sans-serif;overflow:hidden}div#switchesContainer input{margin-bottom:0}div.toolbar{border-top:solid #ffffff 1px;border-bottom:solid #aca899 1px;background-color:#f1efe7;padding:3px 5px;font-size:68.75%}div.toolbar,div#search input{font-family:tahoma,verdana,arial,helvetica,sans-serif}div.toolbar input.button{padding:0 5px;font-size:100%}div.toolbar input.hidden{display:none}div#switches input#clearButton{margin-left:20px}div#levels label{font-weight:bold}div#levels label,div#options label{margin-right:5px}div#levels label#wrapLabel{font-weight:normal}div#search label{margin-right:10px}div#search label.searchboxlabel{margin-right:0}div#search input{font-size:100%}div#search input.validregex{color:green}div#search input.invalidregex{color:red}div#search input.nomatches{color:white;background-color:#ff6666}div#search input.nomatches{color:white;background-color:#ff6666}div#searchNav{display:none}div#commandLine{display:none}div#commandLine input#command{font-size:100%;font-family:Courier New,Courier}div#commandLine input#evaluateButton{}*.greyedout{color:gray !important;border-color:gray !important}*.greyedout *.alwaysenabled{color:black}*.unselectable{-khtml-user-select:none;-moz-user-select:none;user-select:none}div#log{font-family:Courier New,Courier;font-size:75%;width:100%;overflow:auto;clear:both;position:relative}div.group{border-color:#cccccc;border-style:solid;border-width:1px 0 1px 1px;overflow:visible}div.oldIe div.group,div.oldIe div.group *,div.oldIe *.logentry{height:1%}div.group div.groupheading span.expander{border:solid black 1px;font-family:Courier New,Courier;font-size:0.833em;background-color:#eeeeee;position:relative;top:-1px;color:black;padding:0 2px;cursor:pointer;cursor:hand;height:1%}div.group div.groupcontent{margin-left:10px;padding-bottom:2px;overflow:visible}div.group div.expanded{display:block}div.group div.collapsed{display:none}*.logentry{overflow:visible;display:none;white-space:pre}span.pre{white-space:pre}pre.unwrapped{display:inline !important}pre.unwrapped pre.pre,div.wrapped pre.pre{display:inline}div.wrapped pre.pre{white-space:normal}div.wrapped{display:none}body.searching *.logentry span.currentmatch{color:white !important;background-color:green !important}body.searching div.searchhighlight *.logentry span.searchterm{color:black;background-color:yellow}div.wrap *.logentry{white-space:normal !important;border-width:0 0 1px 0;border-color:#dddddd;border-style:dotted}div.wrap #log_wrapped,#log_unwrapped{display:block}div.wrap #log_unwrapped,#log_wrapped{display:none}div.wrap *.logentry span.pre{overflow:visible;white-space:normal}div.wrap *.logentry pre.unwrapped{display:none}div.wrap *.logentry span.wrapped{display:inline}div.searchfilter *.searchnonmatch{display:none !important}div#log *.TRACE,label#label_TRACE{color:#666666}div#log *.DEBUG,label#label_DEBUG{color:green}div#log *.INFO,label#label_INFO{color:#000099}div#log *.WARN,label#label_WARN{color:#999900}div#log *.ERROR,label#label_ERROR{color:red}div#log *.FATAL,label#label_FATAL{color:#660066}div.TRACE#log *.TRACE,div.DEBUG#log *.DEBUG,div.INFO#log *.INFO,div.WARN#log *.WARN,div.ERROR#log *.ERROR,div.FATAL#log *.FATAL{display:block}div#log div.separator{background-color:#cccccc;margin:5px 0;line-height:1px}

+</style>

+</head>

+<body id="body">

+<div id="switchesContainer">

+<div id="switches">

+<div id="levels" class="toolbar">

+Filters:

+<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>

+<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>

+<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>

+<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>

+<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>

+<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>

+<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>

+</div>

+<div id="search" class="toolbar">

+<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />

+<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />

+<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>

+<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>

+<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>

+<div id="searchNav">

+<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />

+<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />

+<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>

+<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>

+</div>

+</div>

+<div id="options" class="toolbar">

+Options:

+<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>

+<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>

+<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>

+<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>

+<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />

+<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />

+<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />

+</div>

+</div>

+</div>

+<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>

+<div id="commandLine" class="toolbar">

+<div id="commandLineContainer">

+<input type="text" id="command" title="Enter a JavaScript command here and hit return or press 'Evaluate'" />

+<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />

+</div>

+</div>

+</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/console_uncompressed.html b/planetstack/core/static/log4javascript-1.4.6/js/console_uncompressed.html
new file mode 100644
index 0000000..55679f8
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/console_uncompressed.html
@@ -0,0 +1,2279 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript</title>

+		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

+		<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->

+		<meta http-equiv="X-UA-Compatible" content="IE=7" />

+		<script type="text/javascript">var isIe = false, isIePre7 = false;</script>

+		<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->

+		<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->

+		<script type="text/javascript">

+			//<![CDATA[

+			var loggingEnabled = true;

+			var logQueuedEventsTimer = null;

+			var logEntries = [];

+			var logEntriesAndSeparators = [];

+			var logItems = [];

+			var renderDelay = 100;

+			var unrenderedLogItemsExist = false;

+			var rootGroup, currentGroup = null;

+			var loaded = false;

+			var currentLogItem = null;

+			var logMainContainer;

+

+			function copyProperties(obj, props) {

+				for (var i in props) {

+					obj[i] = props[i];

+				}

+			}

+

+			/*----------------------------------------------------------------*/

+

+			function LogItem() {

+			}

+

+			LogItem.prototype = {

+				mainContainer: null,

+				wrappedContainer: null,

+				unwrappedContainer: null,

+				group: null,

+

+				appendToLog: function() {

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].appendToLog();

+					}

+					this.group.update();

+				},

+

+				doRemove: function(doUpdate, removeFromGroup) {

+					if (this.rendered) {

+						for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+							this.elementContainers[i].remove();

+						}

+						this.unwrappedElementContainer = null;

+						this.wrappedElementContainer = null;

+						this.mainElementContainer = null;

+					}

+					if (this.group && removeFromGroup) {

+						this.group.removeChild(this, doUpdate);

+					}

+					if (this === currentLogItem) {

+						currentLogItem = null;

+					}

+				},

+

+				remove: function(doUpdate, removeFromGroup) {

+					this.doRemove(doUpdate, removeFromGroup);

+				},

+

+				render: function() {},

+

+				accept: function(visitor) {

+					visitor.visit(this);

+				},

+

+				getUnwrappedDomContainer: function() {

+					return this.group.unwrappedElementContainer.contentDiv;

+				},

+

+				getWrappedDomContainer: function() {

+					return this.group.wrappedElementContainer.contentDiv;

+				},

+

+				getMainDomContainer: function() {

+					return this.group.mainElementContainer.contentDiv;

+				}

+			};

+

+			LogItem.serializedItemKeys = {LOG_ENTRY: 0, GROUP_START: 1, GROUP_END: 2};

+

+			/*----------------------------------------------------------------*/

+

+			function LogItemContainerElement() {

+			}

+

+			LogItemContainerElement.prototype = {

+				appendToLog: function() {

+					var insertBeforeFirst = (newestAtTop && this.containerDomNode.hasChildNodes());

+					if (insertBeforeFirst) {

+						this.containerDomNode.insertBefore(this.mainDiv, this.containerDomNode.firstChild);

+					} else {

+						this.containerDomNode.appendChild(this.mainDiv);

+					}

+				}

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function SeparatorElementContainer(containerDomNode) {

+				this.containerDomNode = containerDomNode;

+				this.mainDiv = document.createElement("div");

+				this.mainDiv.className = "separator";

+				this.mainDiv.innerHTML = "&nbsp;";

+			}

+

+			SeparatorElementContainer.prototype = new LogItemContainerElement();

+

+			SeparatorElementContainer.prototype.remove = function() {

+				this.mainDiv.parentNode.removeChild(this.mainDiv);

+				this.mainDiv = null;

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function Separator() {

+				this.rendered = false;

+			}

+

+			Separator.prototype = new LogItem();

+

+			copyProperties(Separator.prototype, {

+				render: function() {

+					var containerDomNode = this.group.contentDiv;

+					if (isIe) {

+						this.unwrappedElementContainer = new SeparatorElementContainer(this.getUnwrappedDomContainer());

+						this.wrappedElementContainer = new SeparatorElementContainer(this.getWrappedDomContainer());

+						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];

+					} else {

+						this.mainElementContainer = new SeparatorElementContainer(this.getMainDomContainer());

+						this.elementContainers = [this.mainElementContainer];

+					}

+					this.content = this.formattedMessage;

+					this.rendered = true;

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function GroupElementContainer(group, containerDomNode, isRoot, isWrapped) {

+				this.group = group;

+				this.containerDomNode = containerDomNode;

+				this.isRoot = isRoot;

+				this.isWrapped = isWrapped;

+				this.expandable = false;

+

+				if (this.isRoot) {

+					if (isIe) {

+						this.contentDiv = logMainContainer.appendChild(document.createElement("div"));

+						this.contentDiv.id = this.isWrapped ? "log_wrapped" : "log_unwrapped";

+					} else {

+						this.contentDiv = logMainContainer;

+					}

+				} else {

+					var groupElementContainer = this;

+					

+					this.mainDiv = document.createElement("div");

+					this.mainDiv.className = "group";

+

+					this.headingDiv = this.mainDiv.appendChild(document.createElement("div"));

+					this.headingDiv.className = "groupheading";

+

+					this.expander = this.headingDiv.appendChild(document.createElement("span"));

+					this.expander.className = "expander unselectable greyedout";

+					this.expander.unselectable = true;

+					var expanderText = this.group.expanded ? "-" : "+";

+					this.expanderTextNode = this.expander.appendChild(document.createTextNode(expanderText));

+					

+					this.headingDiv.appendChild(document.createTextNode(" " + this.group.name));

+

+					this.contentDiv = this.mainDiv.appendChild(document.createElement("div"));

+					var contentCssClass = this.group.expanded ? "expanded" : "collapsed";

+					this.contentDiv.className = "groupcontent " + contentCssClass;

+

+					this.expander.onclick = function() {

+						if (groupElementContainer.group.expandable) {

+							groupElementContainer.group.toggleExpanded();

+						}

+					};

+				}

+			}

+

+			GroupElementContainer.prototype = new LogItemContainerElement();

+

+			copyProperties(GroupElementContainer.prototype, {

+				toggleExpanded: function() {

+					if (!this.isRoot) {

+						var oldCssClass, newCssClass, expanderText;

+						if (this.group.expanded) {

+							newCssClass = "expanded";

+							oldCssClass = "collapsed";

+							expanderText = "-";

+						} else {

+							newCssClass = "collapsed";

+							oldCssClass = "expanded";

+							expanderText = "+";

+						}

+						replaceClass(this.contentDiv, newCssClass, oldCssClass);

+						this.expanderTextNode.nodeValue = expanderText;

+					}

+				},

+

+				remove: function() {

+					if (!this.isRoot) {

+						this.headingDiv = null;

+						this.expander.onclick = null;

+						this.expander = null;

+						this.expanderTextNode = null;

+						this.contentDiv = null;

+						this.containerDomNode = null;

+						this.mainDiv.parentNode.removeChild(this.mainDiv);

+						this.mainDiv = null;

+					}

+				},

+

+				reverseChildren: function() {

+					// Invert the order of the log entries

+					var node = null;

+

+					// Remove all the log container nodes

+					var childDomNodes = [];

+					while ((node = this.contentDiv.firstChild)) {

+						this.contentDiv.removeChild(node);

+						childDomNodes.push(node);

+					}

+

+					// Put them all back in reverse order

+					while ((node = childDomNodes.pop())) {

+						this.contentDiv.appendChild(node);

+					}

+				},

+

+				update: function() {

+					if (!this.isRoot) {

+						if (this.group.expandable) {

+							removeClass(this.expander, "greyedout");

+						} else {

+							addClass(this.expander, "greyedout");

+						}

+					}

+				},

+

+				clear: function() {

+					if (this.isRoot) {

+						this.contentDiv.innerHTML = "";

+					}

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function Group(name, isRoot, initiallyExpanded) {

+				this.name = name;

+				this.group = null;

+				this.isRoot = isRoot;

+				this.initiallyExpanded = initiallyExpanded;

+				this.elementContainers = [];

+				this.children = [];

+				this.expanded = initiallyExpanded;

+				this.rendered = false;

+				this.expandable = false;

+			}

+

+			Group.prototype = new LogItem();

+

+			copyProperties(Group.prototype, {

+				addChild: function(logItem) {

+					this.children.push(logItem);

+					logItem.group = this;

+				},

+

+				render: function() {

+					if (isIe) {

+						var unwrappedDomContainer, wrappedDomContainer;

+						if (this.isRoot) {

+							unwrappedDomContainer = logMainContainer;

+							wrappedDomContainer = logMainContainer;

+						} else {

+							unwrappedDomContainer = this.getUnwrappedDomContainer();

+							wrappedDomContainer = this.getWrappedDomContainer();

+						}

+						this.unwrappedElementContainer = new GroupElementContainer(this, unwrappedDomContainer, this.isRoot, false);

+						this.wrappedElementContainer = new GroupElementContainer(this, wrappedDomContainer, this.isRoot, true);

+						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];

+					} else {

+						var mainDomContainer = this.isRoot ? logMainContainer : this.getMainDomContainer();

+						this.mainElementContainer = new GroupElementContainer(this, mainDomContainer, this.isRoot, false);

+						this.elementContainers = [this.mainElementContainer];

+					}

+					this.rendered = true;

+				},

+

+				toggleExpanded: function() {

+					this.expanded = !this.expanded;

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].toggleExpanded();

+					}

+				},

+

+				expand: function() {

+					if (!this.expanded) {

+						this.toggleExpanded();

+					}

+				},

+

+				accept: function(visitor) {

+					visitor.visitGroup(this);

+				},

+

+				reverseChildren: function() {

+					if (this.rendered) {

+						for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+							this.elementContainers[i].reverseChildren();

+						}

+					}

+				},

+

+				update: function() {

+					var previouslyExpandable = this.expandable;

+					this.expandable = (this.children.length !== 0);

+					if (this.expandable !== previouslyExpandable) {

+						for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+							this.elementContainers[i].update();

+						}

+					}

+				},

+

+				flatten: function() {

+					var visitor = new GroupFlattener();

+					this.accept(visitor);

+					return visitor.logEntriesAndSeparators;

+				},

+

+				removeChild: function(child, doUpdate) {

+					array_remove(this.children, child);

+					child.group = null;

+					if (doUpdate) {

+						this.update();

+					}

+				},

+

+				remove: function(doUpdate, removeFromGroup) {

+					for (var i = 0, len = this.children.length; i < len; i++) {

+						this.children[i].remove(false, false);

+					}

+					this.children = [];

+					this.update();

+					if (this === currentGroup) {

+						currentGroup = this.group;

+					}

+					this.doRemove(doUpdate, removeFromGroup);

+				},

+

+				serialize: function(items) {

+					items.push([LogItem.serializedItemKeys.GROUP_START, this.name]);

+					for (var i = 0, len = this.children.length; i < len; i++) {

+						this.children[i].serialize(items);

+					}

+					if (this !== currentGroup) {

+						items.push([LogItem.serializedItemKeys.GROUP_END]);

+					}

+				},

+

+				clear: function() {

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].clear();

+					}

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntryElementContainer() {

+			}

+

+			LogEntryElementContainer.prototype = new LogItemContainerElement();

+

+			copyProperties(LogEntryElementContainer.prototype, {

+				remove: function() {

+					this.doRemove();

+				},

+

+				doRemove: function() {

+					this.mainDiv.parentNode.removeChild(this.mainDiv);

+					this.mainDiv = null;

+					this.contentElement = null;

+					this.containerDomNode = null;

+				},

+

+				setContent: function(content, wrappedContent) {

+					if (content === this.formattedMessage) {

+						this.contentElement.innerHTML = "";

+						this.contentElement.appendChild(document.createTextNode(this.formattedMessage));

+					} else {

+						this.contentElement.innerHTML = content;

+					}

+				},

+

+				setSearchMatch: function(isMatch) {

+					var oldCssClass = isMatch ? "searchnonmatch" : "searchmatch";

+					var newCssClass = isMatch ? "searchmatch" : "searchnonmatch";

+					replaceClass(this.mainDiv, newCssClass, oldCssClass);

+				},

+

+				clearSearch: function() {

+					removeClass(this.mainDiv, "searchmatch");

+					removeClass(this.mainDiv, "searchnonmatch");

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntryWrappedElementContainer(logEntry, containerDomNode) {

+				this.logEntry = logEntry;

+				this.containerDomNode = containerDomNode;

+				this.mainDiv = document.createElement("div");

+				this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));

+				this.mainDiv.className = "logentry wrapped " + this.logEntry.level;

+				this.contentElement = this.mainDiv;

+			}

+

+			LogEntryWrappedElementContainer.prototype = new LogEntryElementContainer();

+

+			LogEntryWrappedElementContainer.prototype.setContent = function(content, wrappedContent) {

+				if (content === this.formattedMessage) {

+					this.contentElement.innerHTML = "";

+					this.contentElement.appendChild(document.createTextNode(this.formattedMessage));

+				} else {

+					this.contentElement.innerHTML = wrappedContent;

+				}

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntryUnwrappedElementContainer(logEntry, containerDomNode) {

+				this.logEntry = logEntry;

+				this.containerDomNode = containerDomNode;

+				this.mainDiv = document.createElement("div");

+				this.mainDiv.className = "logentry unwrapped " + this.logEntry.level;

+				this.pre = this.mainDiv.appendChild(document.createElement("pre"));

+				this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));

+				this.pre.className = "unwrapped";

+				this.contentElement = this.pre;

+			}

+

+			LogEntryUnwrappedElementContainer.prototype = new LogEntryElementContainer();

+

+			LogEntryUnwrappedElementContainer.prototype.remove = function() {

+				this.doRemove();

+				this.pre = null;

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntryMainElementContainer(logEntry, containerDomNode) {

+				this.logEntry = logEntry;

+				this.containerDomNode = containerDomNode;

+				this.mainDiv = document.createElement("div");

+				this.mainDiv.className = "logentry nonielogentry " + this.logEntry.level;

+				this.contentElement = this.mainDiv.appendChild(document.createElement("span"));

+				this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));

+			}

+

+			LogEntryMainElementContainer.prototype = new LogEntryElementContainer();

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntry(level, formattedMessage) {

+				this.level = level;

+				this.formattedMessage = formattedMessage;

+				this.rendered = false;

+			}

+

+			LogEntry.prototype = new LogItem();

+

+			copyProperties(LogEntry.prototype, {

+				render: function() {

+					var logEntry = this;

+					var containerDomNode = this.group.contentDiv;

+

+					// Support for the CSS attribute white-space in IE for Windows is

+					// non-existent pre version 6 and slightly odd in 6, so instead

+					// use two different HTML elements

+					if (isIe) {

+						this.formattedMessage = this.formattedMessage.replace(/\r\n/g, "\r"); // Workaround for IE's treatment of white space

+						this.unwrappedElementContainer = new LogEntryUnwrappedElementContainer(this, this.getUnwrappedDomContainer());

+						this.wrappedElementContainer = new LogEntryWrappedElementContainer(this, this.getWrappedDomContainer());

+						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];

+					} else {

+						this.mainElementContainer = new LogEntryMainElementContainer(this, this.getMainDomContainer());

+						this.elementContainers = [this.mainElementContainer];

+					}

+					this.content = this.formattedMessage;

+					this.rendered = true;

+				},

+

+				setContent: function(content, wrappedContent) {

+					if (content != this.content) {

+						if (isIe && (content !== this.formattedMessage)) {

+							content = content.replace(/\r\n/g, "\r"); // Workaround for IE's treatment of white space

+						}

+						for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+							this.elementContainers[i].setContent(content, wrappedContent);

+						}

+						this.content = content;

+					}

+				},

+

+				getSearchMatches: function() {

+					var matches = [];

+					var i, len;

+					if (isIe) {

+						var unwrappedEls = getElementsByClass(this.unwrappedElementContainer.mainDiv, "searchterm", "span");

+						var wrappedEls = getElementsByClass(this.wrappedElementContainer.mainDiv, "searchterm", "span");

+						for (i = 0, len = unwrappedEls.length; i < len; i++) {

+							matches[i] = new Match(this.level, null, unwrappedEls[i], wrappedEls[i]);

+						}

+					} else {

+						var els = getElementsByClass(this.mainElementContainer.mainDiv, "searchterm", "span");

+						for (i = 0, len = els.length; i < len; i++) {

+							matches[i] = new Match(this.level, els[i]);

+						}

+					}

+					return matches;

+				},

+

+				setSearchMatch: function(isMatch) {

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].setSearchMatch(isMatch);

+					}

+				},

+

+				clearSearch: function() {

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].clearSearch();

+					}

+				},

+

+				accept: function(visitor) {

+					visitor.visitLogEntry(this);

+				},

+

+				serialize: function(items) {

+					items.push([LogItem.serializedItemKeys.LOG_ENTRY, this.level, this.formattedMessage]);

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function LogItemVisitor() {

+			}

+

+			LogItemVisitor.prototype = {

+				visit: function(logItem) {

+				},

+

+				visitParent: function(logItem) {

+					if (logItem.group) {

+						logItem.group.accept(this);

+					}

+				},

+

+				visitChildren: function(logItem) {

+					for (var i = 0, len = logItem.children.length; i < len; i++) {

+						logItem.children[i].accept(this);

+					}

+				},

+

+				visitLogEntry: function(logEntry) {

+					this.visit(logEntry);

+				},

+

+				visitSeparator: function(separator) {

+					this.visit(separator);

+				},

+

+				visitGroup: function(group) {

+					this.visit(group);

+				}

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function GroupFlattener() {

+				this.logEntriesAndSeparators = [];

+			}

+

+			GroupFlattener.prototype = new LogItemVisitor();

+

+			GroupFlattener.prototype.visitGroup = function(group) {

+				this.visitChildren(group);

+			};

+

+			GroupFlattener.prototype.visitLogEntry = function(logEntry) {

+				this.logEntriesAndSeparators.push(logEntry);

+			};

+

+			GroupFlattener.prototype.visitSeparator = function(separator) {

+				this.logEntriesAndSeparators.push(separator);

+			};

+

+			/*----------------------------------------------------------------*/

+

+			window.onload = function() {

+				// Sort out document.domain

+				if (location.search) {

+					var queryBits = unescape(location.search).substr(1).split("&"), nameValueBits;

+					for (var i = 0, len = queryBits.length; i < len; i++) {

+						nameValueBits = queryBits[i].split("=");

+						if (nameValueBits[0] == "log4javascript_domain") {

+							document.domain = nameValueBits[1];

+							break;

+						}

+					}

+				}

+

+				// Create DOM objects

+				logMainContainer = $("log");

+				if (isIePre7) {

+					addClass(logMainContainer, "oldIe");

+				}

+

+				rootGroup = new Group("root", true);

+				rootGroup.render();

+				currentGroup = rootGroup;

+				

+				setCommandInputWidth();

+				setLogContainerHeight();

+				toggleLoggingEnabled();

+				toggleSearchEnabled();

+				toggleSearchFilter();

+				toggleSearchHighlight();

+				applyFilters();

+				checkAllLevels();

+				toggleWrap();

+				toggleNewestAtTop();

+				toggleScrollToLatest();

+				renderQueuedLogItems();

+				loaded = true;

+				$("command").value = "";

+				$("command").autocomplete = "off";

+				$("command").onkeydown = function(evt) {

+					evt = getEvent(evt);

+					if (evt.keyCode == 10 || evt.keyCode == 13) { // Return/Enter

+						evalCommandLine();

+						stopPropagation(evt);

+					} else if (evt.keyCode == 27) { // Escape

+						this.value = "";

+						this.focus();

+					} else if (evt.keyCode == 38 && commandHistory.length > 0) { // Up

+						currentCommandIndex = Math.max(0, currentCommandIndex - 1);

+						this.value = commandHistory[currentCommandIndex];

+						moveCaretToEnd(this);

+					} else if (evt.keyCode == 40 && commandHistory.length > 0) { // Down

+						currentCommandIndex = Math.min(commandHistory.length - 1, currentCommandIndex + 1);

+						this.value = commandHistory[currentCommandIndex];

+						moveCaretToEnd(this);

+					}

+				};

+

+				// Prevent the keypress moving the caret in Firefox

+				$("command").onkeypress = function(evt) {

+					evt = getEvent(evt);

+					if (evt.keyCode == 38 && commandHistory.length > 0 && evt.preventDefault) { // Up

+						evt.preventDefault();

+					}

+				};

+

+				// Prevent the keyup event blurring the input in Opera

+				$("command").onkeyup = function(evt) {

+					evt = getEvent(evt);

+					if (evt.keyCode == 27 && evt.preventDefault) { // Up

+						evt.preventDefault();

+						this.focus();

+					}

+				};

+

+				// Add document keyboard shortcuts

+				document.onkeydown = function keyEventHandler(evt) {

+					evt = getEvent(evt);

+					switch (evt.keyCode) {

+						case 69: // Ctrl + shift + E: re-execute last command

+							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {

+								evalLastCommand();

+								cancelKeyEvent(evt);

+								return false;

+							}

+							break;

+						case 75: // Ctrl + shift + K: focus search

+							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {

+								focusSearch();

+								cancelKeyEvent(evt);

+								return false;

+							}

+							break;

+						case 40: // Ctrl + shift + down arrow: focus command line

+						case 76: // Ctrl + shift + L: focus command line

+							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {

+								focusCommandLine();

+								cancelKeyEvent(evt);

+								return false;

+							}

+							break;

+					}

+				};

+

+				// Workaround to make sure log div starts at the correct size

+				setTimeout(setLogContainerHeight, 20);

+

+				setShowCommandLine(showCommandLine);

+				doSearch();

+			};

+

+			window.onunload = function() {

+				if (mainWindowExists()) {

+					appender.unload();

+				}

+				appender = null;

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function toggleLoggingEnabled() {

+				setLoggingEnabled($("enableLogging").checked);

+			}

+

+			function setLoggingEnabled(enable) {

+				loggingEnabled = enable;

+			}

+

+			var appender = null;

+

+			function setAppender(appenderParam) {

+				appender = appenderParam;

+			}

+

+			function setShowCloseButton(showCloseButton) {

+				$("closeButton").style.display = showCloseButton ? "inline" : "none";

+			}

+

+			function setShowHideButton(showHideButton) {

+				$("hideButton").style.display = showHideButton ? "inline" : "none";

+			}

+

+			var newestAtTop = false;

+

+			/*----------------------------------------------------------------*/

+

+			function LogItemContentReverser() {

+			}

+			

+			LogItemContentReverser.prototype = new LogItemVisitor();

+			

+			LogItemContentReverser.prototype.visitGroup = function(group) {

+				group.reverseChildren();

+				this.visitChildren(group);

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function setNewestAtTop(isNewestAtTop) {

+				var oldNewestAtTop = newestAtTop;

+				var i, iLen, j, jLen;

+				newestAtTop = Boolean(isNewestAtTop);

+				if (oldNewestAtTop != newestAtTop) {

+					var visitor = new LogItemContentReverser();

+					rootGroup.accept(visitor);

+

+					// Reassemble the matches array

+					if (currentSearch) {

+						var currentMatch = currentSearch.matches[currentMatchIndex];

+						var matchIndex = 0;

+						var matches = [];

+						var actOnLogEntry = function(logEntry) {

+							var logEntryMatches = logEntry.getSearchMatches();

+							for (j = 0, jLen = logEntryMatches.length; j < jLen; j++) {

+								matches[matchIndex] = logEntryMatches[j];

+								if (currentMatch && logEntryMatches[j].equals(currentMatch)) {

+									currentMatchIndex = matchIndex;

+								}

+								matchIndex++;

+							}

+						};

+						if (newestAtTop) {

+							for (i = logEntries.length - 1; i >= 0; i--) {

+								actOnLogEntry(logEntries[i]);

+							}

+						} else {

+							for (i = 0, iLen = logEntries.length; i < iLen; i++) {

+								actOnLogEntry(logEntries[i]);

+							}

+						}

+						currentSearch.matches = matches;

+						if (currentMatch) {

+							currentMatch.setCurrent();

+						}

+					} else if (scrollToLatest) {

+						doScrollToLatest();

+					}

+				}

+				$("newestAtTop").checked = isNewestAtTop;

+			}

+

+			function toggleNewestAtTop() {

+				var isNewestAtTop = $("newestAtTop").checked;

+				setNewestAtTop(isNewestAtTop);

+			}

+

+			var scrollToLatest = true;

+

+			function setScrollToLatest(isScrollToLatest) {

+				scrollToLatest = isScrollToLatest;

+				if (scrollToLatest) {

+					doScrollToLatest();

+				}

+				$("scrollToLatest").checked = isScrollToLatest;

+			}

+

+			function toggleScrollToLatest() {

+				var isScrollToLatest = $("scrollToLatest").checked;

+				setScrollToLatest(isScrollToLatest);

+			}

+

+			function doScrollToLatest() {

+				var l = logMainContainer;

+				if (typeof l.scrollTop != "undefined") {

+					if (newestAtTop) {

+						l.scrollTop = 0;

+					} else {

+						var latestLogEntry = l.lastChild;

+						if (latestLogEntry) {

+							l.scrollTop = l.scrollHeight;

+						}

+					}

+				}

+			}

+

+			var closeIfOpenerCloses = true;

+

+			function setCloseIfOpenerCloses(isCloseIfOpenerCloses) {

+				closeIfOpenerCloses = isCloseIfOpenerCloses;

+			}

+

+			var maxMessages = null;

+

+			function setMaxMessages(max) {

+				maxMessages = max;

+				pruneLogEntries();

+			}

+

+			var showCommandLine = false;

+

+			function setShowCommandLine(isShowCommandLine) {

+				showCommandLine = isShowCommandLine;

+				if (loaded) {

+					$("commandLine").style.display = showCommandLine ? "block" : "none";

+					setCommandInputWidth();

+					setLogContainerHeight();

+				}

+			}

+

+			function focusCommandLine() {

+				if (loaded) {

+					$("command").focus();

+				}

+			}

+

+			function focusSearch() {

+				if (loaded) {

+					$("searchBox").focus();

+				}

+			}

+

+			function getLogItems() {

+				var items = [];

+				for (var i = 0, len = logItems.length; i < len; i++) {

+					logItems[i].serialize(items);

+				}

+				return items;

+			}

+

+			function setLogItems(items) {

+				var loggingReallyEnabled = loggingEnabled;

+				// Temporarily turn logging on

+				loggingEnabled = true;

+				for (var i = 0, len = items.length; i < len; i++) {

+					switch (items[i][0]) {

+						case LogItem.serializedItemKeys.LOG_ENTRY:

+							log(items[i][1], items[i][2]);

+							break;

+						case LogItem.serializedItemKeys.GROUP_START:

+							group(items[i][1]);

+							break;

+						case LogItem.serializedItemKeys.GROUP_END:

+							groupEnd();

+							break;

+					}

+				}

+				loggingEnabled = loggingReallyEnabled;

+			}

+

+			function log(logLevel, formattedMessage) {

+				if (loggingEnabled) {

+					var logEntry = new LogEntry(logLevel, formattedMessage);

+					logEntries.push(logEntry);

+					logEntriesAndSeparators.push(logEntry);

+					logItems.push(logEntry);

+					currentGroup.addChild(logEntry);

+					if (loaded) {

+						if (logQueuedEventsTimer !== null) {

+							clearTimeout(logQueuedEventsTimer);

+						}

+						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);

+						unrenderedLogItemsExist = true;

+					}

+				}

+			}

+

+			function renderQueuedLogItems() {

+				logQueuedEventsTimer = null;

+				var pruned = pruneLogEntries();

+

+				// Render any unrendered log entries and apply the current search to them

+				var initiallyHasMatches = currentSearch ? currentSearch.hasMatches() : false;

+				for (var i = 0, len = logItems.length; i < len; i++) {

+					if (!logItems[i].rendered) {

+						logItems[i].render();

+						logItems[i].appendToLog();

+						if (currentSearch && (logItems[i] instanceof LogEntry)) {

+							currentSearch.applyTo(logItems[i]);

+						}

+					}

+				}

+				if (currentSearch) {

+					if (pruned) {

+						if (currentSearch.hasVisibleMatches()) {

+							if (currentMatchIndex === null) {

+								setCurrentMatchIndex(0);

+							}

+							displayMatches();

+						} else {

+							displayNoMatches();

+						}

+					} else if (!initiallyHasMatches && currentSearch.hasVisibleMatches()) {

+						setCurrentMatchIndex(0);

+						displayMatches();

+					}

+				}

+				if (scrollToLatest) {

+					doScrollToLatest();

+				}

+				unrenderedLogItemsExist = false;

+			}

+

+			function pruneLogEntries() {

+				if ((maxMessages !== null) && (logEntriesAndSeparators.length > maxMessages)) {

+					var numberToDelete = logEntriesAndSeparators.length - maxMessages;

+					var prunedLogEntries = logEntriesAndSeparators.slice(0, numberToDelete);

+					if (currentSearch) {

+						currentSearch.removeMatches(prunedLogEntries);

+					}

+					var group;

+					for (var i = 0; i < numberToDelete; i++) {

+						group = logEntriesAndSeparators[i].group;

+						array_remove(logItems, logEntriesAndSeparators[i]);

+						array_remove(logEntries, logEntriesAndSeparators[i]);

+						logEntriesAndSeparators[i].remove(true, true);

+						if (group.children.length === 0 && group !== currentGroup && group !== rootGroup) {

+							array_remove(logItems, group);

+							group.remove(true, true);

+						}

+					}

+					logEntriesAndSeparators = array_removeFromStart(logEntriesAndSeparators, numberToDelete);

+					return true;

+				}

+				return false;

+			}

+

+			function group(name, startExpanded) {

+				if (loggingEnabled) {

+					initiallyExpanded = (typeof startExpanded === "undefined") ? true : Boolean(startExpanded);

+					var newGroup = new Group(name, false, initiallyExpanded);

+					currentGroup.addChild(newGroup);

+					currentGroup = newGroup;

+					logItems.push(newGroup);

+					if (loaded) {

+						if (logQueuedEventsTimer !== null) {

+							clearTimeout(logQueuedEventsTimer);

+						}

+						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);

+						unrenderedLogItemsExist = true;

+					}

+				}

+			}

+

+			function groupEnd() {

+				currentGroup = (currentGroup === rootGroup) ? rootGroup : currentGroup.group;

+			}

+

+			function mainPageReloaded() {

+				currentGroup = rootGroup;

+				var separator = new Separator();

+				logEntriesAndSeparators.push(separator);

+				logItems.push(separator);

+				currentGroup.addChild(separator);

+			}

+

+			function closeWindow() {

+				if (appender && mainWindowExists()) {

+					appender.close(true);

+				} else {

+					window.close();

+				}

+			}

+

+			function hide() {

+				if (appender && mainWindowExists()) {

+					appender.hide();

+				}

+			}

+

+			var mainWindow = window;

+			var windowId = "log4javascriptConsoleWindow_" + new Date().getTime() + "_" + ("" + Math.random()).substr(2);

+

+			function setMainWindow(win) {

+				mainWindow = win;

+				mainWindow[windowId] = window;

+				// If this is a pop-up, poll the opener to see if it's closed

+				if (opener && closeIfOpenerCloses) {

+					pollOpener();

+				}

+			}

+

+			function pollOpener() {

+				if (closeIfOpenerCloses) {

+					if (mainWindowExists()) {

+						setTimeout(pollOpener, 500);

+					} else {

+						closeWindow();

+					}

+				}

+			}

+

+			function mainWindowExists() {

+				try {

+					return (mainWindow && !mainWindow.closed &&

+						mainWindow[windowId] == window);

+				} catch (ex) {}

+				return false;

+			}

+

+			var logLevels = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"];

+

+			function getCheckBox(logLevel) {

+				return $("switch_" + logLevel);

+			}

+

+			function getIeWrappedLogContainer() {

+				return $("log_wrapped");

+			}

+

+			function getIeUnwrappedLogContainer() {

+				return $("log_unwrapped");

+			}

+

+			function applyFilters() {

+				for (var i = 0; i < logLevels.length; i++) {

+					if (getCheckBox(logLevels[i]).checked) {

+						addClass(logMainContainer, logLevels[i]);

+					} else {

+						removeClass(logMainContainer, logLevels[i]);

+					}

+				}

+				updateSearchFromFilters();

+			}

+

+			function toggleAllLevels() {

+				var turnOn = $("switch_ALL").checked;

+				for (var i = 0; i < logLevels.length; i++) {

+					getCheckBox(logLevels[i]).checked = turnOn;

+					if (turnOn) {

+						addClass(logMainContainer, logLevels[i]);

+					} else {

+						removeClass(logMainContainer, logLevels[i]);

+					}

+				}

+			}

+

+			function checkAllLevels() {

+				for (var i = 0; i < logLevels.length; i++) {

+					if (!getCheckBox(logLevels[i]).checked) {

+						getCheckBox("ALL").checked = false;

+						return;

+					}

+				}

+				getCheckBox("ALL").checked = true;

+			}

+

+			function clearLog() {

+				rootGroup.clear();

+				currentGroup = rootGroup;

+				logEntries = [];

+				logItems = [];

+				logEntriesAndSeparators = [];

+ 				doSearch();

+			}

+

+			function toggleWrap() {

+				var enable = $("wrap").checked;

+				if (enable) {

+					addClass(logMainContainer, "wrap");

+				} else {

+					removeClass(logMainContainer, "wrap");

+				}

+				refreshCurrentMatch();

+			}

+

+			/* ------------------------------------------------------------------- */

+

+			// Search

+

+			var searchTimer = null;

+

+			function scheduleSearch() {

+				try {

+					clearTimeout(searchTimer);

+				} catch (ex) {

+					// Do nothing

+				}

+				searchTimer = setTimeout(doSearch, 500);

+			}

+

+			function Search(searchTerm, isRegex, searchRegex, isCaseSensitive) {

+				this.searchTerm = searchTerm;

+				this.isRegex = isRegex;

+				this.searchRegex = searchRegex;

+				this.isCaseSensitive = isCaseSensitive;

+				this.matches = [];

+			}

+

+			Search.prototype = {

+				hasMatches: function() {

+					return this.matches.length > 0;

+				},

+

+				hasVisibleMatches: function() {

+					if (this.hasMatches()) {

+						for (var i = 0; i < this.matches.length; i++) {

+							if (this.matches[i].isVisible()) {

+								return true;

+							}

+						}

+					}

+					return false;

+				},

+

+				match: function(logEntry) {

+					var entryText = String(logEntry.formattedMessage);

+					var matchesSearch = false;

+					if (this.isRegex) {

+						matchesSearch = this.searchRegex.test(entryText);

+					} else if (this.isCaseSensitive) {

+						matchesSearch = (entryText.indexOf(this.searchTerm) > -1);

+					} else {

+						matchesSearch = (entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1);

+					}

+					return matchesSearch;

+				},

+

+				getNextVisibleMatchIndex: function() {

+					for (var i = currentMatchIndex + 1; i < this.matches.length; i++) {

+						if (this.matches[i].isVisible()) {

+							return i;

+						}

+					}

+					// Start again from the first match

+					for (i = 0; i <= currentMatchIndex; i++) {

+						if (this.matches[i].isVisible()) {

+							return i;

+						}

+					}

+					return -1;

+				},

+

+				getPreviousVisibleMatchIndex: function() {

+					for (var i = currentMatchIndex - 1; i >= 0; i--) {

+						if (this.matches[i].isVisible()) {

+							return i;

+						}

+					}

+					// Start again from the last match

+					for (var i = this.matches.length - 1; i >= currentMatchIndex; i--) {

+						if (this.matches[i].isVisible()) {

+							return i;

+						}

+					}

+					return -1;

+				},

+

+				applyTo: function(logEntry) {

+					var doesMatch = this.match(logEntry);

+					if (doesMatch) {

+						logEntry.group.expand();

+						logEntry.setSearchMatch(true);

+						var logEntryContent;

+						var wrappedLogEntryContent;

+						var searchTermReplacementStartTag = "<span class=\"searchterm\">";

+						var searchTermReplacementEndTag = "<" + "/span>";

+						var preTagName = isIe ? "pre" : "span";

+						var preStartTag = "<" + preTagName + " class=\"pre\">";

+						var preEndTag = "<" + "/" + preTagName + ">";

+						var startIndex = 0;

+						var searchIndex, matchedText, textBeforeMatch;

+						if (this.isRegex) {

+							var flags = this.isCaseSensitive ? "g" : "gi";

+							var capturingRegex = new RegExp("(" + this.searchRegex.source + ")", flags);

+

+							// Replace the search term with temporary tokens for the start and end tags

+							var rnd = ("" + Math.random()).substr(2);

+							var startToken = "%%s" + rnd + "%%";

+							var endToken = "%%e" + rnd + "%%";

+							logEntryContent = logEntry.formattedMessage.replace(capturingRegex, startToken + "$1" + endToken);

+

+							// Escape the HTML to get rid of angle brackets

+							logEntryContent = escapeHtml(logEntryContent);

+

+							// Substitute the proper HTML back in for the search match

+							var result;

+							var searchString = logEntryContent;

+							logEntryContent = "";

+							wrappedLogEntryContent = "";

+							while ((searchIndex = searchString.indexOf(startToken, startIndex)) > -1) {

+								var endTokenIndex = searchString.indexOf(endToken, searchIndex);

+								matchedText = searchString.substring(searchIndex + startToken.length, endTokenIndex);

+								textBeforeMatch = searchString.substring(startIndex, searchIndex);

+								logEntryContent += preStartTag + textBeforeMatch + preEndTag;

+								logEntryContent += searchTermReplacementStartTag + preStartTag + matchedText +

+									preEndTag + searchTermReplacementEndTag;

+								if (isIe) {

+									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +

+										matchedText + searchTermReplacementEndTag;

+								}

+								startIndex = endTokenIndex + endToken.length;

+							}

+							logEntryContent += preStartTag + searchString.substr(startIndex) + preEndTag;

+							if (isIe) {

+								wrappedLogEntryContent += searchString.substr(startIndex);

+							}

+						} else {

+							logEntryContent = "";

+							wrappedLogEntryContent = "";

+							var searchTermReplacementLength = searchTermReplacementStartTag.length +

+								this.searchTerm.length + searchTermReplacementEndTag.length;

+							var searchTermLength = this.searchTerm.length;

+							var searchTermLowerCase = this.searchTerm.toLowerCase();

+							var logTextLowerCase = logEntry.formattedMessage.toLowerCase();

+							while ((searchIndex = logTextLowerCase.indexOf(searchTermLowerCase, startIndex)) > -1) {

+								matchedText = escapeHtml(logEntry.formattedMessage.substr(searchIndex, this.searchTerm.length));

+								textBeforeMatch = escapeHtml(logEntry.formattedMessage.substring(startIndex, searchIndex));

+								var searchTermReplacement = searchTermReplacementStartTag +

+									preStartTag + matchedText + preEndTag + searchTermReplacementEndTag;

+								logEntryContent += preStartTag + textBeforeMatch + preEndTag + searchTermReplacement;

+								if (isIe) {

+									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +

+										matchedText + searchTermReplacementEndTag;

+								}

+								startIndex = searchIndex + searchTermLength;

+							}

+							var textAfterLastMatch = escapeHtml(logEntry.formattedMessage.substr(startIndex));

+							logEntryContent += preStartTag + textAfterLastMatch + preEndTag;

+							if (isIe) {

+								wrappedLogEntryContent += textAfterLastMatch;

+							}

+						}

+						logEntry.setContent(logEntryContent, wrappedLogEntryContent);

+						var logEntryMatches = logEntry.getSearchMatches();

+						this.matches = this.matches.concat(logEntryMatches);

+					} else {

+						logEntry.setSearchMatch(false);

+						logEntry.setContent(logEntry.formattedMessage, logEntry.formattedMessage);

+					}

+					return doesMatch;

+				},

+

+				removeMatches: function(logEntries) {

+					var matchesToRemoveCount = 0;

+					var currentMatchRemoved = false;

+					var matchesToRemove = [];

+					var i, iLen, j, jLen;

+

+					// Establish the list of matches to be removed

+					for (i = 0, iLen = this.matches.length; i < iLen; i++) {

+						for (j = 0, jLen = logEntries.length; j < jLen; j++) {

+							if (this.matches[i].belongsTo(logEntries[j])) {

+								matchesToRemove.push(this.matches[i]);

+								if (i === currentMatchIndex) {

+									currentMatchRemoved = true;

+								}

+							}

+						}

+					}

+

+					// Set the new current match index if the current match has been deleted

+					// This will be the first match that appears after the first log entry being

+					// deleted, if one exists; otherwise, it's the first match overall

+					var newMatch = currentMatchRemoved ? null : this.matches[currentMatchIndex];

+					if (currentMatchRemoved) {

+						for (i = currentMatchIndex, iLen = this.matches.length; i < iLen; i++) {

+							if (this.matches[i].isVisible() && !array_contains(matchesToRemove, this.matches[i])) {

+								newMatch = this.matches[i];

+								break;

+							}

+						}

+					}

+

+					// Remove the matches

+					for (i = 0, iLen = matchesToRemove.length; i < iLen; i++) {

+						array_remove(this.matches, matchesToRemove[i]);

+						matchesToRemove[i].remove();

+					}

+

+					// Set the new match, if one exists

+					if (this.hasVisibleMatches()) {

+						if (newMatch === null) {

+							setCurrentMatchIndex(0);

+						} else {

+							// Get the index of the new match

+							var newMatchIndex = 0;

+							for (i = 0, iLen = this.matches.length; i < iLen; i++) {

+								if (newMatch === this.matches[i]) {

+									newMatchIndex = i;

+									break;

+								}

+							}

+							setCurrentMatchIndex(newMatchIndex);

+						}

+					} else {

+						currentMatchIndex = null;

+						displayNoMatches();

+					}

+				}

+			};

+

+			function getPageOffsetTop(el, container) {

+				var currentEl = el;

+				var y = 0;

+				while (currentEl && currentEl != container) {

+					y += currentEl.offsetTop;

+					currentEl = currentEl.offsetParent;

+				}

+				return y;

+			}

+

+			function scrollIntoView(el) {

+				var logContainer = logMainContainer;

+				// Check if the whole width of the element is visible and centre if not

+				if (!$("wrap").checked) {

+					var logContainerLeft = logContainer.scrollLeft;

+					var logContainerRight = logContainerLeft  + logContainer.offsetWidth;

+					var elLeft = el.offsetLeft;

+					var elRight = elLeft + el.offsetWidth;

+					if (elLeft < logContainerLeft || elRight > logContainerRight) {

+						logContainer.scrollLeft = elLeft - (logContainer.offsetWidth - el.offsetWidth) / 2;

+					}

+				}

+				// Check if the whole height of the element is visible and centre if not

+				var logContainerTop = logContainer.scrollTop;

+				var logContainerBottom = logContainerTop  + logContainer.offsetHeight;

+				var elTop = getPageOffsetTop(el) - getToolBarsHeight();

+				var elBottom = elTop + el.offsetHeight;

+				if (elTop < logContainerTop || elBottom > logContainerBottom) {

+					logContainer.scrollTop = elTop - (logContainer.offsetHeight - el.offsetHeight) / 2;

+				}

+			}

+

+			function Match(logEntryLevel, spanInMainDiv, spanInUnwrappedPre, spanInWrappedDiv) {

+				this.logEntryLevel = logEntryLevel;

+				this.spanInMainDiv = spanInMainDiv;

+				if (isIe) {

+					this.spanInUnwrappedPre = spanInUnwrappedPre;

+					this.spanInWrappedDiv = spanInWrappedDiv;

+				}

+				this.mainSpan = isIe ? spanInUnwrappedPre : spanInMainDiv;

+			}

+

+			Match.prototype = {

+				equals: function(match) {

+					return this.mainSpan === match.mainSpan;

+				},

+

+				setCurrent: function() {

+					if (isIe) {

+						addClass(this.spanInUnwrappedPre, "currentmatch");

+						addClass(this.spanInWrappedDiv, "currentmatch");

+						// Scroll the visible one into view

+						var elementToScroll = $("wrap").checked ? this.spanInWrappedDiv : this.spanInUnwrappedPre;

+						scrollIntoView(elementToScroll);

+					} else {

+						addClass(this.spanInMainDiv, "currentmatch");

+						scrollIntoView(this.spanInMainDiv);

+					}

+				},

+

+				belongsTo: function(logEntry) {

+					if (isIe) {

+						return isDescendant(this.spanInUnwrappedPre, logEntry.unwrappedPre);

+					} else {

+						return isDescendant(this.spanInMainDiv, logEntry.mainDiv);

+					}

+				},

+

+				setNotCurrent: function() {

+					if (isIe) {

+						removeClass(this.spanInUnwrappedPre, "currentmatch");

+						removeClass(this.spanInWrappedDiv, "currentmatch");

+					} else {

+						removeClass(this.spanInMainDiv, "currentmatch");

+					}

+				},

+

+				isOrphan: function() {

+					return isOrphan(this.mainSpan);

+				},

+

+				isVisible: function() {

+					return getCheckBox(this.logEntryLevel).checked;

+				},

+

+				remove: function() {

+					if (isIe) {

+						this.spanInUnwrappedPre = null;

+						this.spanInWrappedDiv = null;

+					} else {

+						this.spanInMainDiv = null;

+					}

+				}

+			};

+

+			var currentSearch = null;

+			var currentMatchIndex = null;

+

+			function doSearch() {

+				var searchBox = $("searchBox");

+				var searchTerm = searchBox.value;

+				var isRegex = $("searchRegex").checked;

+				var isCaseSensitive = $("searchCaseSensitive").checked;

+				var i;

+

+				if (searchTerm === "") {

+					$("searchReset").disabled = true;

+					$("searchNav").style.display = "none";

+					removeClass(document.body, "searching");

+					removeClass(searchBox, "hasmatches");

+					removeClass(searchBox, "nomatches");

+					for (i = 0; i < logEntries.length; i++) {

+						logEntries[i].clearSearch();

+						logEntries[i].setContent(logEntries[i].formattedMessage, logEntries[i].formattedMessage);

+					}

+					currentSearch = null;

+					setLogContainerHeight();

+				} else {

+					$("searchReset").disabled = false;

+					$("searchNav").style.display = "block";

+					var searchRegex;

+					var regexValid;

+					if (isRegex) {

+						try {

+							searchRegex = isCaseSensitive ? new RegExp(searchTerm, "g") : new RegExp(searchTerm, "gi");

+							regexValid = true;

+							replaceClass(searchBox, "validregex", "invalidregex");

+							searchBox.title = "Valid regex";

+						} catch (ex) {

+							regexValid = false;

+							replaceClass(searchBox, "invalidregex", "validregex");

+							searchBox.title = "Invalid regex: " + (ex.message ? ex.message : (ex.description ? ex.description : "unknown error"));

+							return;

+						}

+					} else {

+						searchBox.title = "";

+						removeClass(searchBox, "validregex");

+						removeClass(searchBox, "invalidregex");

+					}

+					addClass(document.body, "searching");

+					currentSearch = new Search(searchTerm, isRegex, searchRegex, isCaseSensitive);

+					for (i = 0; i < logEntries.length; i++) {

+						currentSearch.applyTo(logEntries[i]);

+					}

+					setLogContainerHeight();

+

+					// Highlight the first search match

+					if (currentSearch.hasVisibleMatches()) {

+						setCurrentMatchIndex(0);

+						displayMatches();

+					} else {

+						displayNoMatches();

+					}

+				}

+			}

+

+			function updateSearchFromFilters() {

+				if (currentSearch) {

+					if (currentSearch.hasMatches()) {

+						if (currentMatchIndex === null) {

+							currentMatchIndex = 0;

+						}

+						var currentMatch = currentSearch.matches[currentMatchIndex];

+						if (currentMatch.isVisible()) {

+							displayMatches();

+							setCurrentMatchIndex(currentMatchIndex);

+						} else {

+							currentMatch.setNotCurrent();

+							// Find the next visible match, if one exists

+							var nextVisibleMatchIndex = currentSearch.getNextVisibleMatchIndex();

+							if (nextVisibleMatchIndex > -1) {

+								setCurrentMatchIndex(nextVisibleMatchIndex);

+								displayMatches();

+							} else {

+								displayNoMatches();

+							}

+						}

+					} else {

+						displayNoMatches();

+					}

+				}

+			}

+

+			function refreshCurrentMatch() {

+				if (currentSearch && currentSearch.hasVisibleMatches()) {

+					setCurrentMatchIndex(currentMatchIndex);

+				}

+			}

+

+			function displayMatches() {

+				replaceClass($("searchBox"), "hasmatches", "nomatches");

+				$("searchBox").title = "" + currentSearch.matches.length + " matches found";

+				$("searchNav").style.display = "block";

+				setLogContainerHeight();

+			}

+

+			function displayNoMatches() {

+				replaceClass($("searchBox"), "nomatches", "hasmatches");

+				$("searchBox").title = "No matches found";

+				$("searchNav").style.display = "none";

+				setLogContainerHeight();

+			}

+

+			function toggleSearchEnabled(enable) {

+				enable = (typeof enable == "undefined") ? !$("searchDisable").checked : enable;

+				$("searchBox").disabled = !enable;

+				$("searchReset").disabled = !enable;

+				$("searchRegex").disabled = !enable;

+				$("searchNext").disabled = !enable;

+				$("searchPrevious").disabled = !enable;

+				$("searchCaseSensitive").disabled = !enable;

+				$("searchNav").style.display = (enable && ($("searchBox").value !== "") &&

+						currentSearch && currentSearch.hasVisibleMatches()) ?

+					"block" : "none";

+				if (enable) {

+					removeClass($("search"), "greyedout");

+					addClass(document.body, "searching");

+					if ($("searchHighlight").checked) {

+						addClass(logMainContainer, "searchhighlight");

+					} else {

+						removeClass(logMainContainer, "searchhighlight");

+					}

+					if ($("searchFilter").checked) {

+						addClass(logMainContainer, "searchfilter");

+					} else {

+						removeClass(logMainContainer, "searchfilter");

+					}

+					$("searchDisable").checked = !enable;

+				} else {

+					addClass($("search"), "greyedout");

+					removeClass(document.body, "searching");

+					removeClass(logMainContainer, "searchhighlight");

+					removeClass(logMainContainer, "searchfilter");

+				}

+				setLogContainerHeight();

+			}

+

+			function toggleSearchFilter() {

+				var enable = $("searchFilter").checked;

+				if (enable) {

+					addClass(logMainContainer, "searchfilter");

+				} else {

+					removeClass(logMainContainer, "searchfilter");

+				}

+				refreshCurrentMatch();

+			}

+

+			function toggleSearchHighlight() {

+				var enable = $("searchHighlight").checked;

+				if (enable) {

+					addClass(logMainContainer, "searchhighlight");

+				} else {

+					removeClass(logMainContainer, "searchhighlight");

+				}

+			}

+

+			function clearSearch() {

+				$("searchBox").value = "";

+				doSearch();

+			}

+

+			function searchNext() {

+				if (currentSearch !== null && currentMatchIndex !== null) {

+					currentSearch.matches[currentMatchIndex].setNotCurrent();

+					var nextMatchIndex = currentSearch.getNextVisibleMatchIndex();

+					if (nextMatchIndex > currentMatchIndex || confirm("Reached the end of the page. Start from the top?")) {

+						setCurrentMatchIndex(nextMatchIndex);

+					}

+				}

+			}

+

+			function searchPrevious() {

+				if (currentSearch !== null && currentMatchIndex !== null) {

+					currentSearch.matches[currentMatchIndex].setNotCurrent();

+					var previousMatchIndex = currentSearch.getPreviousVisibleMatchIndex();

+					if (previousMatchIndex < currentMatchIndex || confirm("Reached the start of the page. Continue from the bottom?")) {

+						setCurrentMatchIndex(previousMatchIndex);

+					}

+				}

+			}

+

+			function setCurrentMatchIndex(index) {

+				currentMatchIndex = index;

+				currentSearch.matches[currentMatchIndex].setCurrent();

+			}

+

+			/* ------------------------------------------------------------------------- */

+

+			// CSS Utilities

+

+			function addClass(el, cssClass) {

+				if (!hasClass(el, cssClass)) {

+					if (el.className) {

+						el.className += " " + cssClass;

+					} else {

+						el.className = cssClass;

+					}

+				}

+			}

+

+			function hasClass(el, cssClass) {

+				if (el.className) {

+					var classNames = el.className.split(" ");

+					return array_contains(classNames, cssClass);

+				}

+				return false;

+			}

+

+			function removeClass(el, cssClass) {

+				if (hasClass(el, cssClass)) {

+					// Rebuild the className property

+					var existingClasses = el.className.split(" ");

+					var newClasses = [];

+					for (var i = 0, len = existingClasses.length; i < len; i++) {

+						if (existingClasses[i] != cssClass) {

+							newClasses[newClasses.length] = existingClasses[i];

+						}

+					}

+					el.className = newClasses.join(" ");

+				}

+			}

+

+			function replaceClass(el, newCssClass, oldCssClass) {

+				removeClass(el, oldCssClass);

+				addClass(el, newCssClass);

+			}

+

+			/* ------------------------------------------------------------------------- */

+

+			// Other utility functions

+

+			function getElementsByClass(el, cssClass, tagName) {

+				var elements = el.getElementsByTagName(tagName);

+				var matches = [];

+				for (var i = 0, len = elements.length; i < len; i++) {

+					if (hasClass(elements[i], cssClass)) {

+						matches.push(elements[i]);

+					}

+				}

+				return matches;

+			}

+

+			// Syntax borrowed from Prototype library

+			function $(id) {

+				return document.getElementById(id);

+			}

+

+			function isDescendant(node, ancestorNode) {

+				while (node != null) {

+					if (node === ancestorNode) {

+						return true;

+					}

+					node = node.parentNode;

+				}

+				return false;

+			}

+

+			function isOrphan(node) {

+				var currentNode = node;

+				while (currentNode) {

+					if (currentNode == document.body) {

+						return false;

+					}

+					currentNode = currentNode.parentNode;

+				}

+				return true;

+			}

+

+			function escapeHtml(str) {

+				return str.replace(/&/g, "&amp;").replace(/[<]/g, "&lt;").replace(/>/g, "&gt;");

+			}

+

+			function getWindowWidth() {

+				if (window.innerWidth) {

+					return window.innerWidth;

+				} else if (document.documentElement && document.documentElement.clientWidth) {

+					return document.documentElement.clientWidth;

+				} else if (document.body) {

+					return document.body.clientWidth;

+				}

+				return 0;

+			}

+

+			function getWindowHeight() {

+				if (window.innerHeight) {

+					return window.innerHeight;

+				} else if (document.documentElement && document.documentElement.clientHeight) {

+					return document.documentElement.clientHeight;

+				} else if (document.body) {

+					return document.body.clientHeight;

+				}

+				return 0;

+			}

+

+			function getToolBarsHeight() {

+				return $("switches").offsetHeight;

+			}

+

+			function getChromeHeight() {

+				var height = getToolBarsHeight();

+				if (showCommandLine) {

+					height += $("commandLine").offsetHeight;

+				}

+				return height;

+			}

+

+			function setLogContainerHeight() {

+				if (logMainContainer) {

+					var windowHeight = getWindowHeight();

+					$("body").style.height = getWindowHeight() + "px";

+					logMainContainer.style.height = "" +

+						Math.max(0, windowHeight - getChromeHeight()) + "px";

+				}

+			}

+

+			function setCommandInputWidth() {

+				if (showCommandLine) {

+					$("command").style.width = "" + Math.max(0, $("commandLineContainer").offsetWidth -

+						($("evaluateButton").offsetWidth + 13)) + "px";

+				}

+			}

+

+			window.onresize = function() {

+				setCommandInputWidth();

+				setLogContainerHeight();

+			};

+

+			if (!Array.prototype.push) {

+				Array.prototype.push = function() {

+			        for (var i = 0, len = arguments.length; i < len; i++){

+			            this[this.length] = arguments[i];

+			        }

+			        return this.length;

+				};

+			}

+

+			if (!Array.prototype.pop) {

+				Array.prototype.pop = function() {

+					if (this.length > 0) {

+						var val = this[this.length - 1];

+						this.length = this.length - 1;

+						return val;

+					}

+				};

+			}

+

+			if (!Array.prototype.shift) {

+				Array.prototype.shift = function() {

+					if (this.length > 0) {

+						var firstItem = this[0];

+						for (var i = 0, len = this.length - 1; i < len; i++) {

+							this[i] = this[i + 1];

+						}

+						this.length = this.length - 1;

+						return firstItem;

+					}

+				};

+			}

+

+			if (!Array.prototype.splice) {

+				Array.prototype.splice = function(startIndex, deleteCount) {

+					var itemsAfterDeleted = this.slice(startIndex + deleteCount);

+					var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);

+					this.length = startIndex;

+					// Copy the arguments into a proper Array object

+					var argumentsArray = [];

+					for (var i = 0, len = arguments.length; i < len; i++) {

+						argumentsArray[i] = arguments[i];

+					}

+					var itemsToAppend = (argumentsArray.length > 2) ?

+						itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;

+					for (i = 0, len = itemsToAppend.length; i < len; i++) {

+						this.push(itemsToAppend[i]);

+					}

+					return itemsDeleted;

+				};

+			}

+

+			function array_remove(arr, val) {

+				var index = -1;

+				for (var i = 0, len = arr.length; i < len; i++) {

+					if (arr[i] === val) {

+						index = i;

+						break;

+					}

+				}

+				if (index >= 0) {

+					arr.splice(index, 1);

+					return index;

+				} else {

+					return false;

+				}

+			}

+

+			function array_removeFromStart(array, numberToRemove) {

+				if (Array.prototype.splice) {

+					array.splice(0, numberToRemove);

+				} else {

+					for (var i = numberToRemove, len = array.length; i < len; i++) {

+						array[i - numberToRemove] = array[i];

+					}

+					array.length = array.length - numberToRemove;

+				}

+				return array;

+			}

+

+			function array_contains(arr, val) {

+				for (var i = 0, len = arr.length; i < len; i++) {

+					if (arr[i] == val) {

+						return true;

+					}

+				}

+				return false;

+			}

+

+			function getErrorMessage(ex) {

+				if (ex.message) {

+					return ex.message;

+				} else if (ex.description) {

+					return ex.description;

+				}

+				return "" + ex;

+			}

+

+			function moveCaretToEnd(input) {

+				if (input.setSelectionRange) {

+					input.focus();

+					var length = input.value.length;

+					input.setSelectionRange(length, length);

+				} else if (input.createTextRange) {

+					var range = input.createTextRange();

+					range.collapse(false);

+					range.select();

+				}

+				input.focus();

+			}

+

+			function stopPropagation(evt) {

+				if (evt.stopPropagation) {

+					evt.stopPropagation();

+				} else if (typeof evt.cancelBubble != "undefined") {

+					evt.cancelBubble = true;

+				}

+			}

+

+			function getEvent(evt) {

+				return evt ? evt : event;

+			}

+

+			function getTarget(evt) {

+				return evt.target ? evt.target : evt.srcElement;

+			}

+

+			function getRelatedTarget(evt) {

+				if (evt.relatedTarget) {

+					return evt.relatedTarget;

+				} else if (evt.srcElement) {

+					switch(evt.type) {

+						case "mouseover":

+							return evt.fromElement;

+						case "mouseout":

+							return evt.toElement;

+						default:

+							return evt.srcElement;

+					}

+				}

+			}

+

+			function cancelKeyEvent(evt) {

+				evt.returnValue = false;

+				stopPropagation(evt);

+			}

+

+			function evalCommandLine() {

+				var expr = $("command").value;

+				evalCommand(expr);

+				$("command").value = "";

+			}

+

+			function evalLastCommand() {

+				if (lastCommand != null) {

+					evalCommand(lastCommand);

+				}

+			}

+

+			var lastCommand = null;

+			var commandHistory = [];

+			var currentCommandIndex = 0;

+

+			function evalCommand(expr) {

+				if (appender) {

+					appender.evalCommandAndAppend(expr);

+				} else {

+					var prefix = ">>> " + expr + "\r\n";

+					try {

+						log("INFO", prefix + eval(expr));

+					} catch (ex) {

+						log("ERROR", prefix + "Error: " + getErrorMessage(ex));

+					}

+				}

+				// Update command history

+				if (expr != commandHistory[commandHistory.length - 1]) {

+					commandHistory.push(expr);

+					// Update the appender

+					if (appender) {

+						appender.storeCommandHistory(commandHistory);

+					}

+				}

+				currentCommandIndex = (expr == commandHistory[currentCommandIndex]) ? currentCommandIndex + 1 : commandHistory.length;

+				lastCommand = expr;

+			}

+			//]]>

+		</script>

+		<style type="text/css">

+			body {

+				background-color: white;

+				color: black;

+				padding: 0;

+				margin: 0;

+				font-family: tahoma, verdana, arial, helvetica, sans-serif;

+				overflow: hidden;

+			}

+

+			div#switchesContainer input {

+				margin-bottom: 0;

+			}

+

+			div.toolbar {

+				border-top: solid #ffffff 1px;

+				border-bottom: solid #aca899 1px;

+				background-color: #f1efe7;

+				padding: 3px 5px;

+				font-size: 68.75%;

+			}

+

+			div.toolbar, div#search input {

+				font-family: tahoma, verdana, arial, helvetica, sans-serif;

+			}

+

+			div.toolbar input.button {

+				padding: 0 5px;

+				font-size: 100%;

+			}

+

+			div.toolbar input.hidden {

+				display: none;

+			}

+

+			div#switches input#clearButton {

+				margin-left: 20px;

+			}

+

+			div#levels label {

+				font-weight: bold;

+			}

+

+			div#levels label, div#options label {

+				margin-right: 5px;

+			}

+

+			div#levels label#wrapLabel {

+				font-weight: normal;

+			}

+

+			div#search label {

+				margin-right: 10px;

+			}

+

+			div#search label.searchboxlabel {

+				margin-right: 0;

+			}

+

+			div#search input {

+				font-size: 100%;

+			}

+

+			div#search input.validregex {

+				color: green;

+			}

+

+			div#search input.invalidregex {

+				color: red;

+			}

+

+			div#search input.nomatches {

+				color: white;

+				background-color: #ff6666;

+			}

+

+			div#search input.nomatches {

+				color: white;

+				background-color: #ff6666;

+			}

+

+			div#searchNav {

+				display: none;

+			}

+

+			div#commandLine {

+				display: none;

+			}

+

+			div#commandLine input#command {

+				font-size: 100%;

+				font-family: Courier New, Courier;

+			}

+

+			div#commandLine input#evaluateButton {

+			}

+

+			*.greyedout {

+				color: gray !important;

+				border-color: gray !important;

+			}

+

+			*.greyedout *.alwaysenabled { color: black; }

+

+			*.unselectable {

+				-khtml-user-select: none;

+				-moz-user-select: none;

+				user-select: none;

+			}

+

+			div#log {

+				font-family: Courier New, Courier;

+				font-size: 75%;

+				width: 100%;

+				overflow: auto;

+				clear: both;

+				position: relative;

+			}

+

+			div.group {

+				border-color: #cccccc;

+				border-style: solid;

+				border-width: 1px 0 1px 1px;

+				overflow: visible;

+			}

+

+			div.oldIe div.group, div.oldIe div.group *, div.oldIe *.logentry {

+				height: 1%;

+			}

+

+			div.group div.groupheading span.expander {

+				border: solid black 1px;

+				font-family: Courier New, Courier;

+				font-size: 0.833em;

+				background-color: #eeeeee;

+				position: relative;

+				top: -1px;

+				color: black;

+				padding: 0 2px;

+				cursor: pointer;

+				cursor: hand;

+				height: 1%;

+			}

+

+			div.group div.groupcontent {

+				margin-left: 10px;

+				padding-bottom: 2px;

+				overflow: visible;

+			}

+

+			div.group div.expanded {

+				display: block;

+			}

+

+			div.group div.collapsed {

+				display: none;

+			}

+

+			*.logentry {

+				overflow: visible;

+				display: none;

+				white-space: pre;

+			}

+

+			span.pre {

+				white-space: pre;

+			}

+			

+			pre.unwrapped {

+				display: inline !important;

+			}

+

+			pre.unwrapped pre.pre, div.wrapped pre.pre {

+				display: inline;

+			}

+

+			div.wrapped pre.pre {

+				white-space: normal;

+			}

+

+			div.wrapped {

+				display: none;

+			}

+

+			body.searching *.logentry span.currentmatch {

+				color: white !important;

+				background-color: green !important;

+			}

+

+			body.searching div.searchhighlight *.logentry span.searchterm {

+				color: black;

+				background-color: yellow;

+			}

+

+			div.wrap *.logentry {

+				white-space: normal !important;

+				border-width: 0 0 1px 0;

+				border-color: #dddddd;

+				border-style: dotted;

+			}

+

+			div.wrap #log_wrapped, #log_unwrapped {

+				display: block;

+			}

+

+			div.wrap #log_unwrapped, #log_wrapped {

+				display: none;

+			}

+

+			div.wrap *.logentry span.pre {

+				overflow: visible;

+				white-space: normal;

+			}

+

+			div.wrap *.logentry pre.unwrapped {

+				display: none;

+			}

+

+			div.wrap *.logentry span.wrapped {

+				display: inline;

+			}

+

+			div.searchfilter *.searchnonmatch {

+				display: none !important;

+			}

+

+			div#log *.TRACE, label#label_TRACE {

+				color: #666666;

+			}

+

+			div#log *.DEBUG, label#label_DEBUG {

+				color: green;

+			}

+

+			div#log *.INFO, label#label_INFO {

+				color: #000099;

+			}

+

+			div#log *.WARN, label#label_WARN {

+				color: #999900;

+			}

+

+			div#log *.ERROR, label#label_ERROR {

+				color: red;

+			}

+

+			div#log *.FATAL, label#label_FATAL {

+				color: #660066;

+			}

+

+			div.TRACE#log *.TRACE,

+			div.DEBUG#log *.DEBUG,

+			div.INFO#log *.INFO,

+			div.WARN#log *.WARN,

+			div.ERROR#log *.ERROR,

+			div.FATAL#log *.FATAL {

+				display: block;

+			}

+

+			div#log div.separator {

+				background-color: #cccccc;

+				margin: 5px 0;

+				line-height: 1px;

+			}

+		</style>

+	</head>

+

+	<body id="body">

+		<div id="switchesContainer">

+			<div id="switches">

+				<div id="levels" class="toolbar">

+					Filters:

+					<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>

+					<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>

+					<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>

+					<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>

+					<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>

+					<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>

+					<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>

+				</div>

+				<div id="search" class="toolbar">

+					<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />

+					<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />

+					<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>

+					<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>

+					<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>

+					<div id="searchNav">

+						<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />

+						<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />

+						<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>

+						<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>

+					</div>

+				</div>

+				<div id="options" class="toolbar">

+					Options:

+					<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>

+					<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>

+					<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>

+					<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>

+					<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />

+					<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />

+					<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />

+				</div>

+			</div>

+		</div>

+		<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>

+		<div id="commandLine" class="toolbar">

+			<div id="commandLineContainer">

+				<input type="text" id="command" title="Enter a JavaScript command here and hit return or press 'Evaluate'" />

+				<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />

+			</div>

+		</div>

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/liteconsole.html b/planetstack/core/static/log4javascript-1.4.6/js/liteconsole.html
new file mode 100644
index 0000000..840a59b
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/liteconsole.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+<head>

+<title>log4javascript</title>

+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

+<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->

+<meta http-equiv="X-UA-Compatible" content="IE=7" />

+<script type="text/javascript">

+//<![CDATA[

+var loggingEnabled=true;var messagesBeforeDocLoaded=[];function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}

+function setLoggingEnabled(enable){loggingEnabled=enable;}

+function scrollToLatestEntry(){var l=getLogContainer();if(typeof l.scrollTop!="undefined"){var latestLogEntry=l.lastChild;if(latestLogEntry){l.scrollTop=l.scrollHeight;}}}

+function log(logLevel,formattedMessage){if(loggingEnabled){if(loaded){doLog(logLevel,formattedMessage);}else{messagesBeforeDocLoaded.push([logLevel,formattedMessage]);}}}

+function doLog(logLevel,formattedMessage){var logEntry=document.createElement("div");logEntry.appendChild(document.createTextNode(formattedMessage));logEntry.className="logentry "+logLevel.name;getLogContainer().appendChild(logEntry);scrollToLatestEntry();}

+function mainPageReloaded(){var separator=document.createElement("div");separator.className="separator";separator.innerHTML="&nbsp;";getLogContainer().appendChild(separator);}

+var loaded=false;var logLevels=["DEBUG","INFO","WARN","ERROR","FATAL"];window.onload=function(){setLogContainerHeight();toggleLoggingEnabled();for(var i=0;i<messagesBeforeDocLoaded.length;i++){doLog(messagesBeforeDocLoaded[i][0],messagesBeforeDocLoaded[i][1]);}

+messagesBeforeDocLoaded=[];loaded=true;setTimeout(setLogContainerHeight,20);};function getLogContainer(){return $("log");}

+function clearLog(){getLogContainer().innerHTML="";}

+function $(id){return document.getElementById(id);}

+function getWindowHeight(){if(window.innerHeight){return window.innerHeight;}else if(document.documentElement&&document.documentElement.clientHeight){return document.documentElement.clientHeight;}else if(document.body){return document.body.clientHeight;}

+return 0;}

+function getChromeHeight(){return $("toolbar").offsetHeight;}

+function setLogContainerHeight(){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";getLogContainer().style.height=""+

+Math.max(0,windowHeight-getChromeHeight())+"px";}

+window.onresize=function(){setLogContainerHeight();};

+//]]>

+</script>

+<style type="text/css">

+body{background-color:white;color:black;padding:0;margin:0;font-family:tahoma,verdana,arial,helvetica,sans-serif;overflow:hidden}div#toolbar{border-top:solid #ffffff 1px;border-bottom:solid #aca899 1px;background-color:#f1efe7;padding:3px 5px;font-size:68.75%}div#toolbar input.button{padding:0 5px;font-size:100%}div#log{font-family:Courier New,Courier;font-size:75%;width:100%;overflow:auto;clear:both}*.logentry{overflow:visible;white-space:pre}*.TRACE{color:#666666}*.DEBUG{color:green}*.INFO{color:#000099}*.WARN{color:#999900}*.ERROR{color:red}*.FATAL{color:#660066}div#log div.separator{background-color:#cccccc;margin:5px 0;line-height:1px}

+</style>

+</head>

+<body id="body">

+<div id="toolbar">

+Options:

+<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" class="stateful" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Enable logging</label>

+<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="stateful button" title="Clear all log messages"  />

+<input type="button" id="closeButton" value="Close" onclick="window.close()" class="stateful button" title="Close the window" />

+</div>

+<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>

+</body>

+</html>
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/js/liteconsole_uncompressed.html b/planetstack/core/static/log4javascript-1.4.6/js/liteconsole_uncompressed.html
new file mode 100644
index 0000000..df5275f
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/liteconsole_uncompressed.html
@@ -0,0 +1,194 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript</title>

+		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

+		<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->

+		<meta http-equiv="X-UA-Compatible" content="IE=7" />

+		<script type="text/javascript">

+			//<![CDATA[

+			var loggingEnabled = true;

+			var messagesBeforeDocLoaded = [];

+

+			function toggleLoggingEnabled() {

+				setLoggingEnabled($("enableLogging").checked);

+			}

+

+			function setLoggingEnabled(enable) {

+				loggingEnabled = enable;

+			}

+

+			function scrollToLatestEntry() {

+				var l = getLogContainer();

+				if (typeof l.scrollTop != "undefined") {

+					var latestLogEntry = l.lastChild;

+					if (latestLogEntry) {

+						l.scrollTop = l.scrollHeight;

+					}

+				}

+			}

+

+			function log(logLevel, formattedMessage) {

+				if (loggingEnabled) {

+					if (loaded) {

+						doLog(logLevel, formattedMessage);

+					} else {

+						messagesBeforeDocLoaded.push([logLevel, formattedMessage]);

+					}

+				}

+			}

+

+			function doLog(logLevel, formattedMessage) {

+				var logEntry = document.createElement("div");

+				logEntry.appendChild(document.createTextNode(formattedMessage));

+				logEntry.className = "logentry " + logLevel.name;

+				getLogContainer().appendChild(logEntry);

+				scrollToLatestEntry();

+			}

+

+			function mainPageReloaded() {

+				var separator = document.createElement("div");

+				separator.className = "separator";

+				separator.innerHTML = "&nbsp;";

+				getLogContainer().appendChild(separator);

+			}

+

+			var loaded = false;

+			var logLevels = ["DEBUG", "INFO", "WARN", "ERROR", "FATAL"];

+

+			window.onload = function() {

+				setLogContainerHeight();

+				toggleLoggingEnabled();

+				for (var i = 0; i < messagesBeforeDocLoaded.length; i++) {

+					doLog(messagesBeforeDocLoaded[i][0], messagesBeforeDocLoaded[i][1]);

+				}

+				messagesBeforeDocLoaded = [];

+				loaded = true;

+

+				// Workaround to make sure log div starts at the correct size

+				setTimeout(setLogContainerHeight, 20);

+			};

+

+			function getLogContainer() {

+				return $("log");

+			}

+

+			function clearLog() {

+				getLogContainer().innerHTML = "";

+			}

+

+			/* ------------------------------------------------------------------------- */

+

+			// Other utility functions

+

+			// Syntax borrowed from Prototype library

+			function $(id) {

+				return document.getElementById(id);

+			}

+

+			function getWindowHeight() {

+				if (window.innerHeight) {

+					return window.innerHeight;

+				} else if (document.documentElement && document.documentElement.clientHeight) {

+					return document.documentElement.clientHeight;

+				} else if (document.body) {

+					return document.body.clientHeight;

+				}

+				return 0;

+			}

+

+			function getChromeHeight() {

+				return $("toolbar").offsetHeight;

+			}

+

+			function setLogContainerHeight() {

+				var windowHeight = getWindowHeight();

+				$("body").style.height = getWindowHeight() + "px";

+				getLogContainer().style.height = "" +

+					Math.max(0, windowHeight - getChromeHeight()) + "px";

+			}

+

+			window.onresize = function() {

+				setLogContainerHeight();

+			};

+

+			//]]>

+		</script>

+		<style type="text/css">

+			body {

+				background-color: white;

+				color: black;

+				padding: 0;

+				margin: 0;

+				font-family: tahoma, verdana, arial, helvetica, sans-serif;

+				overflow: hidden;

+			}

+			

+			div#toolbar {

+				border-top: solid #ffffff 1px;

+				border-bottom: solid #aca899 1px;

+				background-color: #f1efe7;

+				padding: 3px 5px;

+				font-size: 68.75%;

+			}

+

+			div#toolbar input.button {

+				padding: 0 5px;

+				font-size: 100%;

+			}

+

+			div#log {

+				font-family: Courier New, Courier;

+				font-size: 75%;

+				width: 100%;

+				overflow: auto;

+				clear: both;

+			}

+

+			*.logentry {

+				overflow: visible;

+				white-space: pre;

+			}

+

+			*.TRACE {

+				color: #666666;

+			}

+

+			*.DEBUG {

+				color: green;

+			}

+

+			*.INFO {

+				color: #000099;

+			}

+

+			*.WARN {

+				color: #999900;

+			}

+

+			*.ERROR {

+				color: red;

+			}

+

+			*.FATAL {

+				color: #660066;

+			}

+

+			div#log div.separator {

+				background-color: #cccccc;

+				margin: 5px 0;

+				line-height: 1px;

+			}

+		</style>

+	</head>

+

+	<body id="body">

+		<div id="toolbar">

+			Options:

+			<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" class="stateful" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Enable logging</label>

+			<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="stateful button" title="Clear all log messages"  />

+			<input type="button" id="closeButton" value="Close" onclick="window.close()" class="stateful button" title="Close the window" />

+		</div>

+		<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>

+	</body>

+</html>
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/js/log4javascript.js b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript.js
new file mode 100644
index 0000000..042daa9
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript.js
@@ -0,0 +1,274 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}

+return this.length;};}

+if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}

+this.length=this.length-1;return firstItem;}};}

+if(!Array.prototype.splice){Array.prototype.splice=function(startIndex,deleteCount){var itemsAfterDeleted=this.slice(startIndex+deleteCount);var itemsDeleted=this.slice(startIndex,startIndex+deleteCount);this.length=startIndex;var argumentsArray=[];for(var i=0,len=arguments.length;i<len;i++){argumentsArray[i]=arguments[i];}

+var itemsToAppend=(argumentsArray.length>2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i<len;i++){this.push(itemsToAppend[i]);}

+return itemsDeleted;};}

+var log4javascript=(function(){function isUndefined(obj){return typeof obj=="undefined";}

+function EventSupport(){}

+EventSupport.prototype={eventTypes:[],eventListeners:{},setEventTypes:function(eventTypesParam){if(eventTypesParam instanceof Array){this.eventTypes=eventTypesParam;this.eventListeners={};for(var i=0,len=this.eventTypes.length;i<len;i++){this.eventListeners[this.eventTypes[i]]=[];}}else{handleError("log4javascript.EventSupport ["+this+"]: setEventTypes: eventTypes parameter must be an Array");}},addEventListener:function(eventType,listener){if(typeof listener=="function"){if(!array_contains(this.eventTypes,eventType)){handleError("log4javascript.EventSupport ["+this+"]: addEventListener: no event called '"+eventType+"'");}

+this.eventListeners[eventType].push(listener);}else{handleError("log4javascript.EventSupport ["+this+"]: addEventListener: listener must be a function");}},removeEventListener:function(eventType,listener){if(typeof listener=="function"){if(!array_contains(this.eventTypes,eventType)){handleError("log4javascript.EventSupport ["+this+"]: removeEventListener: no event called '"+eventType+"'");}

+array_remove(this.eventListeners[eventType],listener);}else{handleError("log4javascript.EventSupport ["+this+"]: removeEventListener: listener must be a function");}},dispatchEvent:function(eventType,eventArgs){if(array_contains(this.eventTypes,eventType)){var listeners=this.eventListeners[eventType];for(var i=0,len=listeners.length;i<len;i++){listeners[i](this,eventType,eventArgs);}}else{handleError("log4javascript.EventSupport ["+this+"]: dispatchEvent: no event called '"+eventType+"'");}}};var applicationStartDate=new Date();var uniqueId="log4javascript_"+applicationStartDate.getTime()+"_"+

+Math.floor(Math.random()*100000000);var emptyFunction=function(){};var newLine="\r\n";var pageLoaded=false;function Log4JavaScript(){}

+Log4JavaScript.prototype=new EventSupport();log4javascript=new Log4JavaScript();log4javascript.version="1.4.6";log4javascript.edition="log4javascript";function toStr(obj){if(obj&&obj.toString){return obj.toString();}else{return String(obj);}}

+function getExceptionMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}else{return toStr(ex);}}

+function getUrlFileName(url){var lastSlashIndex=Math.max(url.lastIndexOf("/"),url.lastIndexOf("\\"));return url.substr(lastSlashIndex+1);}

+function getExceptionStringRep(ex){if(ex){var exStr="Exception: "+getExceptionMessage(ex);try{if(ex.lineNumber){exStr+=" on line number "+ex.lineNumber;}

+if(ex.fileName){exStr+=" in file "+getUrlFileName(ex.fileName);}}catch(localEx){logLog.warn("Unable to obtain file and line information for error");}

+if(showStackTraces&&ex.stack){exStr+=newLine+"Stack trace:"+newLine+ex.stack;}

+return exStr;}

+return null;}

+function bool(obj){return Boolean(obj);}

+function trim(str){return str.replace(/^\s+/,"").replace(/\s+$/,"");}

+function splitIntoLines(text){var text2=text.replace(/\r\n/g,"\n").replace(/\r/g,"\n");return text2.split("\n");}

+var urlEncode=(typeof window.encodeURIComponent!="undefined")?function(str){return encodeURIComponent(str);}:function(str){return escape(str).replace(/\+/g,"%2B").replace(/"/g,"%22").replace(/'/g,"%27").replace(/\//g,"%2F").replace(/=/g,"%3D");};var urlDecode=(typeof window.decodeURIComponent!="undefined")?function(str){return decodeURIComponent(str);}:function(str){return unescape(str).replace(/%2B/g,"+").replace(/%22/g,"\"").replace(/%27/g,"'").replace(/%2F/g,"/").replace(/%3D/g,"=");};function array_remove(arr,val){var index=-1;for(var i=0,len=arr.length;i<len;i++){if(arr[i]===val){index=i;break;}}

+if(index>=0){arr.splice(index,1);return true;}else{return false;}}

+function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}

+return false;}

+function extractBooleanFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return bool(param);}}

+function extractStringFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return String(param);}}

+function extractIntFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{try{var value=parseInt(param,10);return isNaN(value)?defaultValue:value;}catch(ex){logLog.warn("Invalid int param "+param,ex);return defaultValue;}}}

+function extractFunctionFromParam(param,defaultValue){if(typeof param=="function"){return param;}else{return defaultValue;}}

+function isError(err){return(err instanceof Error);}

+if(!Function.prototype.apply){Function.prototype.apply=function(obj,args){var methodName="__apply__";if(typeof obj[methodName]!="undefined"){methodName+=String(Math.random()).substr(2);}

+obj[methodName]=this;var argsStrings=[];for(var i=0,len=args.length;i<len;i++){argsStrings[i]="args["+i+"]";}

+var script="obj."+methodName+"("+argsStrings.join(",")+")";var returnValue=eval(script);delete obj[methodName];return returnValue;};}

+if(!Function.prototype.call){Function.prototype.call=function(obj){var args=[];for(var i=1,len=arguments.length;i<len;i++){args[i-1]=arguments[i];}

+return this.apply(obj,args);};}

+function getListenersPropertyName(eventName){return"__log4javascript_listeners__"+eventName;}

+function addEvent(node,eventName,listener,useCapture,win){win=win?win:window;if(node.addEventListener){node.addEventListener(eventName,listener,useCapture);}else if(node.attachEvent){node.attachEvent("on"+eventName,listener);}else{var propertyName=getListenersPropertyName(eventName);if(!node[propertyName]){node[propertyName]=[];node["on"+eventName]=function(evt){evt=getEvent(evt,win);var listenersPropertyName=getListenersPropertyName(eventName);var listeners=this[listenersPropertyName].concat([]);var currentListener;while((currentListener=listeners.shift())){currentListener.call(this,evt);}};}

+node[propertyName].push(listener);}}

+function removeEvent(node,eventName,listener,useCapture){if(node.removeEventListener){node.removeEventListener(eventName,listener,useCapture);}else if(node.detachEvent){node.detachEvent("on"+eventName,listener);}else{var propertyName=getListenersPropertyName(eventName);if(node[propertyName]){array_remove(node[propertyName],listener);}}}

+function getEvent(evt,win){win=win?win:window;return evt?evt:win.event;}

+function stopEventPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}

+evt.returnValue=false;}

+var logLog={quietMode:false,debugMessages:[],setQuietMode:function(quietMode){this.quietMode=bool(quietMode);},numberOfErrors:0,alertAllErrors:false,setAlertAllErrors:function(alertAllErrors){this.alertAllErrors=alertAllErrors;},debug:function(message){this.debugMessages.push(message);},displayDebug:function(){alert(this.debugMessages.join(newLine));},warn:function(message,exception){},error:function(message,exception){if(++this.numberOfErrors==1||this.alertAllErrors){if(!this.quietMode){var alertMessage="log4javascript error: "+message;if(exception){alertMessage+=newLine+newLine+"Original error: "+getExceptionStringRep(exception);}

+alert(alertMessage);}}}};log4javascript.logLog=logLog;log4javascript.setEventTypes(["load","error"]);function handleError(message,exception){logLog.error(message,exception);log4javascript.dispatchEvent("error",{"message":message,"exception":exception});}

+log4javascript.handleError=handleError;var enabled=!((typeof log4javascript_disabled!="undefined")&&log4javascript_disabled);log4javascript.setEnabled=function(enable){enabled=bool(enable);};log4javascript.isEnabled=function(){return enabled;};var useTimeStampsInMilliseconds=true;log4javascript.setTimeStampsInMilliseconds=function(timeStampsInMilliseconds){useTimeStampsInMilliseconds=bool(timeStampsInMilliseconds);};log4javascript.isTimeStampsInMilliseconds=function(){return useTimeStampsInMilliseconds;};log4javascript.evalInScope=function(expr){return eval(expr);};var showStackTraces=false;log4javascript.setShowStackTraces=function(show){showStackTraces=bool(show);};var Level=function(level,name){this.level=level;this.name=name;};Level.prototype={toString:function(){return this.name;},equals:function(level){return this.level==level.level;},isGreaterOrEqual:function(level){return this.level>=level.level;}};Level.ALL=new Level(Number.MIN_VALUE,"ALL");Level.TRACE=new Level(10000,"TRACE");Level.DEBUG=new Level(20000,"DEBUG");Level.INFO=new Level(30000,"INFO");Level.WARN=new Level(40000,"WARN");Level.ERROR=new Level(50000,"ERROR");Level.FATAL=new Level(60000,"FATAL");Level.OFF=new Level(Number.MAX_VALUE,"OFF");log4javascript.Level=Level;function Timer(name,level){this.name=name;this.level=isUndefined(level)?Level.INFO:level;this.start=new Date();}

+Timer.prototype.getElapsedTime=function(){return new Date().getTime()-this.start.getTime();};var anonymousLoggerName="[anonymous]";var defaultLoggerName="[default]";var nullLoggerName="[null]";var rootLoggerName="root";function Logger(name){this.name=name;this.parent=null;this.children=[];var appenders=[];var loggerLevel=null;var isRoot=(this.name===rootLoggerName);var isNull=(this.name===nullLoggerName);var appenderCache=null;var appenderCacheInvalidated=false;this.addChild=function(childLogger){this.children.push(childLogger);childLogger.parent=this;childLogger.invalidateAppenderCache();};var additive=true;this.getAdditivity=function(){return additive;};this.setAdditivity=function(additivity){var valueChanged=(additive!=additivity);additive=additivity;if(valueChanged){this.invalidateAppenderCache();}};this.addAppender=function(appender){if(isNull){handleError("Logger.addAppender: you may not add an appender to the null logger");}else{if(appender instanceof log4javascript.Appender){if(!array_contains(appenders,appender)){appenders.push(appender);appender.setAddedToLogger(this);this.invalidateAppenderCache();}}else{handleError("Logger.addAppender: appender supplied ('"+

+toStr(appender)+"') is not a subclass of Appender");}}};this.removeAppender=function(appender){array_remove(appenders,appender);appender.setRemovedFromLogger(this);this.invalidateAppenderCache();};this.removeAllAppenders=function(){var appenderCount=appenders.length;if(appenderCount>0){for(var i=0;i<appenderCount;i++){appenders[i].setRemovedFromLogger(this);}

+appenders.length=0;this.invalidateAppenderCache();}};this.getEffectiveAppenders=function(){if(appenderCache===null||appenderCacheInvalidated){var parentEffectiveAppenders=(isRoot||!this.getAdditivity())?[]:this.parent.getEffectiveAppenders();appenderCache=parentEffectiveAppenders.concat(appenders);appenderCacheInvalidated=false;}

+return appenderCache;};this.invalidateAppenderCache=function(){appenderCacheInvalidated=true;for(var i=0,len=this.children.length;i<len;i++){this.children[i].invalidateAppenderCache();}};this.log=function(level,params){if(enabled&&level.isGreaterOrEqual(this.getEffectiveLevel())){var exception;var finalParamIndex=params.length-1;var lastParam=params[finalParamIndex];if(params.length>1&&isError(lastParam)){exception=lastParam;finalParamIndex--;}

+var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];}

+var loggingEvent=new LoggingEvent(this,new Date(),level,messages,exception);this.callAppenders(loggingEvent);}};this.callAppenders=function(loggingEvent){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].doAppend(loggingEvent);}};this.setLevel=function(level){if(isRoot&&level===null){handleError("Logger.setLevel: you cannot set the level of the root logger to null");}else if(level instanceof Level){loggerLevel=level;}else{handleError("Logger.setLevel: level supplied to logger "+

+this.name+" is not an instance of log4javascript.Level");}};this.getLevel=function(){return loggerLevel;};this.getEffectiveLevel=function(){for(var logger=this;logger!==null;logger=logger.parent){var level=logger.getLevel();if(level!==null){return level;}}};this.group=function(name,initiallyExpanded){if(enabled){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].group(name,initiallyExpanded);}}};this.groupEnd=function(){if(enabled){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].groupEnd();}}};var timers={};this.time=function(name,level){if(enabled){if(isUndefined(name)){handleError("Logger.time: a name for the timer must be supplied");}else if(level&&!(level instanceof Level)){handleError("Logger.time: level supplied to timer "+

+name+" is not an instance of log4javascript.Level");}else{timers[name]=new Timer(name,level);}}};this.timeEnd=function(name){if(enabled){if(isUndefined(name)){handleError("Logger.timeEnd: a name for the timer must be supplied");}else if(timers[name]){var timer=timers[name];var milliseconds=timer.getElapsedTime();this.log(timer.level,["Timer "+toStr(name)+" completed in "+milliseconds+"ms"]);delete timers[name];}else{logLog.warn("Logger.timeEnd: no timer found with name "+name);}}};this.assert=function(expr){if(enabled&&!expr){var args=[];for(var i=1,len=arguments.length;i<len;i++){args.push(arguments[i]);}

+args=(args.length>0)?args:["Assertion Failure"];args.push(newLine);args.push(expr);this.log(Level.ERROR,args);}};this.toString=function(){return"Logger["+this.name+"]";};}

+Logger.prototype={trace:function(){this.log(Level.TRACE,arguments);},debug:function(){this.log(Level.DEBUG,arguments);},info:function(){this.log(Level.INFO,arguments);},warn:function(){this.log(Level.WARN,arguments);},error:function(){this.log(Level.ERROR,arguments);},fatal:function(){this.log(Level.FATAL,arguments);},isEnabledFor:function(level){return level.isGreaterOrEqual(this.getEffectiveLevel());},isTraceEnabled:function(){return this.isEnabledFor(Level.TRACE);},isDebugEnabled:function(){return this.isEnabledFor(Level.DEBUG);},isInfoEnabled:function(){return this.isEnabledFor(Level.INFO);},isWarnEnabled:function(){return this.isEnabledFor(Level.WARN);},isErrorEnabled:function(){return this.isEnabledFor(Level.ERROR);},isFatalEnabled:function(){return this.isEnabledFor(Level.FATAL);}};Logger.prototype.trace.isEntryPoint=true;Logger.prototype.debug.isEntryPoint=true;Logger.prototype.info.isEntryPoint=true;Logger.prototype.warn.isEntryPoint=true;Logger.prototype.error.isEntryPoint=true;Logger.prototype.fatal.isEntryPoint=true;var loggers={};var loggerNames=[];var ROOT_LOGGER_DEFAULT_LEVEL=Level.DEBUG;var rootLogger=new Logger(rootLoggerName);rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);log4javascript.getRootLogger=function(){return rootLogger;};log4javascript.getLogger=function(loggerName){if(!(typeof loggerName=="string")){loggerName=anonymousLoggerName;logLog.warn("log4javascript.getLogger: non-string logger name "+

+toStr(loggerName)+" supplied, returning anonymous logger");}

+if(loggerName==rootLoggerName){handleError("log4javascript.getLogger: root logger may not be obtained by name");}

+if(!loggers[loggerName]){var logger=new Logger(loggerName);loggers[loggerName]=logger;loggerNames.push(loggerName);var lastDotIndex=loggerName.lastIndexOf(".");var parentLogger;if(lastDotIndex>-1){var parentLoggerName=loggerName.substring(0,lastDotIndex);parentLogger=log4javascript.getLogger(parentLoggerName);}else{parentLogger=rootLogger;}

+parentLogger.addChild(logger);}

+return loggers[loggerName];};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=log4javascript.getLogger(defaultLoggerName);var a=new log4javascript.PopUpAppender();defaultLogger.addAppender(a);}

+return defaultLogger;};var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger(nullLoggerName);nullLogger.setLevel(Level.OFF);}

+return nullLogger;};log4javascript.resetConfiguration=function(){rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);loggers={};};var LoggingEvent=function(logger,timeStamp,level,messages,exception){this.logger=logger;this.timeStamp=timeStamp;this.timeStampInMilliseconds=timeStamp.getTime();this.timeStampInSeconds=Math.floor(this.timeStampInMilliseconds/1000);this.milliseconds=this.timeStamp.getMilliseconds();this.level=level;this.messages=messages;this.exception=exception;};LoggingEvent.prototype={getThrowableStrRep:function(){return this.exception?getExceptionStringRep(this.exception):"";},getCombinedMessages:function(){return(this.messages.length==1)?this.messages[0]:this.messages.join(newLine);},toString:function(){return"LoggingEvent["+this.level+"]";}};log4javascript.LoggingEvent=LoggingEvent;var Layout=function(){};Layout.prototype={defaults:{loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url"},loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url",batchHeader:"",batchFooter:"",batchSeparator:"",returnsPostData:false,overrideTimeStampsSetting:false,useTimeStampsInMilliseconds:null,format:function(){handleError("Layout.format: layout supplied has no format() method");},ignoresThrowable:function(){handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");},getContentType:function(){return"text/plain";},allowBatching:function(){return true;},setTimeStampsInMilliseconds:function(timeStampsInMilliseconds){this.overrideTimeStampsSetting=true;this.useTimeStampsInMilliseconds=bool(timeStampsInMilliseconds);},isTimeStampsInMilliseconds:function(){return this.overrideTimeStampsSetting?this.useTimeStampsInMilliseconds:useTimeStampsInMilliseconds;},getTimeStampValue:function(loggingEvent){return this.isTimeStampsInMilliseconds()?loggingEvent.timeStampInMilliseconds:loggingEvent.timeStampInSeconds;},getDataValues:function(loggingEvent,combineMessages){var dataValues=[[this.loggerKey,loggingEvent.logger.name],[this.timeStampKey,this.getTimeStampValue(loggingEvent)],[this.levelKey,loggingEvent.level.name],[this.urlKey,window.location.href],[this.messageKey,combineMessages?loggingEvent.getCombinedMessages():loggingEvent.messages]];if(!this.isTimeStampsInMilliseconds()){dataValues.push([this.millisecondsKey,loggingEvent.milliseconds]);}

+if(loggingEvent.exception){dataValues.push([this.exceptionKey,getExceptionStringRep(loggingEvent.exception)]);}

+if(this.hasCustomFields()){for(var i=0,len=this.customFields.length;i<len;i++){var val=this.customFields[i].value;if(typeof val==="function"){val=val(this,loggingEvent);}

+dataValues.push([this.customFields[i].name,val]);}}

+return dataValues;},setKeys:function(loggerKey,timeStampKey,levelKey,messageKey,exceptionKey,urlKey,millisecondsKey){this.loggerKey=extractStringFromParam(loggerKey,this.defaults.loggerKey);this.timeStampKey=extractStringFromParam(timeStampKey,this.defaults.timeStampKey);this.levelKey=extractStringFromParam(levelKey,this.defaults.levelKey);this.messageKey=extractStringFromParam(messageKey,this.defaults.messageKey);this.exceptionKey=extractStringFromParam(exceptionKey,this.defaults.exceptionKey);this.urlKey=extractStringFromParam(urlKey,this.defaults.urlKey);this.millisecondsKey=extractStringFromParam(millisecondsKey,this.defaults.millisecondsKey);},setCustomField:function(name,value){var fieldUpdated=false;for(var i=0,len=this.customFields.length;i<len;i++){if(this.customFields[i].name===name){this.customFields[i].value=value;fieldUpdated=true;}}

+if(!fieldUpdated){this.customFields.push({"name":name,"value":value});}},hasCustomFields:function(){return(this.customFields.length>0);},toString:function(){handleError("Layout.toString: all layouts must override this method");}};log4javascript.Layout=Layout;var Appender=function(){};Appender.prototype=new EventSupport();Appender.prototype.layout=new PatternLayout();Appender.prototype.threshold=Level.ALL;Appender.prototype.loggers=[];Appender.prototype.doAppend=function(loggingEvent){if(enabled&&loggingEvent.level.level>=this.threshold.level){this.append(loggingEvent);}};Appender.prototype.append=function(loggingEvent){};Appender.prototype.setLayout=function(layout){if(layout instanceof Layout){this.layout=layout;}else{handleError("Appender.setLayout: layout supplied to "+

+this.toString()+" is not a subclass of Layout");}};Appender.prototype.getLayout=function(){return this.layout;};Appender.prototype.setThreshold=function(threshold){if(threshold instanceof Level){this.threshold=threshold;}else{handleError("Appender.setThreshold: threshold supplied to "+

+this.toString()+" is not a subclass of Level");}};Appender.prototype.getThreshold=function(){return this.threshold;};Appender.prototype.setAddedToLogger=function(logger){this.loggers.push(logger);};Appender.prototype.setRemovedFromLogger=function(logger){array_remove(this.loggers,logger);};Appender.prototype.group=emptyFunction;Appender.prototype.groupEnd=emptyFunction;Appender.prototype.toString=function(){handleError("Appender.toString: all appenders must override this method");};log4javascript.Appender=Appender;function SimpleLayout(){this.customFields=[];}

+SimpleLayout.prototype=new Layout();SimpleLayout.prototype.format=function(loggingEvent){return loggingEvent.level.name+" - "+loggingEvent.getCombinedMessages();};SimpleLayout.prototype.ignoresThrowable=function(){return true;};SimpleLayout.prototype.toString=function(){return"SimpleLayout";};log4javascript.SimpleLayout=SimpleLayout;function NullLayout(){this.customFields=[];}

+NullLayout.prototype=new Layout();NullLayout.prototype.format=function(loggingEvent){return loggingEvent.messages;};NullLayout.prototype.ignoresThrowable=function(){return true;};NullLayout.prototype.toString=function(){return"NullLayout";};log4javascript.NullLayout=NullLayout;function XmlLayout(combineMessages){this.combineMessages=extractBooleanFromParam(combineMessages,true);this.customFields=[];}

+XmlLayout.prototype=new Layout();XmlLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};XmlLayout.prototype.getContentType=function(){return"text/xml";};XmlLayout.prototype.escapeCdata=function(str){return str.replace(/\]\]>/,"]]>]]&gt;<![CDATA[");};XmlLayout.prototype.format=function(loggingEvent){var layout=this;var i,len;function formatMessage(message){message=(typeof message==="string")?message:toStr(message);return"<log4javascript:message><![CDATA["+

+layout.escapeCdata(message)+"]]></log4javascript:message>";}

+var str="<log4javascript:event logger=\""+loggingEvent.logger.name+"\" timestamp=\""+this.getTimeStampValue(loggingEvent)+"\"";if(!this.isTimeStampsInMilliseconds()){str+=" milliseconds=\""+loggingEvent.milliseconds+"\"";}

+str+=" level=\""+loggingEvent.level.name+"\">"+newLine;if(this.combineMessages){str+=formatMessage(loggingEvent.getCombinedMessages());}else{str+="<log4javascript:messages>"+newLine;for(i=0,len=loggingEvent.messages.length;i<len;i++){str+=formatMessage(loggingEvent.messages[i])+newLine;}

+str+="</log4javascript:messages>"+newLine;}

+if(this.hasCustomFields()){for(i=0,len=this.customFields.length;i<len;i++){str+="<log4javascript:customfield name=\""+

+this.customFields[i].name+"\"><![CDATA["+

+this.customFields[i].value.toString()+"]]></log4javascript:customfield>"+newLine;}}

+if(loggingEvent.exception){str+="<log4javascript:exception><![CDATA["+

+getExceptionStringRep(loggingEvent.exception)+"]]></log4javascript:exception>"+newLine;}

+str+="</log4javascript:event>"+newLine+newLine;return str;};XmlLayout.prototype.ignoresThrowable=function(){return false;};XmlLayout.prototype.toString=function(){return"XmlLayout";};log4javascript.XmlLayout=XmlLayout;function escapeNewLines(str){return str.replace(/\r\n|\r|\n/g,"\\r\\n");}

+function JsonLayout(readable,combineMessages){this.readable=extractBooleanFromParam(readable,false);this.combineMessages=extractBooleanFromParam(combineMessages,true);this.batchHeader=this.readable?"["+newLine:"[";this.batchFooter=this.readable?"]"+newLine:"]";this.batchSeparator=this.readable?","+newLine:",";this.setKeys();this.colon=this.readable?": ":":";this.tab=this.readable?"\t":"";this.lineBreak=this.readable?newLine:"";this.customFields=[];}

+JsonLayout.prototype=new Layout();JsonLayout.prototype.isReadable=function(){return this.readable;};JsonLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};JsonLayout.prototype.format=function(loggingEvent){var layout=this;var dataValues=this.getDataValues(loggingEvent,this.combineMessages);var str="{"+this.lineBreak;var i,len;function formatValue(val,prefix,expand){var formattedValue;var valType=typeof val;if(val instanceof Date){formattedValue=String(val.getTime());}else if(expand&&(val instanceof Array)){formattedValue="["+layout.lineBreak;for(var i=0,len=val.length;i<len;i++){var childPrefix=prefix+layout.tab;formattedValue+=childPrefix+formatValue(val[i],childPrefix,false);if(i<val.length-1){formattedValue+=",";}

+formattedValue+=layout.lineBreak;}

+formattedValue+=prefix+"]";}else if(valType!=="number"&&valType!=="boolean"){formattedValue="\""+escapeNewLines(toStr(val).replace(/\"/g,"\\\""))+"\"";}else{formattedValue=val;}

+return formattedValue;}

+for(i=0,len=dataValues.length-1;i<=len;i++){str+=this.tab+"\""+dataValues[i][0]+"\""+this.colon+formatValue(dataValues[i][1],this.tab,true);if(i<len){str+=",";}

+str+=this.lineBreak;}

+str+="}"+this.lineBreak;return str;};JsonLayout.prototype.ignoresThrowable=function(){return false;};JsonLayout.prototype.toString=function(){return"JsonLayout";};JsonLayout.prototype.getContentType=function(){return"application/json";};log4javascript.JsonLayout=JsonLayout;function HttpPostDataLayout(){this.setKeys();this.customFields=[];this.returnsPostData=true;}

+HttpPostDataLayout.prototype=new Layout();HttpPostDataLayout.prototype.allowBatching=function(){return false;};HttpPostDataLayout.prototype.format=function(loggingEvent){var dataValues=this.getDataValues(loggingEvent);var queryBits=[];for(var i=0,len=dataValues.length;i<len;i++){var val=(dataValues[i][1]instanceof Date)?String(dataValues[i][1].getTime()):dataValues[i][1];queryBits.push(urlEncode(dataValues[i][0])+"="+urlEncode(val));}

+return queryBits.join("&");};HttpPostDataLayout.prototype.ignoresThrowable=function(loggingEvent){return false;};HttpPostDataLayout.prototype.toString=function(){return"HttpPostDataLayout";};log4javascript.HttpPostDataLayout=HttpPostDataLayout;function formatObjectExpansion(obj,depth,indentation){var objectsExpanded=[];function doFormat(obj,depth,indentation){var i,j,len,childDepth,childIndentation,childLines,expansion,childExpansion;if(!indentation){indentation="";}

+function formatString(text){var lines=splitIntoLines(text);for(var j=1,jLen=lines.length;j<jLen;j++){lines[j]=indentation+lines[j];}

+return lines.join(newLine);}

+if(obj===null){return"null";}else if(typeof obj=="undefined"){return"undefined";}else if(typeof obj=="string"){return formatString(obj);}else if(typeof obj=="object"&&array_contains(objectsExpanded,obj)){try{expansion=toStr(obj);}catch(ex){expansion="Error formatting property. Details: "+getExceptionStringRep(ex);}

+return expansion+" [already expanded]";}else if((obj instanceof Array)&&depth>0){objectsExpanded.push(obj);expansion="["+newLine;childDepth=depth-1;childIndentation=indentation+"  ";childLines=[];for(i=0,len=obj.length;i<len;i++){try{childExpansion=doFormat(obj[i],childDepth,childIndentation);childLines.push(childIndentation+childExpansion);}catch(ex){childLines.push(childIndentation+"Error formatting array member. Details: "+

+getExceptionStringRep(ex)+"");}}

+expansion+=childLines.join(","+newLine)+newLine+indentation+"]";return expansion;}else if(Object.prototype.toString.call(obj)=="[object Date]"){return obj.toString();}else if(typeof obj=="object"&&depth>0){objectsExpanded.push(obj);expansion="{"+newLine;childDepth=depth-1;childIndentation=indentation+"  ";childLines=[];for(i in obj){try{childExpansion=doFormat(obj[i],childDepth,childIndentation);childLines.push(childIndentation+i+": "+childExpansion);}catch(ex){childLines.push(childIndentation+i+": Error formatting property. Details: "+

+getExceptionStringRep(ex));}}

+expansion+=childLines.join(","+newLine)+newLine+indentation+"}";return expansion;}else{return formatString(toStr(obj));}}

+return doFormat(obj,depth,indentation);}

+var SimpleDateFormat;(function(){var regex=/('[^']*')|(G+|y+|M+|w+|W+|D+|d+|F+|E+|a+|H+|k+|K+|h+|m+|s+|S+|Z+)|([a-zA-Z]+)|([^a-zA-Z']+)/;var monthNames=["January","February","March","April","May","June","July","August","September","October","November","December"];var dayNames=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var TEXT2=0,TEXT3=1,NUMBER=2,YEAR=3,MONTH=4,TIMEZONE=5;var types={G:TEXT2,y:YEAR,M:MONTH,w:NUMBER,W:NUMBER,D:NUMBER,d:NUMBER,F:NUMBER,E:TEXT3,a:TEXT2,H:NUMBER,k:NUMBER,K:NUMBER,h:NUMBER,m:NUMBER,s:NUMBER,S:NUMBER,Z:TIMEZONE};var ONE_DAY=24*60*60*1000;var ONE_WEEK=7*ONE_DAY;var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK=1;var newDateAtMidnight=function(year,month,day){var d=new Date(year,month,day,0,0,0);d.setMilliseconds(0);return d;};Date.prototype.getDifference=function(date){return this.getTime()-date.getTime();};Date.prototype.isBefore=function(d){return this.getTime()<d.getTime();};Date.prototype.getUTCTime=function(){return Date.UTC(this.getFullYear(),this.getMonth(),this.getDate(),this.getHours(),this.getMinutes(),this.getSeconds(),this.getMilliseconds());};Date.prototype.getTimeSince=function(d){return this.getUTCTime()-d.getUTCTime();};Date.prototype.getPreviousSunday=function(){var midday=new Date(this.getFullYear(),this.getMonth(),this.getDate(),12,0,0);var previousSunday=new Date(midday.getTime()-this.getDay()*ONE_DAY);return newDateAtMidnight(previousSunday.getFullYear(),previousSunday.getMonth(),previousSunday.getDate());};Date.prototype.getWeekInYear=function(minimalDaysInFirstWeek){if(isUndefined(this.minimalDaysInFirstWeek)){minimalDaysInFirstWeek=DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;}

+var previousSunday=this.getPreviousSunday();var startOfYear=newDateAtMidnight(this.getFullYear(),0,1);var numberOfSundays=previousSunday.isBefore(startOfYear)?0:1+Math.floor(previousSunday.getTimeSince(startOfYear)/ONE_WEEK);var numberOfDaysInFirstWeek=7-startOfYear.getDay();var weekInYear=numberOfSundays;if(numberOfDaysInFirstWeek<minimalDaysInFirstWeek){weekInYear--;}

+return weekInYear;};Date.prototype.getWeekInMonth=function(minimalDaysInFirstWeek){if(isUndefined(this.minimalDaysInFirstWeek)){minimalDaysInFirstWeek=DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;}

+var previousSunday=this.getPreviousSunday();var startOfMonth=newDateAtMidnight(this.getFullYear(),this.getMonth(),1);var numberOfSundays=previousSunday.isBefore(startOfMonth)?0:1+Math.floor(previousSunday.getTimeSince(startOfMonth)/ONE_WEEK);var numberOfDaysInFirstWeek=7-startOfMonth.getDay();var weekInMonth=numberOfSundays;if(numberOfDaysInFirstWeek>=minimalDaysInFirstWeek){weekInMonth++;}

+return weekInMonth;};Date.prototype.getDayInYear=function(){var startOfYear=newDateAtMidnight(this.getFullYear(),0,1);return 1+Math.floor(this.getTimeSince(startOfYear)/ONE_DAY);};SimpleDateFormat=function(formatString){this.formatString=formatString;};SimpleDateFormat.prototype.setMinimalDaysInFirstWeek=function(days){this.minimalDaysInFirstWeek=days;};SimpleDateFormat.prototype.getMinimalDaysInFirstWeek=function(){return isUndefined(this.minimalDaysInFirstWeek)?DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK:this.minimalDaysInFirstWeek;};var padWithZeroes=function(str,len){while(str.length<len){str="0"+str;}

+return str;};var formatText=function(data,numberOfLetters,minLength){return(numberOfLetters>=4)?data:data.substr(0,Math.max(minLength,numberOfLetters));};var formatNumber=function(data,numberOfLetters){var dataString=""+data;return padWithZeroes(dataString,numberOfLetters);};SimpleDateFormat.prototype.format=function(date){var formattedString="";var result;var searchString=this.formatString;while((result=regex.exec(searchString))){var quotedString=result[1];var patternLetters=result[2];var otherLetters=result[3];var otherCharacters=result[4];if(quotedString){if(quotedString=="''"){formattedString+="'";}else{formattedString+=quotedString.substring(1,quotedString.length-1);}}else if(otherLetters){}else if(otherCharacters){formattedString+=otherCharacters;}else if(patternLetters){var patternLetter=patternLetters.charAt(0);var numberOfLetters=patternLetters.length;var rawData="";switch(patternLetter){case"G":rawData="AD";break;case"y":rawData=date.getFullYear();break;case"M":rawData=date.getMonth();break;case"w":rawData=date.getWeekInYear(this.getMinimalDaysInFirstWeek());break;case"W":rawData=date.getWeekInMonth(this.getMinimalDaysInFirstWeek());break;case"D":rawData=date.getDayInYear();break;case"d":rawData=date.getDate();break;case"F":rawData=1+Math.floor((date.getDate()-1)/7);break;case"E":rawData=dayNames[date.getDay()];break;case"a":rawData=(date.getHours()>=12)?"PM":"AM";break;case"H":rawData=date.getHours();break;case"k":rawData=date.getHours()||24;break;case"K":rawData=date.getHours()%12;break;case"h":rawData=(date.getHours()%12)||12;break;case"m":rawData=date.getMinutes();break;case"s":rawData=date.getSeconds();break;case"S":rawData=date.getMilliseconds();break;case"Z":rawData=date.getTimezoneOffset();break;}

+switch(types[patternLetter]){case TEXT2:formattedString+=formatText(rawData,numberOfLetters,2);break;case TEXT3:formattedString+=formatText(rawData,numberOfLetters,3);break;case NUMBER:formattedString+=formatNumber(rawData,numberOfLetters);break;case YEAR:if(numberOfLetters<=3){var dataString=""+rawData;formattedString+=dataString.substr(2,2);}else{formattedString+=formatNumber(rawData,numberOfLetters);}

+break;case MONTH:if(numberOfLetters>=3){formattedString+=formatText(monthNames[rawData],numberOfLetters,numberOfLetters);}else{formattedString+=formatNumber(rawData+1,numberOfLetters);}

+break;case TIMEZONE:var isPositive=(rawData>0);var prefix=isPositive?"-":"+";var absData=Math.abs(rawData);var hours=""+Math.floor(absData/60);hours=padWithZeroes(hours,2);var minutes=""+(absData%60);minutes=padWithZeroes(minutes,2);formattedString+=prefix+hours+minutes;break;}}

+searchString=searchString.substr(result.index+result[0].length);}

+return formattedString;};})();log4javascript.SimpleDateFormat=SimpleDateFormat;function PatternLayout(pattern){if(pattern){this.pattern=pattern;}else{this.pattern=PatternLayout.DEFAULT_CONVERSION_PATTERN;}

+this.customFields=[];}

+PatternLayout.TTCC_CONVERSION_PATTERN="%r %p %c - %m%n";PatternLayout.DEFAULT_CONVERSION_PATTERN="%m%n";PatternLayout.ISO8601_DATEFORMAT="yyyy-MM-dd HH:mm:ss,SSS";PatternLayout.DATETIME_DATEFORMAT="dd MMM yyyy HH:mm:ss,SSS";PatternLayout.ABSOLUTETIME_DATEFORMAT="HH:mm:ss,SSS";PatternLayout.prototype=new Layout();PatternLayout.prototype.format=function(loggingEvent){var regex=/%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;var formattedString="";var result;var searchString=this.pattern;while((result=regex.exec(searchString))){var matchedString=result[0];var padding=result[1];var truncation=result[2];var conversionCharacter=result[3];var specifier=result[5];var text=result[6];if(text){formattedString+=""+text;}else{var replacement="";switch(conversionCharacter){case"a":case"m":var depth=0;if(specifier){depth=parseInt(specifier,10);if(isNaN(depth)){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character '"+conversionCharacter+"' - should be a number");depth=0;}}

+var messages=(conversionCharacter==="a")?loggingEvent.messages[0]:loggingEvent.messages;for(var i=0,len=messages.length;i<len;i++){if(i>0&&(replacement.charAt(replacement.length-1)!==" ")){replacement+=" ";}

+if(depth===0){replacement+=messages[i];}else{replacement+=formatObjectExpansion(messages[i],depth);}}

+break;case"c":var loggerName=loggingEvent.logger.name;if(specifier){var precision=parseInt(specifier,10);var loggerNameBits=loggingEvent.logger.name.split(".");if(precision>=loggerNameBits.length){replacement=loggerName;}else{replacement=loggerNameBits.slice(loggerNameBits.length-precision).join(".");}}else{replacement=loggerName;}

+break;case"d":var dateFormat=PatternLayout.ISO8601_DATEFORMAT;if(specifier){dateFormat=specifier;if(dateFormat=="ISO8601"){dateFormat=PatternLayout.ISO8601_DATEFORMAT;}else if(dateFormat=="ABSOLUTE"){dateFormat=PatternLayout.ABSOLUTETIME_DATEFORMAT;}else if(dateFormat=="DATE"){dateFormat=PatternLayout.DATETIME_DATEFORMAT;}}

+replacement=(new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);break;case"f":if(this.hasCustomFields()){var fieldIndex=0;if(specifier){fieldIndex=parseInt(specifier,10);if(isNaN(fieldIndex)){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - should be a number");}else if(fieldIndex===0){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - must be greater than zero");}else if(fieldIndex>this.customFields.length){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - there aren't that many custom fields");}else{fieldIndex=fieldIndex-1;}}

+var val=this.customFields[fieldIndex].value;if(typeof val=="function"){val=val(this,loggingEvent);}

+replacement=val;}

+break;case"n":replacement=newLine;break;case"p":replacement=loggingEvent.level.name;break;case"r":replacement=""+loggingEvent.timeStamp.getDifference(applicationStartDate);break;case"%":replacement="%";break;default:replacement=matchedString;break;}

+var l;if(truncation){l=parseInt(truncation.substr(1),10);var strLen=replacement.length;if(l<strLen){replacement=replacement.substring(strLen-l,strLen);}}

+if(padding){if(padding.charAt(0)=="-"){l=parseInt(padding.substr(1),10);while(replacement.length<l){replacement+=" ";}}else{l=parseInt(padding,10);while(replacement.length<l){replacement=" "+replacement;}}}

+formattedString+=replacement;}

+searchString=searchString.substr(result.index+result[0].length);}

+return formattedString;};PatternLayout.prototype.ignoresThrowable=function(){return true;};PatternLayout.prototype.toString=function(){return"PatternLayout";};log4javascript.PatternLayout=PatternLayout;function AlertAppender(){}

+AlertAppender.prototype=new Appender();AlertAppender.prototype.layout=new SimpleLayout();AlertAppender.prototype.append=function(loggingEvent){var formattedMessage=this.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();}

+alert(formattedMessage);};AlertAppender.prototype.toString=function(){return"AlertAppender";};log4javascript.AlertAppender=AlertAppender;function BrowserConsoleAppender(){}

+BrowserConsoleAppender.prototype=new log4javascript.Appender();BrowserConsoleAppender.prototype.layout=new NullLayout();BrowserConsoleAppender.prototype.threshold=Level.DEBUG;BrowserConsoleAppender.prototype.append=function(loggingEvent){var appender=this;var getFormattedMessage=function(){var layout=appender.getLayout();var formattedMessage=layout.format(loggingEvent);if(layout.ignoresThrowable()&&loggingEvent.exception){formattedMessage+=loggingEvent.getThrowableStrRep();}

+return formattedMessage;};if((typeof opera!="undefined")&&opera.postError){opera.postError(getFormattedMessage());}else if(window.console&&window.console.log){var formattedMesage=getFormattedMessage();if(window.console.debug&&Level.DEBUG.isGreaterOrEqual(loggingEvent.level)){window.console.debug(formattedMesage);}else if(window.console.info&&Level.INFO.equals(loggingEvent.level)){window.console.info(formattedMesage);}else if(window.console.warn&&Level.WARN.equals(loggingEvent.level)){window.console.warn(formattedMesage);}else if(window.console.error&&loggingEvent.level.isGreaterOrEqual(Level.ERROR)){window.console.error(formattedMesage);}else{window.console.log(formattedMesage);}}};BrowserConsoleAppender.prototype.group=function(name){if(window.console&&window.console.group){window.console.group(name);}};BrowserConsoleAppender.prototype.groupEnd=function(){if(window.console&&window.console.groupEnd){window.console.groupEnd();}};BrowserConsoleAppender.prototype.toString=function(){return"BrowserConsoleAppender";};log4javascript.BrowserConsoleAppender=BrowserConsoleAppender;var xmlHttpFactories=[function(){return new XMLHttpRequest();},function(){return new ActiveXObject("Msxml2.XMLHTTP");},function(){return new ActiveXObject("Microsoft.XMLHTTP");}];var getXmlHttp=function(errorHandler){var xmlHttp=null,factory;for(var i=0,len=xmlHttpFactories.length;i<len;i++){factory=xmlHttpFactories[i];try{xmlHttp=factory();getXmlHttp=factory;return xmlHttp;}catch(e){}}

+if(errorHandler){errorHandler();}else{handleError("getXmlHttp: unable to obtain XMLHttpRequest object");}};function isHttpRequestSuccessful(xmlHttp){return isUndefined(xmlHttp.status)||xmlHttp.status===0||(xmlHttp.status>=200&&xmlHttp.status<300)||xmlHttp.status==1223;}

+function AjaxAppender(url){var appender=this;var isSupported=true;if(!url){handleError("AjaxAppender: URL must be specified in constructor");isSupported=false;}

+var timed=this.defaults.timed;var waitForResponse=this.defaults.waitForResponse;var batchSize=this.defaults.batchSize;var timerInterval=this.defaults.timerInterval;var requestSuccessCallback=this.defaults.requestSuccessCallback;var failCallback=this.defaults.failCallback;var postVarName=this.defaults.postVarName;var sendAllOnUnload=this.defaults.sendAllOnUnload;var contentType=this.defaults.contentType;var sessionId=null;var queuedLoggingEvents=[];var queuedRequests=[];var headers=[];var sending=false;var initialized=false;function checkCanConfigure(configOptionName){if(initialized){handleError("AjaxAppender: configuration option '"+

+configOptionName+"' may not be set after the appender has been initialized");return false;}

+return true;}

+this.getSessionId=function(){return sessionId;};this.setSessionId=function(sessionIdParam){sessionId=extractStringFromParam(sessionIdParam,null);this.layout.setCustomField("sessionid",sessionId);};this.setLayout=function(layoutParam){if(checkCanConfigure("layout")){this.layout=layoutParam;if(sessionId!==null){this.setSessionId(sessionId);}}};this.isTimed=function(){return timed;};this.setTimed=function(timedParam){if(checkCanConfigure("timed")){timed=bool(timedParam);}};this.getTimerInterval=function(){return timerInterval;};this.setTimerInterval=function(timerIntervalParam){if(checkCanConfigure("timerInterval")){timerInterval=extractIntFromParam(timerIntervalParam,timerInterval);}};this.isWaitForResponse=function(){return waitForResponse;};this.setWaitForResponse=function(waitForResponseParam){if(checkCanConfigure("waitForResponse")){waitForResponse=bool(waitForResponseParam);}};this.getBatchSize=function(){return batchSize;};this.setBatchSize=function(batchSizeParam){if(checkCanConfigure("batchSize")){batchSize=extractIntFromParam(batchSizeParam,batchSize);}};this.isSendAllOnUnload=function(){return sendAllOnUnload;};this.setSendAllOnUnload=function(sendAllOnUnloadParam){if(checkCanConfigure("sendAllOnUnload")){sendAllOnUnload=extractBooleanFromParam(sendAllOnUnloadParam,sendAllOnUnload);}};this.setRequestSuccessCallback=function(requestSuccessCallbackParam){requestSuccessCallback=extractFunctionFromParam(requestSuccessCallbackParam,requestSuccessCallback);};this.setFailCallback=function(failCallbackParam){failCallback=extractFunctionFromParam(failCallbackParam,failCallback);};this.getPostVarName=function(){return postVarName;};this.setPostVarName=function(postVarNameParam){if(checkCanConfigure("postVarName")){postVarName=extractStringFromParam(postVarNameParam,postVarName);}};this.getHeaders=function(){return headers;};this.addHeader=function(name,value){if(name.toLowerCase()=="content-type"){contentType=value;}else{headers.push({name:name,value:value});}};function sendAll(){if(isSupported&&enabled){sending=true;var currentRequestBatch;if(waitForResponse){if(queuedRequests.length>0){currentRequestBatch=queuedRequests.shift();sendRequest(preparePostData(currentRequestBatch),sendAll);}else{sending=false;if(timed){scheduleSending();}}}else{while((currentRequestBatch=queuedRequests.shift())){sendRequest(preparePostData(currentRequestBatch));}

+sending=false;if(timed){scheduleSending();}}}}

+this.sendAll=sendAll;function sendAllRemaining(){var sendingAnything=false;if(isSupported&&enabled){var actualBatchSize=appender.getLayout().allowBatching()?batchSize:1;var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);if(queuedLoggingEvents.length>=actualBatchSize){queuedRequests.push(batchedLoggingEvents);batchedLoggingEvents=[];}}

+if(batchedLoggingEvents.length>0){queuedRequests.push(batchedLoggingEvents);}

+sendingAnything=(queuedRequests.length>0);waitForResponse=false;timed=false;sendAll();}

+return sendingAnything;}

+this.sendAllRemaining=sendAllRemaining;function preparePostData(batchedLoggingEvents){var formattedMessages=[];var currentLoggingEvent;var postData="";while((currentLoggingEvent=batchedLoggingEvents.shift())){var currentFormattedMessage=appender.getLayout().format(currentLoggingEvent);if(appender.getLayout().ignoresThrowable()){currentFormattedMessage+=currentLoggingEvent.getThrowableStrRep();}

+formattedMessages.push(currentFormattedMessage);}

+if(batchedLoggingEvents.length==1){postData=formattedMessages.join("");}else{postData=appender.getLayout().batchHeader+

+formattedMessages.join(appender.getLayout().batchSeparator)+

+appender.getLayout().batchFooter;}

+if(contentType==appender.defaults.contentType){postData=appender.getLayout().returnsPostData?postData:urlEncode(postVarName)+"="+urlEncode(postData);if(postData.length>0){postData+="&";}

+postData+="layout="+urlEncode(appender.getLayout().toString());}

+return postData;}

+function scheduleSending(){window.setTimeout(sendAll,timerInterval);}

+function xmlHttpErrorHandler(){var msg="AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}}

+function sendRequest(postData,successCallback){try{var xmlHttp=getXmlHttp(xmlHttpErrorHandler);if(isSupported){if(xmlHttp.overrideMimeType){xmlHttp.overrideMimeType(appender.getLayout().getContentType());}

+xmlHttp.onreadystatechange=function(){if(xmlHttp.readyState==4){if(isHttpRequestSuccessful(xmlHttp)){if(requestSuccessCallback){requestSuccessCallback(xmlHttp);}

+if(successCallback){successCallback(xmlHttp);}}else{var msg="AjaxAppender.append: XMLHttpRequest request to URL "+

+url+" returned status code "+xmlHttp.status;handleError(msg);if(failCallback){failCallback(msg);}}

+xmlHttp.onreadystatechange=emptyFunction;xmlHttp=null;}};xmlHttp.open("POST",url,true);try{for(var i=0,header;header=headers[i++];){xmlHttp.setRequestHeader(header.name,header.value);}

+xmlHttp.setRequestHeader("Content-Type",contentType);}catch(headerEx){var msg="AjaxAppender.append: your browser's XMLHttpRequest implementation"+" does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}

+return;}

+xmlHttp.send(postData);}}catch(ex){var errMsg="AjaxAppender.append: error sending log message to "+url;handleError(errMsg,ex);isSupported=false;if(failCallback){failCallback(errMsg+". Details: "+getExceptionStringRep(ex));}}}

+this.append=function(loggingEvent){if(isSupported){if(!initialized){init();}

+queuedLoggingEvents.push(loggingEvent);var actualBatchSize=this.getLayout().allowBatching()?batchSize:1;if(queuedLoggingEvents.length>=actualBatchSize){var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);}

+queuedRequests.push(batchedLoggingEvents);if(!timed&&(!waitForResponse||(waitForResponse&&!sending))){sendAll();}}}};function init(){initialized=true;if(sendAllOnUnload){var oldBeforeUnload=window.onbeforeunload;window.onbeforeunload=function(){if(oldBeforeUnload){oldBeforeUnload();}

+if(sendAllRemaining()){return"Sending log messages";}};}

+if(timed){scheduleSending();}}}

+AjaxAppender.prototype=new Appender();AjaxAppender.prototype.defaults={waitForResponse:false,timed:false,timerInterval:1000,batchSize:1,sendAllOnUnload:false,requestSuccessCallback:null,failCallback:null,postVarName:"data",contentType:"application/x-www-form-urlencoded"};AjaxAppender.prototype.layout=new HttpPostDataLayout();AjaxAppender.prototype.toString=function(){return"AjaxAppender";};log4javascript.AjaxAppender=AjaxAppender;function setCookie(name,value,days,path){var expires;path=path?"; path="+path:"";if(days){var date=new Date();date.setTime(date.getTime()+(days*24*60*60*1000));expires="; expires="+date.toGMTString();}else{expires="";}

+document.cookie=escape(name)+"="+escape(value)+expires+path;}

+function getCookie(name){var nameEquals=escape(name)+"=";var ca=document.cookie.split(";");for(var i=0,len=ca.length;i<len;i++){var c=ca[i];while(c.charAt(0)===" "){c=c.substring(1,c.length);}

+if(c.indexOf(nameEquals)===0){return unescape(c.substring(nameEquals.length,c.length));}}

+return null;}

+function getBaseUrl(){var scripts=document.getElementsByTagName("script");for(var i=0,len=scripts.length;i<len;++i){if(scripts[i].src.indexOf("log4javascript")!=-1){var lastSlash=scripts[i].src.lastIndexOf("/");return(lastSlash==-1)?"":scripts[i].src.substr(0,lastSlash+1);}}

+return null;}

+function isLoaded(win){try{return bool(win.loaded);}catch(ex){return false;}}

+var ConsoleAppender;(function(){var getConsoleHtmlLines=function(){return['<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">','<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">','<head>','<title>log4javascript</title>','<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />','<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->','<meta http-equiv="X-UA-Compatible" content="IE=7" />','<script type="text/javascript">var isIe = false, isIePre7 = false;</script>','<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->','<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->','<script type="text/javascript">','//<![CDATA[','var loggingEnabled=true;var logQueuedEventsTimer=null;var logEntries=[];var logEntriesAndSeparators=[];var logItems=[];var renderDelay=100;var unrenderedLogItemsExist=false;var rootGroup,currentGroup=null;var loaded=false;var currentLogItem=null;var logMainContainer;function copyProperties(obj,props){for(var i in props){obj[i]=props[i];}}','function LogItem(){}','LogItem.prototype={mainContainer:null,wrappedContainer:null,unwrappedContainer:null,group:null,appendToLog:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].appendToLog();}','this.group.update();},doRemove:function(doUpdate,removeFromGroup){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].remove();}','this.unwrappedElementContainer=null;this.wrappedElementContainer=null;this.mainElementContainer=null;}','if(this.group&&removeFromGroup){this.group.removeChild(this,doUpdate);}','if(this===currentLogItem){currentLogItem=null;}},remove:function(doUpdate,removeFromGroup){this.doRemove(doUpdate,removeFromGroup);},render:function(){},accept:function(visitor){visitor.visit(this);},getUnwrappedDomContainer:function(){return this.group.unwrappedElementContainer.contentDiv;},getWrappedDomContainer:function(){return this.group.wrappedElementContainer.contentDiv;},getMainDomContainer:function(){return this.group.mainElementContainer.contentDiv;}};LogItem.serializedItemKeys={LOG_ENTRY:0,GROUP_START:1,GROUP_END:2};function LogItemContainerElement(){}','LogItemContainerElement.prototype={appendToLog:function(){var insertBeforeFirst=(newestAtTop&&this.containerDomNode.hasChildNodes());if(insertBeforeFirst){this.containerDomNode.insertBefore(this.mainDiv,this.containerDomNode.firstChild);}else{this.containerDomNode.appendChild(this.mainDiv);}}};function SeparatorElementContainer(containerDomNode){this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="separator";this.mainDiv.innerHTML="&nbsp;";}','SeparatorElementContainer.prototype=new LogItemContainerElement();SeparatorElementContainer.prototype.remove=function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;};function Separator(){this.rendered=false;}','Separator.prototype=new LogItem();copyProperties(Separator.prototype,{render:function(){var containerDomNode=this.group.contentDiv;if(isIe){this.unwrappedElementContainer=new SeparatorElementContainer(this.getUnwrappedDomContainer());this.wrappedElementContainer=new SeparatorElementContainer(this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new SeparatorElementContainer(this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}','this.content=this.formattedMessage;this.rendered=true;}});function GroupElementContainer(group,containerDomNode,isRoot,isWrapped){this.group=group;this.containerDomNode=containerDomNode;this.isRoot=isRoot;this.isWrapped=isWrapped;this.expandable=false;if(this.isRoot){if(isIe){this.contentDiv=logMainContainer.appendChild(document.createElement("div"));this.contentDiv.id=this.isWrapped?"log_wrapped":"log_unwrapped";}else{this.contentDiv=logMainContainer;}}else{var groupElementContainer=this;this.mainDiv=document.createElement("div");this.mainDiv.className="group";this.headingDiv=this.mainDiv.appendChild(document.createElement("div"));this.headingDiv.className="groupheading";this.expander=this.headingDiv.appendChild(document.createElement("span"));this.expander.className="expander unselectable greyedout";this.expander.unselectable=true;var expanderText=this.group.expanded?"-":"+";this.expanderTextNode=this.expander.appendChild(document.createTextNode(expanderText));this.headingDiv.appendChild(document.createTextNode(" "+this.group.name));this.contentDiv=this.mainDiv.appendChild(document.createElement("div"));var contentCssClass=this.group.expanded?"expanded":"collapsed";this.contentDiv.className="groupcontent "+contentCssClass;this.expander.onclick=function(){if(groupElementContainer.group.expandable){groupElementContainer.group.toggleExpanded();}};}}','GroupElementContainer.prototype=new LogItemContainerElement();copyProperties(GroupElementContainer.prototype,{toggleExpanded:function(){if(!this.isRoot){var oldCssClass,newCssClass,expanderText;if(this.group.expanded){newCssClass="expanded";oldCssClass="collapsed";expanderText="-";}else{newCssClass="collapsed";oldCssClass="expanded";expanderText="+";}','replaceClass(this.contentDiv,newCssClass,oldCssClass);this.expanderTextNode.nodeValue=expanderText;}},remove:function(){if(!this.isRoot){this.headingDiv=null;this.expander.onclick=null;this.expander=null;this.expanderTextNode=null;this.contentDiv=null;this.containerDomNode=null;this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;}},reverseChildren:function(){var node=null;var childDomNodes=[];while((node=this.contentDiv.firstChild)){this.contentDiv.removeChild(node);childDomNodes.push(node);}','while((node=childDomNodes.pop())){this.contentDiv.appendChild(node);}},update:function(){if(!this.isRoot){if(this.group.expandable){removeClass(this.expander,"greyedout");}else{addClass(this.expander,"greyedout");}}},clear:function(){if(this.isRoot){this.contentDiv.innerHTML="";}}});function Group(name,isRoot,initiallyExpanded){this.name=name;this.group=null;this.isRoot=isRoot;this.initiallyExpanded=initiallyExpanded;this.elementContainers=[];this.children=[];this.expanded=initiallyExpanded;this.rendered=false;this.expandable=false;}','Group.prototype=new LogItem();copyProperties(Group.prototype,{addChild:function(logItem){this.children.push(logItem);logItem.group=this;},render:function(){if(isIe){var unwrappedDomContainer,wrappedDomContainer;if(this.isRoot){unwrappedDomContainer=logMainContainer;wrappedDomContainer=logMainContainer;}else{unwrappedDomContainer=this.getUnwrappedDomContainer();wrappedDomContainer=this.getWrappedDomContainer();}','this.unwrappedElementContainer=new GroupElementContainer(this,unwrappedDomContainer,this.isRoot,false);this.wrappedElementContainer=new GroupElementContainer(this,wrappedDomContainer,this.isRoot,true);this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{var mainDomContainer=this.isRoot?logMainContainer:this.getMainDomContainer();this.mainElementContainer=new GroupElementContainer(this,mainDomContainer,this.isRoot,false);this.elementContainers=[this.mainElementContainer];}','this.rendered=true;},toggleExpanded:function(){this.expanded=!this.expanded;for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].toggleExpanded();}},expand:function(){if(!this.expanded){this.toggleExpanded();}},accept:function(visitor){visitor.visitGroup(this);},reverseChildren:function(){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].reverseChildren();}}},update:function(){var previouslyExpandable=this.expandable;this.expandable=(this.children.length!==0);if(this.expandable!==previouslyExpandable){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].update();}}},flatten:function(){var visitor=new GroupFlattener();this.accept(visitor);return visitor.logEntriesAndSeparators;},removeChild:function(child,doUpdate){array_remove(this.children,child);child.group=null;if(doUpdate){this.update();}},remove:function(doUpdate,removeFromGroup){for(var i=0,len=this.children.length;i<len;i++){this.children[i].remove(false,false);}','this.children=[];this.update();if(this===currentGroup){currentGroup=this.group;}','this.doRemove(doUpdate,removeFromGroup);},serialize:function(items){items.push([LogItem.serializedItemKeys.GROUP_START,this.name]);for(var i=0,len=this.children.length;i<len;i++){this.children[i].serialize(items);}','if(this!==currentGroup){items.push([LogItem.serializedItemKeys.GROUP_END]);}},clear:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clear();}}});function LogEntryElementContainer(){}','LogEntryElementContainer.prototype=new LogItemContainerElement();copyProperties(LogEntryElementContainer.prototype,{remove:function(){this.doRemove();},doRemove:function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;this.contentElement=null;this.containerDomNode=null;},setContent:function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=content;}},setSearchMatch:function(isMatch){var oldCssClass=isMatch?"searchnonmatch":"searchmatch";var newCssClass=isMatch?"searchmatch":"searchnonmatch";replaceClass(this.mainDiv,newCssClass,oldCssClass);},clearSearch:function(){removeClass(this.mainDiv,"searchmatch");removeClass(this.mainDiv,"searchnonmatch");}});function LogEntryWrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.mainDiv.className="logentry wrapped "+this.logEntry.level;this.contentElement=this.mainDiv;}','LogEntryWrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryWrappedElementContainer.prototype.setContent=function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=wrappedContent;}};function LogEntryUnwrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry unwrapped "+this.logEntry.level;this.pre=this.mainDiv.appendChild(document.createElement("pre"));this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.pre.className="unwrapped";this.contentElement=this.pre;}','LogEntryUnwrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryUnwrappedElementContainer.prototype.remove=function(){this.doRemove();this.pre=null;};function LogEntryMainElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry nonielogentry "+this.logEntry.level;this.contentElement=this.mainDiv.appendChild(document.createElement("span"));this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));}','LogEntryMainElementContainer.prototype=new LogEntryElementContainer();function LogEntry(level,formattedMessage){this.level=level;this.formattedMessage=formattedMessage;this.rendered=false;}','LogEntry.prototype=new LogItem();copyProperties(LogEntry.prototype,{render:function(){var logEntry=this;var containerDomNode=this.group.contentDiv;if(isIe){this.formattedMessage=this.formattedMessage.replace(/\\r\\n/g,"\\r");this.unwrappedElementContainer=new LogEntryUnwrappedElementContainer(this,this.getUnwrappedDomContainer());this.wrappedElementContainer=new LogEntryWrappedElementContainer(this,this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new LogEntryMainElementContainer(this,this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}','this.content=this.formattedMessage;this.rendered=true;},setContent:function(content,wrappedContent){if(content!=this.content){if(isIe&&(content!==this.formattedMessage)){content=content.replace(/\\r\\n/g,"\\r");}','for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setContent(content,wrappedContent);}','this.content=content;}},getSearchMatches:function(){var matches=[];var i,len;if(isIe){var unwrappedEls=getElementsByClass(this.unwrappedElementContainer.mainDiv,"searchterm","span");var wrappedEls=getElementsByClass(this.wrappedElementContainer.mainDiv,"searchterm","span");for(i=0,len=unwrappedEls.length;i<len;i++){matches[i]=new Match(this.level,null,unwrappedEls[i],wrappedEls[i]);}}else{var els=getElementsByClass(this.mainElementContainer.mainDiv,"searchterm","span");for(i=0,len=els.length;i<len;i++){matches[i]=new Match(this.level,els[i]);}}','return matches;},setSearchMatch:function(isMatch){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setSearchMatch(isMatch);}},clearSearch:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clearSearch();}},accept:function(visitor){visitor.visitLogEntry(this);},serialize:function(items){items.push([LogItem.serializedItemKeys.LOG_ENTRY,this.level,this.formattedMessage]);}});function LogItemVisitor(){}','LogItemVisitor.prototype={visit:function(logItem){},visitParent:function(logItem){if(logItem.group){logItem.group.accept(this);}},visitChildren:function(logItem){for(var i=0,len=logItem.children.length;i<len;i++){logItem.children[i].accept(this);}},visitLogEntry:function(logEntry){this.visit(logEntry);},visitSeparator:function(separator){this.visit(separator);},visitGroup:function(group){this.visit(group);}};function GroupFlattener(){this.logEntriesAndSeparators=[];}','GroupFlattener.prototype=new LogItemVisitor();GroupFlattener.prototype.visitGroup=function(group){this.visitChildren(group);};GroupFlattener.prototype.visitLogEntry=function(logEntry){this.logEntriesAndSeparators.push(logEntry);};GroupFlattener.prototype.visitSeparator=function(separator){this.logEntriesAndSeparators.push(separator);};window.onload=function(){if(location.search){var queryBits=unescape(location.search).substr(1).split("&"),nameValueBits;for(var i=0,len=queryBits.length;i<len;i++){nameValueBits=queryBits[i].split("=");if(nameValueBits[0]=="log4javascript_domain"){document.domain=nameValueBits[1];break;}}}','logMainContainer=$("log");if(isIePre7){addClass(logMainContainer,"oldIe");}','rootGroup=new Group("root",true);rootGroup.render();currentGroup=rootGroup;setCommandInputWidth();setLogContainerHeight();toggleLoggingEnabled();toggleSearchEnabled();toggleSearchFilter();toggleSearchHighlight();applyFilters();checkAllLevels();toggleWrap();toggleNewestAtTop();toggleScrollToLatest();renderQueuedLogItems();loaded=true;$("command").value="";$("command").autocomplete="off";$("command").onkeydown=function(evt){evt=getEvent(evt);if(evt.keyCode==10||evt.keyCode==13){evalCommandLine();stopPropagation(evt);}else if(evt.keyCode==27){this.value="";this.focus();}else if(evt.keyCode==38&&commandHistory.length>0){currentCommandIndex=Math.max(0,currentCommandIndex-1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}else if(evt.keyCode==40&&commandHistory.length>0){currentCommandIndex=Math.min(commandHistory.length-1,currentCommandIndex+1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}};$("command").onkeypress=function(evt){evt=getEvent(evt);if(evt.keyCode==38&&commandHistory.length>0&&evt.preventDefault){evt.preventDefault();}};$("command").onkeyup=function(evt){evt=getEvent(evt);if(evt.keyCode==27&&evt.preventDefault){evt.preventDefault();this.focus();}};document.onkeydown=function keyEventHandler(evt){evt=getEvent(evt);switch(evt.keyCode){case 69:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){evalLastCommand();cancelKeyEvent(evt);return false;}','break;case 75:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusSearch();cancelKeyEvent(evt);return false;}','break;case 40:case 76:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusCommandLine();cancelKeyEvent(evt);return false;}','break;}};setTimeout(setLogContainerHeight,20);setShowCommandLine(showCommandLine);doSearch();};window.onunload=function(){if(mainWindowExists()){appender.unload();}','appender=null;};function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}','function setLoggingEnabled(enable){loggingEnabled=enable;}','var appender=null;function setAppender(appenderParam){appender=appenderParam;}','function setShowCloseButton(showCloseButton){$("closeButton").style.display=showCloseButton?"inline":"none";}','function setShowHideButton(showHideButton){$("hideButton").style.display=showHideButton?"inline":"none";}','var newestAtTop=false;function LogItemContentReverser(){}','LogItemContentReverser.prototype=new LogItemVisitor();LogItemContentReverser.prototype.visitGroup=function(group){group.reverseChildren();this.visitChildren(group);};function setNewestAtTop(isNewestAtTop){var oldNewestAtTop=newestAtTop;var i,iLen,j,jLen;newestAtTop=Boolean(isNewestAtTop);if(oldNewestAtTop!=newestAtTop){var visitor=new LogItemContentReverser();rootGroup.accept(visitor);if(currentSearch){var currentMatch=currentSearch.matches[currentMatchIndex];var matchIndex=0;var matches=[];var actOnLogEntry=function(logEntry){var logEntryMatches=logEntry.getSearchMatches();for(j=0,jLen=logEntryMatches.length;j<jLen;j++){matches[matchIndex]=logEntryMatches[j];if(currentMatch&&logEntryMatches[j].equals(currentMatch)){currentMatchIndex=matchIndex;}','matchIndex++;}};if(newestAtTop){for(i=logEntries.length-1;i>=0;i--){actOnLogEntry(logEntries[i]);}}else{for(i=0,iLen=logEntries.length;i<iLen;i++){actOnLogEntry(logEntries[i]);}}','currentSearch.matches=matches;if(currentMatch){currentMatch.setCurrent();}}else if(scrollToLatest){doScrollToLatest();}}','$("newestAtTop").checked=isNewestAtTop;}','function toggleNewestAtTop(){var isNewestAtTop=$("newestAtTop").checked;setNewestAtTop(isNewestAtTop);}','var scrollToLatest=true;function setScrollToLatest(isScrollToLatest){scrollToLatest=isScrollToLatest;if(scrollToLatest){doScrollToLatest();}','$("scrollToLatest").checked=isScrollToLatest;}','function toggleScrollToLatest(){var isScrollToLatest=$("scrollToLatest").checked;setScrollToLatest(isScrollToLatest);}','function doScrollToLatest(){var l=logMainContainer;if(typeof l.scrollTop!="undefined"){if(newestAtTop){l.scrollTop=0;}else{var latestLogEntry=l.lastChild;if(latestLogEntry){l.scrollTop=l.scrollHeight;}}}}','var closeIfOpenerCloses=true;function setCloseIfOpenerCloses(isCloseIfOpenerCloses){closeIfOpenerCloses=isCloseIfOpenerCloses;}','var maxMessages=null;function setMaxMessages(max){maxMessages=max;pruneLogEntries();}','var showCommandLine=false;function setShowCommandLine(isShowCommandLine){showCommandLine=isShowCommandLine;if(loaded){$("commandLine").style.display=showCommandLine?"block":"none";setCommandInputWidth();setLogContainerHeight();}}','function focusCommandLine(){if(loaded){$("command").focus();}}','function focusSearch(){if(loaded){$("searchBox").focus();}}','function getLogItems(){var items=[];for(var i=0,len=logItems.length;i<len;i++){logItems[i].serialize(items);}','return items;}','function setLogItems(items){var loggingReallyEnabled=loggingEnabled;loggingEnabled=true;for(var i=0,len=items.length;i<len;i++){switch(items[i][0]){case LogItem.serializedItemKeys.LOG_ENTRY:log(items[i][1],items[i][2]);break;case LogItem.serializedItemKeys.GROUP_START:group(items[i][1]);break;case LogItem.serializedItemKeys.GROUP_END:groupEnd();break;}}','loggingEnabled=loggingReallyEnabled;}','function log(logLevel,formattedMessage){if(loggingEnabled){var logEntry=new LogEntry(logLevel,formattedMessage);logEntries.push(logEntry);logEntriesAndSeparators.push(logEntry);logItems.push(logEntry);currentGroup.addChild(logEntry);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}','logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}','function renderQueuedLogItems(){logQueuedEventsTimer=null;var pruned=pruneLogEntries();var initiallyHasMatches=currentSearch?currentSearch.hasMatches():false;for(var i=0,len=logItems.length;i<len;i++){if(!logItems[i].rendered){logItems[i].render();logItems[i].appendToLog();if(currentSearch&&(logItems[i]instanceof LogEntry)){currentSearch.applyTo(logItems[i]);}}}','if(currentSearch){if(pruned){if(currentSearch.hasVisibleMatches()){if(currentMatchIndex===null){setCurrentMatchIndex(0);}','displayMatches();}else{displayNoMatches();}}else if(!initiallyHasMatches&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}}','if(scrollToLatest){doScrollToLatest();}','unrenderedLogItemsExist=false;}','function pruneLogEntries(){if((maxMessages!==null)&&(logEntriesAndSeparators.length>maxMessages)){var numberToDelete=logEntriesAndSeparators.length-maxMessages;var prunedLogEntries=logEntriesAndSeparators.slice(0,numberToDelete);if(currentSearch){currentSearch.removeMatches(prunedLogEntries);}','var group;for(var i=0;i<numberToDelete;i++){group=logEntriesAndSeparators[i].group;array_remove(logItems,logEntriesAndSeparators[i]);array_remove(logEntries,logEntriesAndSeparators[i]);logEntriesAndSeparators[i].remove(true,true);if(group.children.length===0&&group!==currentGroup&&group!==rootGroup){array_remove(logItems,group);group.remove(true,true);}}','logEntriesAndSeparators=array_removeFromStart(logEntriesAndSeparators,numberToDelete);return true;}','return false;}','function group(name,startExpanded){if(loggingEnabled){initiallyExpanded=(typeof startExpanded==="undefined")?true:Boolean(startExpanded);var newGroup=new Group(name,false,initiallyExpanded);currentGroup.addChild(newGroup);currentGroup=newGroup;logItems.push(newGroup);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}','logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}','function groupEnd(){currentGroup=(currentGroup===rootGroup)?rootGroup:currentGroup.group;}','function mainPageReloaded(){currentGroup=rootGroup;var separator=new Separator();logEntriesAndSeparators.push(separator);logItems.push(separator);currentGroup.addChild(separator);}','function closeWindow(){if(appender&&mainWindowExists()){appender.close(true);}else{window.close();}}','function hide(){if(appender&&mainWindowExists()){appender.hide();}}','var mainWindow=window;var windowId="log4javascriptConsoleWindow_"+new Date().getTime()+"_"+(""+Math.random()).substr(2);function setMainWindow(win){mainWindow=win;mainWindow[windowId]=window;if(opener&&closeIfOpenerCloses){pollOpener();}}','function pollOpener(){if(closeIfOpenerCloses){if(mainWindowExists()){setTimeout(pollOpener,500);}else{closeWindow();}}}','function mainWindowExists(){try{return(mainWindow&&!mainWindow.closed&&mainWindow[windowId]==window);}catch(ex){}','return false;}','var logLevels=["TRACE","DEBUG","INFO","WARN","ERROR","FATAL"];function getCheckBox(logLevel){return $("switch_"+logLevel);}','function getIeWrappedLogContainer(){return $("log_wrapped");}','function getIeUnwrappedLogContainer(){return $("log_unwrapped");}','function applyFilters(){for(var i=0;i<logLevels.length;i++){if(getCheckBox(logLevels[i]).checked){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}','updateSearchFromFilters();}','function toggleAllLevels(){var turnOn=$("switch_ALL").checked;for(var i=0;i<logLevels.length;i++){getCheckBox(logLevels[i]).checked=turnOn;if(turnOn){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}}','function checkAllLevels(){for(var i=0;i<logLevels.length;i++){if(!getCheckBox(logLevels[i]).checked){getCheckBox("ALL").checked=false;return;}}','getCheckBox("ALL").checked=true;}','function clearLog(){rootGroup.clear();currentGroup=rootGroup;logEntries=[];logItems=[];logEntriesAndSeparators=[];doSearch();}','function toggleWrap(){var enable=$("wrap").checked;if(enable){addClass(logMainContainer,"wrap");}else{removeClass(logMainContainer,"wrap");}','refreshCurrentMatch();}','var searchTimer=null;function scheduleSearch(){try{clearTimeout(searchTimer);}catch(ex){}','searchTimer=setTimeout(doSearch,500);}','function Search(searchTerm,isRegex,searchRegex,isCaseSensitive){this.searchTerm=searchTerm;this.isRegex=isRegex;this.searchRegex=searchRegex;this.isCaseSensitive=isCaseSensitive;this.matches=[];}','Search.prototype={hasMatches:function(){return this.matches.length>0;},hasVisibleMatches:function(){if(this.hasMatches()){for(var i=0;i<this.matches.length;i++){if(this.matches[i].isVisible()){return true;}}}','return false;},match:function(logEntry){var entryText=String(logEntry.formattedMessage);var matchesSearch=false;if(this.isRegex){matchesSearch=this.searchRegex.test(entryText);}else if(this.isCaseSensitive){matchesSearch=(entryText.indexOf(this.searchTerm)>-1);}else{matchesSearch=(entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase())>-1);}','return matchesSearch;},getNextVisibleMatchIndex:function(){for(var i=currentMatchIndex+1;i<this.matches.length;i++){if(this.matches[i].isVisible()){return i;}}','for(i=0;i<=currentMatchIndex;i++){if(this.matches[i].isVisible()){return i;}}','return-1;},getPreviousVisibleMatchIndex:function(){for(var i=currentMatchIndex-1;i>=0;i--){if(this.matches[i].isVisible()){return i;}}','for(var i=this.matches.length-1;i>=currentMatchIndex;i--){if(this.matches[i].isVisible()){return i;}}','return-1;},applyTo:function(logEntry){var doesMatch=this.match(logEntry);if(doesMatch){logEntry.group.expand();logEntry.setSearchMatch(true);var logEntryContent;var wrappedLogEntryContent;var searchTermReplacementStartTag="<span class=\\\"searchterm\\\">";var searchTermReplacementEndTag="<"+"/span>";var preTagName=isIe?"pre":"span";var preStartTag="<"+preTagName+" class=\\\"pre\\\">";var preEndTag="<"+"/"+preTagName+">";var startIndex=0;var searchIndex,matchedText,textBeforeMatch;if(this.isRegex){var flags=this.isCaseSensitive?"g":"gi";var capturingRegex=new RegExp("("+this.searchRegex.source+")",flags);var rnd=(""+Math.random()).substr(2);var startToken="%%s"+rnd+"%%";var endToken="%%e"+rnd+"%%";logEntryContent=logEntry.formattedMessage.replace(capturingRegex,startToken+"$1"+endToken);logEntryContent=escapeHtml(logEntryContent);var result;var searchString=logEntryContent;logEntryContent="";wrappedLogEntryContent="";while((searchIndex=searchString.indexOf(startToken,startIndex))>-1){var endTokenIndex=searchString.indexOf(endToken,searchIndex);matchedText=searchString.substring(searchIndex+startToken.length,endTokenIndex);textBeforeMatch=searchString.substring(startIndex,searchIndex);logEntryContent+=preStartTag+textBeforeMatch+preEndTag;logEntryContent+=searchTermReplacementStartTag+preStartTag+matchedText+','preEndTag+searchTermReplacementEndTag;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+','matchedText+searchTermReplacementEndTag;}','startIndex=endTokenIndex+endToken.length;}','logEntryContent+=preStartTag+searchString.substr(startIndex)+preEndTag;if(isIe){wrappedLogEntryContent+=searchString.substr(startIndex);}}else{logEntryContent="";wrappedLogEntryContent="";var searchTermReplacementLength=searchTermReplacementStartTag.length+','this.searchTerm.length+searchTermReplacementEndTag.length;var searchTermLength=this.searchTerm.length;var searchTermLowerCase=this.searchTerm.toLowerCase();var logTextLowerCase=logEntry.formattedMessage.toLowerCase();while((searchIndex=logTextLowerCase.indexOf(searchTermLowerCase,startIndex))>-1){matchedText=escapeHtml(logEntry.formattedMessage.substr(searchIndex,this.searchTerm.length));textBeforeMatch=escapeHtml(logEntry.formattedMessage.substring(startIndex,searchIndex));var searchTermReplacement=searchTermReplacementStartTag+','preStartTag+matchedText+preEndTag+searchTermReplacementEndTag;logEntryContent+=preStartTag+textBeforeMatch+preEndTag+searchTermReplacement;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+','matchedText+searchTermReplacementEndTag;}','startIndex=searchIndex+searchTermLength;}','var textAfterLastMatch=escapeHtml(logEntry.formattedMessage.substr(startIndex));logEntryContent+=preStartTag+textAfterLastMatch+preEndTag;if(isIe){wrappedLogEntryContent+=textAfterLastMatch;}}','logEntry.setContent(logEntryContent,wrappedLogEntryContent);var logEntryMatches=logEntry.getSearchMatches();this.matches=this.matches.concat(logEntryMatches);}else{logEntry.setSearchMatch(false);logEntry.setContent(logEntry.formattedMessage,logEntry.formattedMessage);}','return doesMatch;},removeMatches:function(logEntries){var matchesToRemoveCount=0;var currentMatchRemoved=false;var matchesToRemove=[];var i,iLen,j,jLen;for(i=0,iLen=this.matches.length;i<iLen;i++){for(j=0,jLen=logEntries.length;j<jLen;j++){if(this.matches[i].belongsTo(logEntries[j])){matchesToRemove.push(this.matches[i]);if(i===currentMatchIndex){currentMatchRemoved=true;}}}}','var newMatch=currentMatchRemoved?null:this.matches[currentMatchIndex];if(currentMatchRemoved){for(i=currentMatchIndex,iLen=this.matches.length;i<iLen;i++){if(this.matches[i].isVisible()&&!array_contains(matchesToRemove,this.matches[i])){newMatch=this.matches[i];break;}}}','for(i=0,iLen=matchesToRemove.length;i<iLen;i++){array_remove(this.matches,matchesToRemove[i]);matchesToRemove[i].remove();}','if(this.hasVisibleMatches()){if(newMatch===null){setCurrentMatchIndex(0);}else{var newMatchIndex=0;for(i=0,iLen=this.matches.length;i<iLen;i++){if(newMatch===this.matches[i]){newMatchIndex=i;break;}}','setCurrentMatchIndex(newMatchIndex);}}else{currentMatchIndex=null;displayNoMatches();}}};function getPageOffsetTop(el,container){var currentEl=el;var y=0;while(currentEl&&currentEl!=container){y+=currentEl.offsetTop;currentEl=currentEl.offsetParent;}','return y;}','function scrollIntoView(el){var logContainer=logMainContainer;if(!$("wrap").checked){var logContainerLeft=logContainer.scrollLeft;var logContainerRight=logContainerLeft+logContainer.offsetWidth;var elLeft=el.offsetLeft;var elRight=elLeft+el.offsetWidth;if(elLeft<logContainerLeft||elRight>logContainerRight){logContainer.scrollLeft=elLeft-(logContainer.offsetWidth-el.offsetWidth)/2;}}','var logContainerTop=logContainer.scrollTop;var logContainerBottom=logContainerTop+logContainer.offsetHeight;var elTop=getPageOffsetTop(el)-getToolBarsHeight();var elBottom=elTop+el.offsetHeight;if(elTop<logContainerTop||elBottom>logContainerBottom){logContainer.scrollTop=elTop-(logContainer.offsetHeight-el.offsetHeight)/2;}}','function Match(logEntryLevel,spanInMainDiv,spanInUnwrappedPre,spanInWrappedDiv){this.logEntryLevel=logEntryLevel;this.spanInMainDiv=spanInMainDiv;if(isIe){this.spanInUnwrappedPre=spanInUnwrappedPre;this.spanInWrappedDiv=spanInWrappedDiv;}','this.mainSpan=isIe?spanInUnwrappedPre:spanInMainDiv;}','Match.prototype={equals:function(match){return this.mainSpan===match.mainSpan;},setCurrent:function(){if(isIe){addClass(this.spanInUnwrappedPre,"currentmatch");addClass(this.spanInWrappedDiv,"currentmatch");var elementToScroll=$("wrap").checked?this.spanInWrappedDiv:this.spanInUnwrappedPre;scrollIntoView(elementToScroll);}else{addClass(this.spanInMainDiv,"currentmatch");scrollIntoView(this.spanInMainDiv);}},belongsTo:function(logEntry){if(isIe){return isDescendant(this.spanInUnwrappedPre,logEntry.unwrappedPre);}else{return isDescendant(this.spanInMainDiv,logEntry.mainDiv);}},setNotCurrent:function(){if(isIe){removeClass(this.spanInUnwrappedPre,"currentmatch");removeClass(this.spanInWrappedDiv,"currentmatch");}else{removeClass(this.spanInMainDiv,"currentmatch");}},isOrphan:function(){return isOrphan(this.mainSpan);},isVisible:function(){return getCheckBox(this.logEntryLevel).checked;},remove:function(){if(isIe){this.spanInUnwrappedPre=null;this.spanInWrappedDiv=null;}else{this.spanInMainDiv=null;}}};var currentSearch=null;var currentMatchIndex=null;function doSearch(){var searchBox=$("searchBox");var searchTerm=searchBox.value;var isRegex=$("searchRegex").checked;var isCaseSensitive=$("searchCaseSensitive").checked;var i;if(searchTerm===""){$("searchReset").disabled=true;$("searchNav").style.display="none";removeClass(document.body,"searching");removeClass(searchBox,"hasmatches");removeClass(searchBox,"nomatches");for(i=0;i<logEntries.length;i++){logEntries[i].clearSearch();logEntries[i].setContent(logEntries[i].formattedMessage,logEntries[i].formattedMessage);}','currentSearch=null;setLogContainerHeight();}else{$("searchReset").disabled=false;$("searchNav").style.display="block";var searchRegex;var regexValid;if(isRegex){try{searchRegex=isCaseSensitive?new RegExp(searchTerm,"g"):new RegExp(searchTerm,"gi");regexValid=true;replaceClass(searchBox,"validregex","invalidregex");searchBox.title="Valid regex";}catch(ex){regexValid=false;replaceClass(searchBox,"invalidregex","validregex");searchBox.title="Invalid regex: "+(ex.message?ex.message:(ex.description?ex.description:"unknown error"));return;}}else{searchBox.title="";removeClass(searchBox,"validregex");removeClass(searchBox,"invalidregex");}','addClass(document.body,"searching");currentSearch=new Search(searchTerm,isRegex,searchRegex,isCaseSensitive);for(i=0;i<logEntries.length;i++){currentSearch.applyTo(logEntries[i]);}','setLogContainerHeight();if(currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}else{displayNoMatches();}}}','function updateSearchFromFilters(){if(currentSearch){if(currentSearch.hasMatches()){if(currentMatchIndex===null){currentMatchIndex=0;}','var currentMatch=currentSearch.matches[currentMatchIndex];if(currentMatch.isVisible()){displayMatches();setCurrentMatchIndex(currentMatchIndex);}else{currentMatch.setNotCurrent();var nextVisibleMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextVisibleMatchIndex>-1){setCurrentMatchIndex(nextVisibleMatchIndex);displayMatches();}else{displayNoMatches();}}}else{displayNoMatches();}}}','function refreshCurrentMatch(){if(currentSearch&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(currentMatchIndex);}}','function displayMatches(){replaceClass($("searchBox"),"hasmatches","nomatches");$("searchBox").title=""+currentSearch.matches.length+" matches found";$("searchNav").style.display="block";setLogContainerHeight();}','function displayNoMatches(){replaceClass($("searchBox"),"nomatches","hasmatches");$("searchBox").title="No matches found";$("searchNav").style.display="none";setLogContainerHeight();}','function toggleSearchEnabled(enable){enable=(typeof enable=="undefined")?!$("searchDisable").checked:enable;$("searchBox").disabled=!enable;$("searchReset").disabled=!enable;$("searchRegex").disabled=!enable;$("searchNext").disabled=!enable;$("searchPrevious").disabled=!enable;$("searchCaseSensitive").disabled=!enable;$("searchNav").style.display=(enable&&($("searchBox").value!=="")&&currentSearch&&currentSearch.hasVisibleMatches())?"block":"none";if(enable){removeClass($("search"),"greyedout");addClass(document.body,"searching");if($("searchHighlight").checked){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}','if($("searchFilter").checked){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}','$("searchDisable").checked=!enable;}else{addClass($("search"),"greyedout");removeClass(document.body,"searching");removeClass(logMainContainer,"searchhighlight");removeClass(logMainContainer,"searchfilter");}','setLogContainerHeight();}','function toggleSearchFilter(){var enable=$("searchFilter").checked;if(enable){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}','refreshCurrentMatch();}','function toggleSearchHighlight(){var enable=$("searchHighlight").checked;if(enable){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}}','function clearSearch(){$("searchBox").value="";doSearch();}','function searchNext(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var nextMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextMatchIndex>currentMatchIndex||confirm("Reached the end of the page. Start from the top?")){setCurrentMatchIndex(nextMatchIndex);}}}','function searchPrevious(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var previousMatchIndex=currentSearch.getPreviousVisibleMatchIndex();if(previousMatchIndex<currentMatchIndex||confirm("Reached the start of the page. Continue from the bottom?")){setCurrentMatchIndex(previousMatchIndex);}}}','function setCurrentMatchIndex(index){currentMatchIndex=index;currentSearch.matches[currentMatchIndex].setCurrent();}','function addClass(el,cssClass){if(!hasClass(el,cssClass)){if(el.className){el.className+=" "+cssClass;}else{el.className=cssClass;}}}','function hasClass(el,cssClass){if(el.className){var classNames=el.className.split(" ");return array_contains(classNames,cssClass);}','return false;}','function removeClass(el,cssClass){if(hasClass(el,cssClass)){var existingClasses=el.className.split(" ");var newClasses=[];for(var i=0,len=existingClasses.length;i<len;i++){if(existingClasses[i]!=cssClass){newClasses[newClasses.length]=existingClasses[i];}}','el.className=newClasses.join(" ");}}','function replaceClass(el,newCssClass,oldCssClass){removeClass(el,oldCssClass);addClass(el,newCssClass);}','function getElementsByClass(el,cssClass,tagName){var elements=el.getElementsByTagName(tagName);var matches=[];for(var i=0,len=elements.length;i<len;i++){if(hasClass(elements[i],cssClass)){matches.push(elements[i]);}}','return matches;}','function $(id){return document.getElementById(id);}','function isDescendant(node,ancestorNode){while(node!=null){if(node===ancestorNode){return true;}','node=node.parentNode;}','return false;}','function isOrphan(node){var currentNode=node;while(currentNode){if(currentNode==document.body){return false;}','currentNode=currentNode.parentNode;}','return true;}','function escapeHtml(str){return str.replace(/&/g,"&amp;").replace(/[<]/g,"&lt;").replace(/>/g,"&gt;");}','function getWindowWidth(){if(window.innerWidth){return window.innerWidth;}else if(document.documentElement&&document.documentElement.clientWidth){return document.documentElement.clientWidth;}else if(document.body){return document.body.clientWidth;}','return 0;}','function getWindowHeight(){if(window.innerHeight){return window.innerHeight;}else if(document.documentElement&&document.documentElement.clientHeight){return document.documentElement.clientHeight;}else if(document.body){return document.body.clientHeight;}','return 0;}','function getToolBarsHeight(){return $("switches").offsetHeight;}','function getChromeHeight(){var height=getToolBarsHeight();if(showCommandLine){height+=$("commandLine").offsetHeight;}','return height;}','function setLogContainerHeight(){if(logMainContainer){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";logMainContainer.style.height=""+','Math.max(0,windowHeight-getChromeHeight())+"px";}}','function setCommandInputWidth(){if(showCommandLine){$("command").style.width=""+Math.max(0,$("commandLineContainer").offsetWidth-','($("evaluateButton").offsetWidth+13))+"px";}}','window.onresize=function(){setCommandInputWidth();setLogContainerHeight();};if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}','return this.length;};}','if(!Array.prototype.pop){Array.prototype.pop=function(){if(this.length>0){var val=this[this.length-1];this.length=this.length-1;return val;}};}','if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}','this.length=this.length-1;return firstItem;}};}','if(!Array.prototype.splice){Array.prototype.splice=function(startIndex,deleteCount){var itemsAfterDeleted=this.slice(startIndex+deleteCount);var itemsDeleted=this.slice(startIndex,startIndex+deleteCount);this.length=startIndex;var argumentsArray=[];for(var i=0,len=arguments.length;i<len;i++){argumentsArray[i]=arguments[i];}','var itemsToAppend=(argumentsArray.length>2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i<len;i++){this.push(itemsToAppend[i]);}','return itemsDeleted;};}','function array_remove(arr,val){var index=-1;for(var i=0,len=arr.length;i<len;i++){if(arr[i]===val){index=i;break;}}','if(index>=0){arr.splice(index,1);return index;}else{return false;}}','function array_removeFromStart(array,numberToRemove){if(Array.prototype.splice){array.splice(0,numberToRemove);}else{for(var i=numberToRemove,len=array.length;i<len;i++){array[i-numberToRemove]=array[i];}','array.length=array.length-numberToRemove;}','return array;}','function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}','return false;}','function getErrorMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}','return""+ex;}','function moveCaretToEnd(input){if(input.setSelectionRange){input.focus();var length=input.value.length;input.setSelectionRange(length,length);}else if(input.createTextRange){var range=input.createTextRange();range.collapse(false);range.select();}','input.focus();}','function stopPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}}','function getEvent(evt){return evt?evt:event;}','function getTarget(evt){return evt.target?evt.target:evt.srcElement;}','function getRelatedTarget(evt){if(evt.relatedTarget){return evt.relatedTarget;}else if(evt.srcElement){switch(evt.type){case"mouseover":return evt.fromElement;case"mouseout":return evt.toElement;default:return evt.srcElement;}}}','function cancelKeyEvent(evt){evt.returnValue=false;stopPropagation(evt);}','function evalCommandLine(){var expr=$("command").value;evalCommand(expr);$("command").value="";}','function evalLastCommand(){if(lastCommand!=null){evalCommand(lastCommand);}}','var lastCommand=null;var commandHistory=[];var currentCommandIndex=0;function evalCommand(expr){if(appender){appender.evalCommandAndAppend(expr);}else{var prefix=">>> "+expr+"\\r\\n";try{log("INFO",prefix+eval(expr));}catch(ex){log("ERROR",prefix+"Error: "+getErrorMessage(ex));}}','if(expr!=commandHistory[commandHistory.length-1]){commandHistory.push(expr);if(appender){appender.storeCommandHistory(commandHistory);}}','currentCommandIndex=(expr==commandHistory[currentCommandIndex])?currentCommandIndex+1:commandHistory.length;lastCommand=expr;}','//]]>','</script>','<style type="text/css">','body{background-color:white;color:black;padding:0;margin:0;font-family:tahoma,verdana,arial,helvetica,sans-serif;overflow:hidden}div#switchesContainer input{margin-bottom:0}div.toolbar{border-top:solid #ffffff 1px;border-bottom:solid #aca899 1px;background-color:#f1efe7;padding:3px 5px;font-size:68.75%}div.toolbar,div#search input{font-family:tahoma,verdana,arial,helvetica,sans-serif}div.toolbar input.button{padding:0 5px;font-size:100%}div.toolbar input.hidden{display:none}div#switches input#clearButton{margin-left:20px}div#levels label{font-weight:bold}div#levels label,div#options label{margin-right:5px}div#levels label#wrapLabel{font-weight:normal}div#search label{margin-right:10px}div#search label.searchboxlabel{margin-right:0}div#search input{font-size:100%}div#search input.validregex{color:green}div#search input.invalidregex{color:red}div#search input.nomatches{color:white;background-color:#ff6666}div#search input.nomatches{color:white;background-color:#ff6666}div#searchNav{display:none}div#commandLine{display:none}div#commandLine input#command{font-size:100%;font-family:Courier New,Courier}div#commandLine input#evaluateButton{}*.greyedout{color:gray !important;border-color:gray !important}*.greyedout *.alwaysenabled{color:black}*.unselectable{-khtml-user-select:none;-moz-user-select:none;user-select:none}div#log{font-family:Courier New,Courier;font-size:75%;width:100%;overflow:auto;clear:both;position:relative}div.group{border-color:#cccccc;border-style:solid;border-width:1px 0 1px 1px;overflow:visible}div.oldIe div.group,div.oldIe div.group *,div.oldIe *.logentry{height:1%}div.group div.groupheading span.expander{border:solid black 1px;font-family:Courier New,Courier;font-size:0.833em;background-color:#eeeeee;position:relative;top:-1px;color:black;padding:0 2px;cursor:pointer;cursor:hand;height:1%}div.group div.groupcontent{margin-left:10px;padding-bottom:2px;overflow:visible}div.group div.expanded{display:block}div.group div.collapsed{display:none}*.logentry{overflow:visible;display:none;white-space:pre}span.pre{white-space:pre}pre.unwrapped{display:inline !important}pre.unwrapped pre.pre,div.wrapped pre.pre{display:inline}div.wrapped pre.pre{white-space:normal}div.wrapped{display:none}body.searching *.logentry span.currentmatch{color:white !important;background-color:green !important}body.searching div.searchhighlight *.logentry span.searchterm{color:black;background-color:yellow}div.wrap *.logentry{white-space:normal !important;border-width:0 0 1px 0;border-color:#dddddd;border-style:dotted}div.wrap #log_wrapped,#log_unwrapped{display:block}div.wrap #log_unwrapped,#log_wrapped{display:none}div.wrap *.logentry span.pre{overflow:visible;white-space:normal}div.wrap *.logentry pre.unwrapped{display:none}div.wrap *.logentry span.wrapped{display:inline}div.searchfilter *.searchnonmatch{display:none !important}div#log *.TRACE,label#label_TRACE{color:#666666}div#log *.DEBUG,label#label_DEBUG{color:green}div#log *.INFO,label#label_INFO{color:#000099}div#log *.WARN,label#label_WARN{color:#999900}div#log *.ERROR,label#label_ERROR{color:red}div#log *.FATAL,label#label_FATAL{color:#660066}div.TRACE#log *.TRACE,div.DEBUG#log *.DEBUG,div.INFO#log *.INFO,div.WARN#log *.WARN,div.ERROR#log *.ERROR,div.FATAL#log *.FATAL{display:block}div#log div.separator{background-color:#cccccc;margin:5px 0;line-height:1px}','</style>','</head>','<body id="body">','<div id="switchesContainer">','<div id="switches">','<div id="levels" class="toolbar">','Filters:','<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>','<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>','<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>','<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>','<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>','<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>','<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>','</div>','<div id="search" class="toolbar">','<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />','<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />','<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>','<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>','<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>','<div id="searchNav">','<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />','<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />','<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>','<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>','</div>','</div>','<div id="options" class="toolbar">','Options:','<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>','<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>','<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>','<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>','<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />','<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />','<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />','</div>','</div>','</div>','<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>','<div id="commandLine" class="toolbar">','<div id="commandLineContainer">','<input type="text" id="command" title="Enter a JavaScript command here and hit return or press \'Evaluate\'" />','<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />','</div>','</div>','</body>','</html>',''];};var defaultCommandLineFunctions=[];ConsoleAppender=function(){};var consoleAppenderIdCounter=1;ConsoleAppender.prototype=new Appender();ConsoleAppender.prototype.create=function(inPage,container,lazyInit,initiallyMinimized,useDocumentWrite,width,height,focusConsoleWindow){var appender=this;var initialized=false;var consoleWindowCreated=false;var consoleWindowLoaded=false;var consoleClosed=false;var queuedLoggingEvents=[];var isSupported=true;var consoleAppenderId=consoleAppenderIdCounter++;initiallyMinimized=extractBooleanFromParam(initiallyMinimized,this.defaults.initiallyMinimized);lazyInit=extractBooleanFromParam(lazyInit,this.defaults.lazyInit);useDocumentWrite=extractBooleanFromParam(useDocumentWrite,this.defaults.useDocumentWrite);var newestMessageAtTop=this.defaults.newestMessageAtTop;var scrollToLatestMessage=this.defaults.scrollToLatestMessage;width=width?width:this.defaults.width;height=height?height:this.defaults.height;var maxMessages=this.defaults.maxMessages;var showCommandLine=this.defaults.showCommandLine;var commandLineObjectExpansionDepth=this.defaults.commandLineObjectExpansionDepth;var showHideButton=this.defaults.showHideButton;var showCloseButton=this.defaults.showCloseButton;var showLogEntryDeleteButtons=this.defaults.showLogEntryDeleteButtons;this.setLayout(this.defaults.layout);var init,createWindow,safeToAppend,getConsoleWindow,open;var appenderName=inPage?"InPageAppender":"PopUpAppender";var checkCanConfigure=function(configOptionName){if(consoleWindowCreated){handleError(appenderName+": configuration option '"+configOptionName+"' may not be set after the appender has been initialized");return false;}

+return true;};var consoleWindowExists=function(){return(consoleWindowLoaded&&isSupported&&!consoleClosed);};this.isNewestMessageAtTop=function(){return newestMessageAtTop;};this.setNewestMessageAtTop=function(newestMessageAtTopParam){newestMessageAtTop=bool(newestMessageAtTopParam);if(consoleWindowExists()){getConsoleWindow().setNewestAtTop(newestMessageAtTop);}};this.isScrollToLatestMessage=function(){return scrollToLatestMessage;};this.setScrollToLatestMessage=function(scrollToLatestMessageParam){scrollToLatestMessage=bool(scrollToLatestMessageParam);if(consoleWindowExists()){getConsoleWindow().setScrollToLatest(scrollToLatestMessage);}};this.getWidth=function(){return width;};this.setWidth=function(widthParam){if(checkCanConfigure("width")){width=extractStringFromParam(widthParam,width);}};this.getHeight=function(){return height;};this.setHeight=function(heightParam){if(checkCanConfigure("height")){height=extractStringFromParam(heightParam,height);}};this.getMaxMessages=function(){return maxMessages;};this.setMaxMessages=function(maxMessagesParam){maxMessages=extractIntFromParam(maxMessagesParam,maxMessages);if(consoleWindowExists()){getConsoleWindow().setMaxMessages(maxMessages);}};this.isShowCommandLine=function(){return showCommandLine;};this.setShowCommandLine=function(showCommandLineParam){showCommandLine=bool(showCommandLineParam);if(consoleWindowExists()){getConsoleWindow().setShowCommandLine(showCommandLine);}};this.isShowHideButton=function(){return showHideButton;};this.setShowHideButton=function(showHideButtonParam){showHideButton=bool(showHideButtonParam);if(consoleWindowExists()){getConsoleWindow().setShowHideButton(showHideButton);}};this.isShowCloseButton=function(){return showCloseButton;};this.setShowCloseButton=function(showCloseButtonParam){showCloseButton=bool(showCloseButtonParam);if(consoleWindowExists()){getConsoleWindow().setShowCloseButton(showCloseButton);}};this.getCommandLineObjectExpansionDepth=function(){return commandLineObjectExpansionDepth;};this.setCommandLineObjectExpansionDepth=function(commandLineObjectExpansionDepthParam){commandLineObjectExpansionDepth=extractIntFromParam(commandLineObjectExpansionDepthParam,commandLineObjectExpansionDepth);};var minimized=initiallyMinimized;this.isInitiallyMinimized=function(){return initiallyMinimized;};this.setInitiallyMinimized=function(initiallyMinimizedParam){if(checkCanConfigure("initiallyMinimized")){initiallyMinimized=bool(initiallyMinimizedParam);minimized=initiallyMinimized;}};this.isUseDocumentWrite=function(){return useDocumentWrite;};this.setUseDocumentWrite=function(useDocumentWriteParam){if(checkCanConfigure("useDocumentWrite")){useDocumentWrite=bool(useDocumentWriteParam);}};function QueuedLoggingEvent(loggingEvent,formattedMessage){this.loggingEvent=loggingEvent;this.levelName=loggingEvent.level.name;this.formattedMessage=formattedMessage;}

+QueuedLoggingEvent.prototype.append=function(){getConsoleWindow().log(this.levelName,this.formattedMessage);};function QueuedGroup(name,initiallyExpanded){this.name=name;this.initiallyExpanded=initiallyExpanded;}

+QueuedGroup.prototype.append=function(){getConsoleWindow().group(this.name,this.initiallyExpanded);};function QueuedGroupEnd(){}

+QueuedGroupEnd.prototype.append=function(){getConsoleWindow().groupEnd();};var checkAndAppend=function(){safeToAppend();if(!initialized){init();}else if(consoleClosed&&reopenWhenClosed){createWindow();}

+if(safeToAppend()){appendQueuedLoggingEvents();}};this.append=function(loggingEvent){if(isSupported){var formattedMessage=appender.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();}

+queuedLoggingEvents.push(new QueuedLoggingEvent(loggingEvent,formattedMessage));checkAndAppend();}};this.group=function(name,initiallyExpanded){if(isSupported){queuedLoggingEvents.push(new QueuedGroup(name,initiallyExpanded));checkAndAppend();}};this.groupEnd=function(){if(isSupported){queuedLoggingEvents.push(new QueuedGroupEnd());checkAndAppend();}};var appendQueuedLoggingEvents=function(){var currentLoggingEvent;while(queuedLoggingEvents.length>0){queuedLoggingEvents.shift().append();}

+if(focusConsoleWindow){getConsoleWindow().focus();}};this.setAddedToLogger=function(logger){this.loggers.push(logger);if(enabled&&!lazyInit){init();}};this.clear=function(){if(consoleWindowExists()){getConsoleWindow().clearLog();}

+queuedLoggingEvents.length=0;};this.focus=function(){if(consoleWindowExists()){getConsoleWindow().focus();}};this.focusCommandLine=function(){if(consoleWindowExists()){getConsoleWindow().focusCommandLine();}};this.focusSearch=function(){if(consoleWindowExists()){getConsoleWindow().focusSearch();}};var commandWindow=window;this.getCommandWindow=function(){return commandWindow;};this.setCommandWindow=function(commandWindowParam){commandWindow=commandWindowParam;};this.executeLastCommand=function(){if(consoleWindowExists()){getConsoleWindow().evalLastCommand();}};var commandLayout=new PatternLayout("%m");this.getCommandLayout=function(){return commandLayout;};this.setCommandLayout=function(commandLayoutParam){commandLayout=commandLayoutParam;};this.evalCommandAndAppend=function(expr){var commandReturnValue={appendResult:true,isError:false};var commandOutput="";try{var result,i;if(!commandWindow.eval&&commandWindow.execScript){commandWindow.execScript("null");}

+var commandLineFunctionsHash={};for(i=0,len=commandLineFunctions.length;i<len;i++){commandLineFunctionsHash[commandLineFunctions[i][0]]=commandLineFunctions[i][1];}

+var objectsToRestore=[];var addObjectToRestore=function(name){objectsToRestore.push([name,commandWindow[name]]);};addObjectToRestore("appender");commandWindow.appender=appender;addObjectToRestore("commandReturnValue");commandWindow.commandReturnValue=commandReturnValue;addObjectToRestore("commandLineFunctionsHash");commandWindow.commandLineFunctionsHash=commandLineFunctionsHash;var addFunctionToWindow=function(name){addObjectToRestore(name);commandWindow[name]=function(){return this.commandLineFunctionsHash[name](appender,arguments,commandReturnValue);};};for(i=0,len=commandLineFunctions.length;i<len;i++){addFunctionToWindow(commandLineFunctions[i][0]);}

+if(commandWindow===window&&commandWindow.execScript){addObjectToRestore("evalExpr");addObjectToRestore("result");window.evalExpr=expr;commandWindow.execScript("window.result=eval(window.evalExpr);");result=window.result;}else{result=commandWindow.eval(expr);}

+commandOutput=isUndefined(result)?result:formatObjectExpansion(result,commandLineObjectExpansionDepth);for(i=0,len=objectsToRestore.length;i<len;i++){commandWindow[objectsToRestore[i][0]]=objectsToRestore[i][1];}}catch(ex){commandOutput="Error evaluating command: "+getExceptionStringRep(ex);commandReturnValue.isError=true;}

+if(commandReturnValue.appendResult){var message=">>> "+expr;if(!isUndefined(commandOutput)){message+=newLine+commandOutput;}

+var level=commandReturnValue.isError?Level.ERROR:Level.INFO;var loggingEvent=new LoggingEvent(null,new Date(),level,[message],null);var mainLayout=this.getLayout();this.setLayout(commandLayout);this.append(loggingEvent);this.setLayout(mainLayout);}};var commandLineFunctions=defaultCommandLineFunctions.concat([]);this.addCommandLineFunction=function(functionName,commandLineFunction){commandLineFunctions.push([functionName,commandLineFunction]);};var commandHistoryCookieName="log4javascriptCommandHistory";this.storeCommandHistory=function(commandHistory){setCookie(commandHistoryCookieName,commandHistory.join(","));};var writeHtml=function(doc){var lines=getConsoleHtmlLines();doc.open();for(var i=0,len=lines.length;i<len;i++){doc.writeln(lines[i]);}

+doc.close();};this.setEventTypes(["load","unload"]);var consoleWindowLoadHandler=function(){var win=getConsoleWindow();win.setAppender(appender);win.setNewestAtTop(newestMessageAtTop);win.setScrollToLatest(scrollToLatestMessage);win.setMaxMessages(maxMessages);win.setShowCommandLine(showCommandLine);win.setShowHideButton(showHideButton);win.setShowCloseButton(showCloseButton);win.setMainWindow(window);var storedValue=getCookie(commandHistoryCookieName);if(storedValue){win.commandHistory=storedValue.split(",");win.currentCommandIndex=win.commandHistory.length;}

+appender.dispatchEvent("load",{"win":win});};this.unload=function(){logLog.debug("unload "+this+", caller: "+this.unload.caller);if(!consoleClosed){logLog.debug("really doing unload "+this);consoleClosed=true;consoleWindowLoaded=false;consoleWindowCreated=false;appender.dispatchEvent("unload",{});}};var pollConsoleWindow=function(windowTest,interval,successCallback,errorMessage){function doPoll(){try{if(consoleClosed){clearInterval(poll);}

+if(windowTest(getConsoleWindow())){clearInterval(poll);successCallback();}}catch(ex){clearInterval(poll);isSupported=false;handleError(errorMessage,ex);}}

+var poll=setInterval(doPoll,interval);};var getConsoleUrl=function(){var documentDomainSet=(document.domain!=location.hostname);return useDocumentWrite?"":getBaseUrl()+"console.html"+

+(documentDomainSet?"?log4javascript_domain="+escape(document.domain):"");};if(inPage){var containerElement=null;var cssProperties=[];this.addCssProperty=function(name,value){if(checkCanConfigure("cssProperties")){cssProperties.push([name,value]);}};var windowCreationStarted=false;var iframeContainerDiv;var iframeId=uniqueId+"_InPageAppender_"+consoleAppenderId;this.hide=function(){if(initialized&&consoleWindowCreated){if(consoleWindowExists()){getConsoleWindow().$("command").blur();}

+iframeContainerDiv.style.display="none";minimized=true;}};this.show=function(){if(initialized){if(consoleWindowCreated){iframeContainerDiv.style.display="block";this.setShowCommandLine(showCommandLine);minimized=false;}else if(!windowCreationStarted){createWindow(true);}}};this.isVisible=function(){return!minimized&&!consoleClosed;};this.close=function(fromButton){if(!consoleClosed&&(!fromButton||confirm("This will permanently remove the console from the page. No more messages will be logged. Do you wish to continue?"))){iframeContainerDiv.parentNode.removeChild(iframeContainerDiv);this.unload();}};open=function(){var initErrorMessage="InPageAppender.open: unable to create console iframe";function finalInit(){try{if(!initiallyMinimized){appender.show();}

+consoleWindowLoadHandler();consoleWindowLoaded=true;appendQueuedLoggingEvents();}catch(ex){isSupported=false;handleError(initErrorMessage,ex);}}

+function writeToDocument(){try{var windowTest=function(win){return isLoaded(win);};if(useDocumentWrite){writeHtml(getConsoleWindow().document);}

+if(windowTest(getConsoleWindow())){finalInit();}else{pollConsoleWindow(windowTest,100,finalInit,initErrorMessage);}}catch(ex){isSupported=false;handleError(initErrorMessage,ex);}}

+minimized=false;iframeContainerDiv=containerElement.appendChild(document.createElement("div"));iframeContainerDiv.style.width=width;iframeContainerDiv.style.height=height;iframeContainerDiv.style.border="solid gray 1px";for(var i=0,len=cssProperties.length;i<len;i++){iframeContainerDiv.style[cssProperties[i][0]]=cssProperties[i][1];}

+var iframeSrc=useDocumentWrite?"":" src='"+getConsoleUrl()+"'";iframeContainerDiv.innerHTML="<iframe id='"+iframeId+"' name='"+iframeId+"' width='100%' height='100%' frameborder='0'"+iframeSrc+" scrolling='no'></iframe>";consoleClosed=false;var iframeDocumentExistsTest=function(win){try{return bool(win)&&bool(win.document);}catch(ex){return false;}};if(iframeDocumentExistsTest(getConsoleWindow())){writeToDocument();}else{pollConsoleWindow(iframeDocumentExistsTest,100,writeToDocument,initErrorMessage);}

+consoleWindowCreated=true;};createWindow=function(show){if(show||!initiallyMinimized){var pageLoadHandler=function(){if(!container){containerElement=document.createElement("div");containerElement.style.position="fixed";containerElement.style.left="0";containerElement.style.right="0";containerElement.style.bottom="0";document.body.appendChild(containerElement);appender.addCssProperty("borderWidth","1px 0 0 0");appender.addCssProperty("zIndex",1000000);open();}else{try{var el=document.getElementById(container);if(el.nodeType==1){containerElement=el;}

+open();}catch(ex){handleError("InPageAppender.init: invalid container element '"+container+"' supplied",ex);}}};if(pageLoaded&&container&&container.appendChild){containerElement=container;open();}else if(pageLoaded){pageLoadHandler();}else{log4javascript.addEventListener("load",pageLoadHandler);}

+windowCreationStarted=true;}};init=function(){createWindow();initialized=true;};getConsoleWindow=function(){var iframe=window.frames[iframeId];if(iframe){return iframe;}};safeToAppend=function(){if(isSupported&&!consoleClosed){if(consoleWindowCreated&&!consoleWindowLoaded&&getConsoleWindow()&&isLoaded(getConsoleWindow())){consoleWindowLoaded=true;}

+return consoleWindowLoaded;}

+return false;};}else{var useOldPopUp=appender.defaults.useOldPopUp;var complainAboutPopUpBlocking=appender.defaults.complainAboutPopUpBlocking;var reopenWhenClosed=this.defaults.reopenWhenClosed;this.isUseOldPopUp=function(){return useOldPopUp;};this.setUseOldPopUp=function(useOldPopUpParam){if(checkCanConfigure("useOldPopUp")){useOldPopUp=bool(useOldPopUpParam);}};this.isComplainAboutPopUpBlocking=function(){return complainAboutPopUpBlocking;};this.setComplainAboutPopUpBlocking=function(complainAboutPopUpBlockingParam){if(checkCanConfigure("complainAboutPopUpBlocking")){complainAboutPopUpBlocking=bool(complainAboutPopUpBlockingParam);}};this.isFocusPopUp=function(){return focusConsoleWindow;};this.setFocusPopUp=function(focusPopUpParam){focusConsoleWindow=bool(focusPopUpParam);};this.isReopenWhenClosed=function(){return reopenWhenClosed;};this.setReopenWhenClosed=function(reopenWhenClosedParam){reopenWhenClosed=bool(reopenWhenClosedParam);};this.close=function(){logLog.debug("close "+this);try{popUp.close();this.unload();}catch(ex){}};this.hide=function(){logLog.debug("hide "+this);if(consoleWindowExists()){this.close();}};this.show=function(){logLog.debug("show "+this);if(!consoleWindowCreated){open();}};this.isVisible=function(){return safeToAppend();};var popUp;open=function(){var windowProperties="width="+width+",height="+height+",status,resizable";var frameInfo="";try{var frameEl=window.frameElement;if(frameEl){frameInfo="_"+frameEl.tagName+"_"+(frameEl.name||frameEl.id||"");}}catch(e){frameInfo="_inaccessibleParentFrame";}

+var windowName="PopUp_"+location.host.replace(/[^a-z0-9]/gi,"_")+"_"+consoleAppenderId+frameInfo;if(!useOldPopUp||!useDocumentWrite){windowName=windowName+"_"+uniqueId;}

+var checkPopUpClosed=function(win){if(consoleClosed){return true;}else{try{return bool(win)&&win.closed;}catch(ex){}}

+return false;};var popUpClosedCallback=function(){if(!consoleClosed){appender.unload();}};function finalInit(){getConsoleWindow().setCloseIfOpenerCloses(!useOldPopUp||!useDocumentWrite);consoleWindowLoadHandler();consoleWindowLoaded=true;appendQueuedLoggingEvents();pollConsoleWindow(checkPopUpClosed,500,popUpClosedCallback,"PopUpAppender.checkPopUpClosed: error checking pop-up window");}

+try{popUp=window.open(getConsoleUrl(),windowName,windowProperties);consoleClosed=false;consoleWindowCreated=true;if(popUp&&popUp.document){if(useDocumentWrite&&useOldPopUp&&isLoaded(popUp)){popUp.mainPageReloaded();finalInit();}else{if(useDocumentWrite){writeHtml(popUp.document);}

+var popUpLoadedTest=function(win){return bool(win)&&isLoaded(win);};if(isLoaded(popUp)){finalInit();}else{pollConsoleWindow(popUpLoadedTest,100,finalInit,"PopUpAppender.init: unable to create console window");}}}else{isSupported=false;logLog.warn("PopUpAppender.init: pop-ups blocked, please unblock to use PopUpAppender");if(complainAboutPopUpBlocking){handleError("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");}}}catch(ex){handleError("PopUpAppender.init: error creating pop-up",ex);}};createWindow=function(){if(!initiallyMinimized){open();}};init=function(){createWindow();initialized=true;};getConsoleWindow=function(){return popUp;};safeToAppend=function(){if(isSupported&&!isUndefined(popUp)&&!consoleClosed){if(popUp.closed||(consoleWindowLoaded&&isUndefined(popUp.closed))){appender.unload();logLog.debug("PopUpAppender: pop-up closed");return false;}

+if(!consoleWindowLoaded&&isLoaded(popUp)){consoleWindowLoaded=true;}}

+return isSupported&&consoleWindowLoaded&&!consoleClosed;};}

+this.getConsoleWindow=getConsoleWindow;};ConsoleAppender.addGlobalCommandLineFunction=function(functionName,commandLineFunction){defaultCommandLineFunctions.push([functionName,commandLineFunction]);};function PopUpAppender(lazyInit,initiallyMinimized,useDocumentWrite,width,height){this.create(false,null,lazyInit,initiallyMinimized,useDocumentWrite,width,height,this.defaults.focusPopUp);}

+PopUpAppender.prototype=new ConsoleAppender();PopUpAppender.prototype.defaults={layout:new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),initiallyMinimized:false,focusPopUp:false,lazyInit:true,useOldPopUp:true,complainAboutPopUpBlocking:true,newestMessageAtTop:false,scrollToLatestMessage:true,width:"600",height:"400",reopenWhenClosed:false,maxMessages:null,showCommandLine:true,commandLineObjectExpansionDepth:1,showHideButton:false,showCloseButton:true,showLogEntryDeleteButtons:true,useDocumentWrite:true};PopUpAppender.prototype.toString=function(){return"PopUpAppender";};log4javascript.PopUpAppender=PopUpAppender;function InPageAppender(container,lazyInit,initiallyMinimized,useDocumentWrite,width,height){this.create(true,container,lazyInit,initiallyMinimized,useDocumentWrite,width,height,false);}

+InPageAppender.prototype=new ConsoleAppender();InPageAppender.prototype.defaults={layout:new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),initiallyMinimized:false,lazyInit:true,newestMessageAtTop:false,scrollToLatestMessage:true,width:"100%",height:"220px",maxMessages:null,showCommandLine:true,commandLineObjectExpansionDepth:1,showHideButton:false,showCloseButton:false,showLogEntryDeleteButtons:true,useDocumentWrite:true};InPageAppender.prototype.toString=function(){return"InPageAppender";};log4javascript.InPageAppender=InPageAppender;log4javascript.InlineAppender=InPageAppender;})();function padWithSpaces(str,len){if(str.length<len){var spaces=[];var numberOfSpaces=Math.max(0,len-str.length);for(var i=0;i<numberOfSpaces;i++){spaces[i]=" ";}

+str+=spaces.join("");}

+return str;}

+(function(){function dir(obj){var maxLen=0;for(var p in obj){maxLen=Math.max(toStr(p).length,maxLen);}

+var propList=[];for(p in obj){var propNameStr="  "+padWithSpaces(toStr(p),maxLen+2);var propVal;try{propVal=splitIntoLines(toStr(obj[p])).join(padWithSpaces(newLine,maxLen+6));}catch(ex){propVal="[Error obtaining property. Details: "+getExceptionMessage(ex)+"]";}

+propList.push(propNameStr+propVal);}

+return propList.join(newLine);}

+var nodeTypes={ELEMENT_NODE:1,ATTRIBUTE_NODE:2,TEXT_NODE:3,CDATA_SECTION_NODE:4,ENTITY_REFERENCE_NODE:5,ENTITY_NODE:6,PROCESSING_INSTRUCTION_NODE:7,COMMENT_NODE:8,DOCUMENT_NODE:9,DOCUMENT_TYPE_NODE:10,DOCUMENT_FRAGMENT_NODE:11,NOTATION_NODE:12};var preFormattedElements=["script","pre"];var emptyElements=["br","img","hr","param","link","area","input","col","base","meta"];var indentationUnit="  ";function getXhtml(rootNode,includeRootNode,indentation,startNewLine,preformatted){includeRootNode=(typeof includeRootNode=="undefined")?true:!!includeRootNode;if(typeof indentation!="string"){indentation="";}

+startNewLine=!!startNewLine;preformatted=!!preformatted;var xhtml;function isWhitespace(node){return((node.nodeType==nodeTypes.TEXT_NODE)&&/^[ \t\r\n]*$/.test(node.nodeValue));}

+function fixAttributeValue(attrValue){return attrValue.toString().replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/"/g,"&quot;");}

+function getStyleAttributeValue(el){var stylePairs=el.style.cssText.split(";");var styleValue="";var isFirst=true;for(var j=0,len=stylePairs.length;j<len;j++){var nameValueBits=stylePairs[j].split(":");var props=[];if(!/^\s*$/.test(nameValueBits[0])){props.push(trim(nameValueBits[0]).toLowerCase()+":"+trim(nameValueBits[1]));}

+styleValue=props.join(";");}

+return styleValue;}

+function getNamespace(el){if(el.prefix){return el.prefix;}else if(el.outerHTML){var regex=new RegExp("<([^:]+):"+el.tagName+"[^>]*>","i");if(regex.test(el.outerHTML)){return RegExp.$1.toLowerCase();}}

+return"";}

+var lt="<";var gt=">";if(includeRootNode&&rootNode.nodeType!=nodeTypes.DOCUMENT_FRAGMENT_NODE){switch(rootNode.nodeType){case nodeTypes.ELEMENT_NODE:var tagName=rootNode.tagName.toLowerCase();xhtml=startNewLine?newLine+indentation:"";xhtml+=lt;var prefix=getNamespace(rootNode);var hasPrefix=!!prefix;if(hasPrefix){xhtml+=prefix+":";}

+xhtml+=tagName;for(i=0,len=rootNode.attributes.length;i<len;i++){var currentAttr=rootNode.attributes[i];if(!currentAttr.specified||currentAttr.nodeValue===null||currentAttr.nodeName.toLowerCase()==="style"||typeof currentAttr.nodeValue!=="string"||currentAttr.nodeName.indexOf("_moz")===0){continue;}

+xhtml+=" "+currentAttr.nodeName.toLowerCase()+"=\"";xhtml+=fixAttributeValue(currentAttr.nodeValue);xhtml+="\"";}

+if(rootNode.style.cssText){var styleValue=getStyleAttributeValue(rootNode);if(styleValue!==""){xhtml+=" style=\""+getStyleAttributeValue(rootNode)+"\"";}}

+if(array_contains(emptyElements,tagName)||(hasPrefix&&!rootNode.hasChildNodes())){xhtml+="/"+gt;}else{xhtml+=gt;var childStartNewLine=!(rootNode.childNodes.length===1&&rootNode.childNodes[0].nodeType===nodeTypes.TEXT_NODE);var childPreformatted=array_contains(preFormattedElements,tagName);for(var i=0,len=rootNode.childNodes.length;i<len;i++){xhtml+=getXhtml(rootNode.childNodes[i],true,indentation+indentationUnit,childStartNewLine,childPreformatted);}

+var endTag=lt+"/"+tagName+gt;xhtml+=childStartNewLine?newLine+indentation+endTag:endTag;}

+return xhtml;case nodeTypes.TEXT_NODE:if(isWhitespace(rootNode)){xhtml="";}else{if(preformatted){xhtml=rootNode.nodeValue;}else{var lines=splitIntoLines(trim(rootNode.nodeValue));var trimmedLines=[];for(var i=0,len=lines.length;i<len;i++){trimmedLines[i]=trim(lines[i]);}

+xhtml=trimmedLines.join(newLine+indentation);}

+if(startNewLine){xhtml=newLine+indentation+xhtml;}}

+return xhtml;case nodeTypes.CDATA_SECTION_NODE:return"<![CDA"+"TA["+rootNode.nodeValue+"]"+"]>"+newLine;case nodeTypes.DOCUMENT_NODE:xhtml="";for(var i=0,len=rootNode.childNodes.length;i<len;i++){xhtml+=getXhtml(rootNode.childNodes[i],true,indentation);}

+return xhtml;default:return"";}}else{xhtml="";for(var i=0,len=rootNode.childNodes.length;i<len;i++){xhtml+=getXhtml(rootNode.childNodes[i],true,indentation+indentationUnit);}

+return xhtml;}}

+function createCommandLineFunctions(){ConsoleAppender.addGlobalCommandLineFunction("$",function(appender,args,returnValue){return document.getElementById(args[0]);});ConsoleAppender.addGlobalCommandLineFunction("dir",function(appender,args,returnValue){var lines=[];for(var i=0,len=args.length;i<len;i++){lines[i]=dir(args[i]);}

+return lines.join(newLine+newLine);});ConsoleAppender.addGlobalCommandLineFunction("dirxml",function(appender,args,returnValue){var lines=[];for(var i=0,len=args.length;i<len;i++){var win=appender.getCommandWindow();lines[i]=getXhtml(args[i]);}

+return lines.join(newLine+newLine);});ConsoleAppender.addGlobalCommandLineFunction("cd",function(appender,args,returnValue){var win,message;if(args.length===0||args[0]===""){win=window;message="Command line set to run in main window";}else{if(args[0].window==args[0]){win=args[0];message="Command line set to run in frame '"+args[0].name+"'";}else{win=window.frames[args[0]];if(win){message="Command line set to run in frame '"+args[0]+"'";}else{returnValue.isError=true;message="Frame '"+args[0]+"' does not exist";win=appender.getCommandWindow();}}}

+appender.setCommandWindow(win);return message;});ConsoleAppender.addGlobalCommandLineFunction("clear",function(appender,args,returnValue){returnValue.appendResult=false;appender.clear();});ConsoleAppender.addGlobalCommandLineFunction("keys",function(appender,args,returnValue){var keys=[];for(var k in args[0]){keys.push(k);}

+return keys;});ConsoleAppender.addGlobalCommandLineFunction("values",function(appender,args,returnValue){var values=[];for(var k in args[0]){try{values.push(args[0][k]);}catch(ex){logLog.warn("values(): Unable to obtain value for key "+k+". Details: "+getExceptionMessage(ex));}}

+return values;});ConsoleAppender.addGlobalCommandLineFunction("expansionDepth",function(appender,args,returnValue){var expansionDepth=parseInt(args[0],10);if(isNaN(expansionDepth)||expansionDepth<0){returnValue.isError=true;return""+args[0]+" is not a valid expansion depth";}else{appender.setCommandLineObjectExpansionDepth(expansionDepth);return"Object expansion depth set to "+expansionDepth;}});}

+function init(){createCommandLineFunctions();}

+init();})();log4javascript.setDocumentReady=function(){pageLoaded=true;log4javascript.dispatchEvent("load",{});};if(window.addEventListener){window.addEventListener("load",log4javascript.setDocumentReady,false);}else if(window.attachEvent){window.attachEvent("onload",log4javascript.setDocumentReady);}else{var oldOnload=window.onload;if(typeof window.onload!="function"){window.onload=log4javascript.setDocumentReady;}else{window.onload=function(evt){if(oldOnload){oldOnload(evt);}

+log4javascript.setDocumentReady();};}}

+window.log4javascript=log4javascript;return log4javascript;})();

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_lite.js b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_lite.js
new file mode 100644
index 0000000..b04ce8e
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_lite.js
@@ -0,0 +1,55 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}

+this.length--;return firstItem;}};}

+var log4javascript;(function(){var newLine="\r\n";function Log4JavaScript(){}

+log4javascript=new Log4JavaScript();log4javascript.version="1.4.6";log4javascript.edition="log4javascript_lite";function getExceptionMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}else{return String(ex);}}

+function getUrlFileName(url){var lastSlashIndex=Math.max(url.lastIndexOf("/"),url.lastIndexOf("\\"));return url.substr(lastSlashIndex+1);}

+function getExceptionStringRep(ex){if(ex){var exStr="Exception: "+getExceptionMessage(ex);try{if(ex.lineNumber){exStr+=" on line number "+ex.lineNumber;}

+if(ex.fileName){exStr+=" in file "+getUrlFileName(ex.fileName);}}catch(localEx){}

+if(showStackTraces&&ex.stack){exStr+=newLine+"Stack trace:"+newLine+ex.stack;}

+return exStr;}

+return null;}

+function isError(err){return(err instanceof Error);}

+function bool(obj){return Boolean(obj);}

+var enabled=(typeof log4javascript_disabled!="undefined")&&log4javascript_disabled?false:true;log4javascript.setEnabled=function(enable){enabled=bool(enable);};log4javascript.isEnabled=function(){return enabled;};var showStackTraces=false;log4javascript.setShowStackTraces=function(show){showStackTraces=bool(show);};var Level=function(level,name){this.level=level;this.name=name;};Level.prototype={toString:function(){return this.name;},equals:function(level){return this.level==level.level;},isGreaterOrEqual:function(level){return this.level>=level.level;}};Level.ALL=new Level(Number.MIN_VALUE,"ALL");Level.TRACE=new Level(10000,"TRACE");Level.DEBUG=new Level(20000,"DEBUG");Level.INFO=new Level(30000,"INFO");Level.WARN=new Level(40000,"WARN");Level.ERROR=new Level(50000,"ERROR");Level.FATAL=new Level(60000,"FATAL");Level.OFF=new Level(Number.MAX_VALUE,"OFF");log4javascript.Level=Level;function Appender(){var getConsoleHtmlLines=function(){return['<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">','<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">','<head>','<title>log4javascript</title>','<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />','<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->','<meta http-equiv="X-UA-Compatible" content="IE=7" />','<script type="text/javascript">','//<![CDATA[','var loggingEnabled=true;var messagesBeforeDocLoaded=[];function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}','function setLoggingEnabled(enable){loggingEnabled=enable;}','function scrollToLatestEntry(){var l=getLogContainer();if(typeof l.scrollTop!="undefined"){var latestLogEntry=l.lastChild;if(latestLogEntry){l.scrollTop=l.scrollHeight;}}}','function log(logLevel,formattedMessage){if(loggingEnabled){if(loaded){doLog(logLevel,formattedMessage);}else{messagesBeforeDocLoaded.push([logLevel,formattedMessage]);}}}','function doLog(logLevel,formattedMessage){var logEntry=document.createElement("div");logEntry.appendChild(document.createTextNode(formattedMessage));logEntry.className="logentry "+logLevel.name;getLogContainer().appendChild(logEntry);scrollToLatestEntry();}','function mainPageReloaded(){var separator=document.createElement("div");separator.className="separator";separator.innerHTML="&nbsp;";getLogContainer().appendChild(separator);}','var loaded=false;var logLevels=["DEBUG","INFO","WARN","ERROR","FATAL"];window.onload=function(){setLogContainerHeight();toggleLoggingEnabled();for(var i=0;i<messagesBeforeDocLoaded.length;i++){doLog(messagesBeforeDocLoaded[i][0],messagesBeforeDocLoaded[i][1]);}','messagesBeforeDocLoaded=[];loaded=true;setTimeout(setLogContainerHeight,20);};function getLogContainer(){return $("log");}','function clearLog(){getLogContainer().innerHTML="";}','function $(id){return document.getElementById(id);}','function getWindowHeight(){if(window.innerHeight){return window.innerHeight;}else if(document.documentElement&&document.documentElement.clientHeight){return document.documentElement.clientHeight;}else if(document.body){return document.body.clientHeight;}','return 0;}','function getChromeHeight(){return $("toolbar").offsetHeight;}','function setLogContainerHeight(){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";getLogContainer().style.height=""+','Math.max(0,windowHeight-getChromeHeight())+"px";}','window.onresize=function(){setLogContainerHeight();};','//]]>','</script>','<style type="text/css">','body{background-color:white;color:black;padding:0;margin:0;font-family:tahoma,verdana,arial,helvetica,sans-serif;overflow:hidden}div#toolbar{border-top:solid #ffffff 1px;border-bottom:solid #aca899 1px;background-color:#f1efe7;padding:3px 5px;font-size:68.75%}div#toolbar input.button{padding:0 5px;font-size:100%}div#log{font-family:Courier New,Courier;font-size:75%;width:100%;overflow:auto;clear:both}*.logentry{overflow:visible;white-space:pre}*.TRACE{color:#666666}*.DEBUG{color:green}*.INFO{color:#000099}*.WARN{color:#999900}*.ERROR{color:red}*.FATAL{color:#660066}div#log div.separator{background-color:#cccccc;margin:5px 0;line-height:1px}','</style>','</head>','<body id="body">','<div id="toolbar">','Options:','<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" class="stateful" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Enable logging</label>','<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="stateful button" title="Clear all log messages"  />','<input type="button" id="closeButton" value="Close" onclick="window.close()" class="stateful button" title="Close the window" />','</div>','<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>','</body>','</html>'];};var popUp=null;var popUpsBlocked=false;var popUpClosed=false;var popUpLoaded=false;var complainAboutPopUpBlocking=true;var initialized=false;var isSupported=true;var width=600;var height=400;var focusPopUp=false;var queuedLoggingEvents=new Array();function isLoaded(win){try{return bool(win.loaded);}catch(ex){return false;}}

+function finalInit(){popUpLoaded=true;appendQueuedLoggingEvents();}

+function writeHtml(doc){var lines=getConsoleHtmlLines();doc.open();for(var i=0,len=lines.length;i<len;i++){doc.writeln(lines[i]);}

+doc.close();}

+function pollConsoleWindow(){function pollConsoleWindowLoaded(){if(popUpLoaded){clearInterval(poll);}else if(bool(popUp)&&isLoaded(popUp)){clearInterval(poll);finalInit();}}

+var poll=setInterval(pollConsoleWindowLoaded,100);}

+function init(){var windowProperties="width="+width+",height="+height+",status,resizable";var windowName="log4javascriptLitePopUp"+location.host.replace(/[^a-z0-9]/gi,"_");popUp=window.open("",windowName,windowProperties);popUpClosed=false;if(popUp){if(isLoaded(popUp)){popUp.mainPageReloaded();finalInit();}else{writeHtml(popUp.document);if(isLoaded(popUp)){finalInit();}else{pollConsoleWindow();}}}else{isSupported=false;if(complainAboutPopUpBlocking){alert("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");}}

+initialized=true;}

+function safeToAppend(){if(!popUpsBlocked&&!popUpClosed){if(popUp.closed){popUpClosed=true;return false;}

+if(!popUpLoaded&&popUp.loaded){popUpLoaded=true;}}

+return!popUpsBlocked&&popUpLoaded&&!popUpClosed;}

+function padWithZeroes(num,len){var str=""+num;while(str.length<len){str="0"+str;}

+return str;}

+function padWithSpaces(str,len){while(str.length<len){str+=" ";}

+return str;}

+this.append=function(loggingEvent){if(!initialized){init();}

+queuedLoggingEvents.push(loggingEvent);if(safeToAppend()){appendQueuedLoggingEvents();}};function appendQueuedLoggingEvents(){if(safeToAppend()){while(queuedLoggingEvents.length>0){var currentLoggingEvent=queuedLoggingEvents.shift();var date=currentLoggingEvent.timeStamp;var formattedDate=padWithZeroes(date.getHours(),2)+":"+

+padWithZeroes(date.getMinutes(),2)+":"+padWithZeroes(date.getSeconds(),2);var formattedMessage=formattedDate+" "+padWithSpaces(currentLoggingEvent.level.name,5)+" - "+currentLoggingEvent.getCombinedMessages();var throwableStringRep=currentLoggingEvent.getThrowableStrRep();if(throwableStringRep){formattedMessage+=newLine+throwableStringRep;}

+popUp.log(currentLoggingEvent.level,formattedMessage);}

+if(focusPopUp){popUp.focus();}}}}

+log4javascript.Appender=Appender;function Logger(){var appender=new Appender();var loggerLevel=Level.ALL;this.log=function(level,params){if(enabled&&level.isGreaterOrEqual(this.getLevel())){var exception;var finalParamIndex=params.length-1;var lastParam=params[params.length-1];if(params.length>1&&isError(lastParam)){exception=lastParam;finalParamIndex--;}

+var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];}

+var loggingEvent=new LoggingEvent(this,new Date(),level,messages,exception);appender.append(loggingEvent);}};this.setLevel=function(level){loggerLevel=level;};this.getLevel=function(){return loggerLevel;};}

+Logger.prototype={trace:function(){this.log(Level.TRACE,arguments);},debug:function(){this.log(Level.DEBUG,arguments);},info:function(){this.log(Level.INFO,arguments);},warn:function(){this.log(Level.WARN,arguments);},error:function(){this.log(Level.ERROR,arguments);},fatal:function(){this.log(Level.FATAL,arguments);},isEnabledFor:function(level){return level.isGreaterOrEqual(this.getLevel());},isTraceEnabled:function(){return this.isEnabledFor(Level.TRACE);},isDebugEnabled:function(){return this.isEnabledFor(Level.DEBUG);},isInfoEnabled:function(){return this.isEnabledFor(Level.INFO);},isWarnEnabled:function(){return this.isEnabledFor(Level.WARN);},isErrorEnabled:function(){return this.isEnabledFor(Level.ERROR);},isFatalEnabled:function(){return this.isEnabledFor(Level.FATAL);}};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=new Logger();}

+return defaultLogger;};log4javascript.getLogger=log4javascript.getDefaultLogger;var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger();nullLogger.setLevel(Level.OFF);}

+return nullLogger;};var LoggingEvent=function(logger,timeStamp,level,messages,exception){this.logger=logger;this.timeStamp=timeStamp;this.level=level;this.messages=messages;this.exception=exception;};LoggingEvent.prototype={getThrowableStrRep:function(){return this.exception?getExceptionStringRep(this.exception):"";},getCombinedMessages:function(){return(this.messages.length===1)?this.messages[0]:this.messages.join(newLine);}};log4javascript.LoggingEvent=LoggingEvent;window.log4javascript=log4javascript;})();

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_lite_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_lite_uncompressed.js
new file mode 100644
index 0000000..12e97d8
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_lite_uncompressed.js
@@ -0,0 +1,620 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+if (!Array.prototype.shift) {

+	Array.prototype.shift = function() {

+		if (this.length > 0) {

+			var firstItem = this[0];

+			for (var i = 0, len = this.length - 1; i < len; i++) {

+				this[i] = this[i + 1];

+			}

+			this.length--;

+			return firstItem;

+		}

+	};

+}

+

+var log4javascript;

+

+(function() {

+	var newLine = "\r\n";

+	function Log4JavaScript() {}

+	log4javascript = new Log4JavaScript();

+	log4javascript.version = "1.4.6";

+	log4javascript.edition = "log4javascript_lite";

+

+	function getExceptionMessage(ex) {

+		if (ex.message) {

+			return ex.message;

+		} else if (ex.description) {

+			return ex.description;

+		} else {

+			return String(ex);

+		}

+	}

+

+	// Gets the portion of the URL after the last slash

+	function getUrlFileName(url) {

+		var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\"));

+		return url.substr(lastSlashIndex + 1);

+	}

+

+	// Returns a nicely formatted representation of an error

+	function getExceptionStringRep(ex) {

+		if (ex) {

+			var exStr = "Exception: " + getExceptionMessage(ex);

+			try {

+				if (ex.lineNumber) {

+					exStr += " on line number " + ex.lineNumber;

+				}

+				if (ex.fileName) {

+					exStr += " in file " + getUrlFileName(ex.fileName);

+				}

+			} catch (localEx) {

+			}

+			if (showStackTraces && ex.stack) {

+				exStr += newLine + "Stack trace:" + newLine + ex.stack;

+			}

+			return exStr;

+		}

+		return null;

+	}

+

+	function isError(err) {

+		return (err instanceof Error);

+	}

+

+	function bool(obj) {

+		return Boolean(obj);

+	}

+

+	var enabled = (typeof log4javascript_disabled != "undefined") &&

+		log4javascript_disabled ? false : true;

+

+	log4javascript.setEnabled = function(enable) {

+		enabled = bool(enable);

+	};

+

+	log4javascript.isEnabled = function() {

+		return enabled;

+	};

+

+	var showStackTraces = false;

+

+	log4javascript.setShowStackTraces = function(show) {

+		showStackTraces = bool(show);

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Levels

+

+	var Level = function(level, name) {

+		this.level = level;

+		this.name = name;

+	};

+

+	Level.prototype = {

+		toString: function() {

+			return this.name;

+		},

+		equals: function(level) {

+			return this.level == level.level;

+		},

+		isGreaterOrEqual: function(level) {

+			return this.level >= level.level;

+		}

+	};

+

+	Level.ALL = new Level(Number.MIN_VALUE, "ALL");

+	Level.TRACE = new Level(10000, "TRACE");

+	Level.DEBUG = new Level(20000, "DEBUG");

+	Level.INFO = new Level(30000, "INFO");

+	Level.WARN = new Level(40000, "WARN");

+	Level.ERROR = new Level(50000, "ERROR");

+	Level.FATAL = new Level(60000, "FATAL");

+	Level.OFF = new Level(Number.MAX_VALUE, "OFF");

+

+	log4javascript.Level = Level;

+

+	/* ---------------------------------------------------------------------- */

+	// Appenders

+

+	function Appender() {

+		var getConsoleHtmlLines = function() {

+			return [

+'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',

+'<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">',

+'	<head>',

+'		<title>log4javascript</title>',

+'		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',

+'		<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->',

+'		<meta http-equiv="X-UA-Compatible" content="IE=7" />',

+'		<script type="text/javascript">',

+'			//<![CDATA[',

+'			var loggingEnabled = true;',

+'			var messagesBeforeDocLoaded = [];',

+'',

+'			function toggleLoggingEnabled() {',

+'				setLoggingEnabled($("enableLogging").checked);',

+'			}',

+'',

+'			function setLoggingEnabled(enable) {',

+'				loggingEnabled = enable;',

+'			}',

+'',

+'			function scrollToLatestEntry() {',

+'				var l = getLogContainer();',

+'				if (typeof l.scrollTop != "undefined") {',

+'					var latestLogEntry = l.lastChild;',

+'					if (latestLogEntry) {',

+'						l.scrollTop = l.scrollHeight;',

+'					}',

+'				}',

+'			}',

+'',

+'			function log(logLevel, formattedMessage) {',

+'				if (loggingEnabled) {',

+'					if (loaded) {',

+'						doLog(logLevel, formattedMessage);',

+'					} else {',

+'						messagesBeforeDocLoaded.push([logLevel, formattedMessage]);',

+'					}',

+'				}',

+'			}',

+'',

+'			function doLog(logLevel, formattedMessage) {',

+'				var logEntry = document.createElement("div");',

+'				logEntry.appendChild(document.createTextNode(formattedMessage));',

+'				logEntry.className = "logentry " + logLevel.name;',

+'				getLogContainer().appendChild(logEntry);',

+'				scrollToLatestEntry();',

+'			}',

+'',

+'			function mainPageReloaded() {',

+'				var separator = document.createElement("div");',

+'				separator.className = "separator";',

+'				separator.innerHTML = "&nbsp;";',

+'				getLogContainer().appendChild(separator);',

+'			}',

+'',

+'			var loaded = false;',

+'			var logLevels = ["DEBUG", "INFO", "WARN", "ERROR", "FATAL"];',

+'',

+'			window.onload = function() {',

+'				setLogContainerHeight();',

+'				toggleLoggingEnabled();',

+'				for (var i = 0; i < messagesBeforeDocLoaded.length; i++) {',

+'					doLog(messagesBeforeDocLoaded[i][0], messagesBeforeDocLoaded[i][1]);',

+'				}',

+'				messagesBeforeDocLoaded = [];',

+'				loaded = true;',

+'',

+'				// Workaround to make sure log div starts at the correct size',

+'				setTimeout(setLogContainerHeight, 20);',

+'			};',

+'',

+'			function getLogContainer() {',

+'				return $("log");',

+'			}',

+'',

+'			function clearLog() {',

+'				getLogContainer().innerHTML = "";',

+'			}',

+'',

+'			/* ------------------------------------------------------------------------- */',

+'',

+'			// Other utility functions',

+'',

+'			// Syntax borrowed from Prototype library',

+'			function $(id) {',

+'				return document.getElementById(id);',

+'			}',

+'',

+'			function getWindowHeight() {',

+'				if (window.innerHeight) {',

+'					return window.innerHeight;',

+'				} else if (document.documentElement && document.documentElement.clientHeight) {',

+'					return document.documentElement.clientHeight;',

+'				} else if (document.body) {',

+'					return document.body.clientHeight;',

+'				}',

+'				return 0;',

+'			}',

+'',

+'			function getChromeHeight() {',

+'				return $("toolbar").offsetHeight;',

+'			}',

+'',

+'			function setLogContainerHeight() {',

+'				var windowHeight = getWindowHeight();',

+'				$("body").style.height = getWindowHeight() + "px";',

+'				getLogContainer().style.height = "" +',

+'					Math.max(0, windowHeight - getChromeHeight()) + "px";',

+'			}',

+'',

+'			window.onresize = function() {',

+'				setLogContainerHeight();',

+'			};',

+'',

+'			//]]>',

+'		</script>',

+'		<style type="text/css">',

+'			body {',

+'				background-color: white;',

+'				color: black;',

+'				padding: 0;',

+'				margin: 0;',

+'				font-family: tahoma, verdana, arial, helvetica, sans-serif;',

+'				overflow: hidden;',

+'			}',

+'			',

+'			div#toolbar {',

+'				border-top: solid #ffffff 1px;',

+'				border-bottom: solid #aca899 1px;',

+'				background-color: #f1efe7;',

+'				padding: 3px 5px;',

+'				font-size: 68.75%;',

+'			}',

+'',

+'			div#toolbar input.button {',

+'				padding: 0 5px;',

+'				font-size: 100%;',

+'			}',

+'',

+'			div#log {',

+'				font-family: Courier New, Courier;',

+'				font-size: 75%;',

+'				width: 100%;',

+'				overflow: auto;',

+'				clear: both;',

+'			}',

+'',

+'			*.logentry {',

+'				overflow: visible;',

+'				white-space: pre;',

+'			}',

+'',

+'			*.TRACE {',

+'				color: #666666;',

+'			}',

+'',

+'			*.DEBUG {',

+'				color: green;',

+'			}',

+'',

+'			*.INFO {',

+'				color: #000099;',

+'			}',

+'',

+'			*.WARN {',

+'				color: #999900;',

+'			}',

+'',

+'			*.ERROR {',

+'				color: red;',

+'			}',

+'',

+'			*.FATAL {',

+'				color: #660066;',

+'			}',

+'',

+'			div#log div.separator {',

+'				background-color: #cccccc;',

+'				margin: 5px 0;',

+'				line-height: 1px;',

+'			}',

+'		</style>',

+'	</head>',

+'',

+'	<body id="body">',

+'		<div id="toolbar">',

+'			Options:',

+'			<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" class="stateful" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Enable logging</label>',

+'			<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="stateful button" title="Clear all log messages"  />',

+'			<input type="button" id="closeButton" value="Close" onclick="window.close()" class="stateful button" title="Close the window" />',

+'		</div>',

+'		<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>',

+'	</body>',

+'</html>'

+];

+		};

+

+		var popUp = null;

+		var popUpsBlocked = false;

+		var popUpClosed = false;

+		var popUpLoaded = false;

+		var complainAboutPopUpBlocking = true;

+		var initialized = false;

+		var isSupported = true;

+		var width = 600;

+		var height = 400;

+		var focusPopUp = false;

+		var queuedLoggingEvents = new Array();

+

+		function isLoaded(win) {

+			try {

+				return bool(win.loaded);

+			} catch (ex) {

+				return false;

+			}

+		}

+

+		function finalInit() {

+			popUpLoaded = true;

+			appendQueuedLoggingEvents();

+		}

+

+		function writeHtml(doc) {

+			var lines = getConsoleHtmlLines();

+			doc.open();

+			for (var i = 0, len = lines.length; i < len; i++) {

+				doc.writeln(lines[i]);

+			}

+			doc.close();

+		}

+

+		function pollConsoleWindow() {

+			function pollConsoleWindowLoaded() {

+				if (popUpLoaded) {

+					clearInterval(poll);

+				} else if (bool(popUp) && isLoaded(popUp)) {

+					clearInterval(poll);

+					finalInit();

+				}

+			}

+

+			// Poll the pop-up since the onload event is not reliable

+			var poll = setInterval(pollConsoleWindowLoaded, 100);

+		}

+

+		function init() {

+			var windowProperties = "width=" + width + ",height=" + height + ",status,resizable";

+			var windowName = "log4javascriptLitePopUp" + location.host.replace(/[^a-z0-9]/gi, "_");

+

+			popUp = window.open("", windowName, windowProperties);

+			popUpClosed = false;

+			if (popUp) {

+				if (isLoaded(popUp)) {

+					popUp.mainPageReloaded();

+					finalInit();

+				} else {

+					writeHtml(popUp.document);

+

+					// Check if the pop-up window object is available

+					if (isLoaded(popUp)) {

+						finalInit();

+					} else {

+						pollConsoleWindow();

+					}

+				}

+			} else {

+				isSupported = false;

+				if (complainAboutPopUpBlocking) {

+					alert("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");

+				}

+			}

+			initialized = true;

+		}

+

+		function safeToAppend() {

+			if (!popUpsBlocked && !popUpClosed) {

+				if (popUp.closed) {

+					popUpClosed = true;

+					return false;

+				}

+				if (!popUpLoaded && popUp.loaded) {

+					popUpLoaded = true;

+				}

+			}

+			return !popUpsBlocked && popUpLoaded && !popUpClosed;

+		}

+

+		function padWithZeroes(num, len) {

+			var str = "" + num;

+			while (str.length < len) {

+				str = "0" + str;

+			}

+			return str;

+		}

+

+		function padWithSpaces(str, len) {

+			while (str.length < len) {

+				str += " ";

+			}

+			return str;

+		}

+

+		this.append = function(loggingEvent) {

+			if (!initialized) {

+				init();

+			}

+			queuedLoggingEvents.push(loggingEvent);

+			if (safeToAppend()) {

+				appendQueuedLoggingEvents();

+			}

+		};

+

+		function appendQueuedLoggingEvents() {

+			if (safeToAppend()) {

+				while (queuedLoggingEvents.length > 0) {

+					var currentLoggingEvent = queuedLoggingEvents.shift();

+					var date = currentLoggingEvent.timeStamp;

+					var formattedDate = padWithZeroes(date.getHours(), 2) + ":" +

+						padWithZeroes(date.getMinutes(), 2) + ":" + padWithZeroes(date.getSeconds(), 2);

+					var formattedMessage = formattedDate + " " + padWithSpaces(currentLoggingEvent.level.name, 5) +

+						" - " + currentLoggingEvent.getCombinedMessages();

+					var throwableStringRep = currentLoggingEvent.getThrowableStrRep();

+					if (throwableStringRep) {

+						formattedMessage += newLine + throwableStringRep;

+					}

+					popUp.log(currentLoggingEvent.level, formattedMessage);

+				}

+				if (focusPopUp) {

+					popUp.focus();

+				}

+			}

+		}

+	}

+

+	log4javascript.Appender = Appender;

+

+	/* ---------------------------------------------------------------------- */

+	// Loggers

+

+	function Logger() {

+		var appender = new Appender();

+		var loggerLevel = Level.ALL;

+

+		this.log = function(level, params) {

+			if (enabled && level.isGreaterOrEqual(this.getLevel())) {

+				// Check whether last param is an exception

+				var exception;

+				var finalParamIndex = params.length - 1;

+				var lastParam = params[params.length - 1];

+				if (params.length > 1 && isError(lastParam)) {

+					exception = lastParam;

+					finalParamIndex--;

+				}

+

+				// Construct genuine array for the params

+				var messages = [];

+				for (var i = 0; i <= finalParamIndex; i++) {

+					messages[i] = params[i];

+				}

+

+				var loggingEvent = new LoggingEvent(

+					this, new Date(), level, messages, exception);

+

+				appender.append(loggingEvent);

+			}

+		};

+

+		this.setLevel = function(level) {

+			loggerLevel = level;

+		};

+

+		this.getLevel = function() {

+			return loggerLevel;

+		};

+	}

+

+	Logger.prototype = {

+		trace: function() {

+			this.log(Level.TRACE, arguments);

+		},

+

+		debug: function() {

+			this.log(Level.DEBUG, arguments);

+		},

+

+		info: function() {

+			this.log(Level.INFO, arguments);

+		},

+

+		warn: function() {

+			this.log(Level.WARN, arguments);

+		},

+

+		error: function() {

+			this.log(Level.ERROR, arguments);

+		},

+

+		fatal: function() {

+			this.log(Level.FATAL, arguments);

+		},

+

+		isEnabledFor: function(level) {

+			return level.isGreaterOrEqual(this.getLevel());

+		},

+

+		isTraceEnabled: function() {

+			return this.isEnabledFor(Level.TRACE);

+		},

+

+		isDebugEnabled: function() {

+			return this.isEnabledFor(Level.DEBUG);

+		},

+

+		isInfoEnabled: function() {

+			return this.isEnabledFor(Level.INFO);

+		},

+

+		isWarnEnabled: function() {

+			return this.isEnabledFor(Level.WARN);

+		},

+

+		isErrorEnabled: function() {

+			return this.isEnabledFor(Level.ERROR);

+		},

+

+		isFatalEnabled: function() {

+			return this.isEnabledFor(Level.FATAL);

+		}

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Logger access methods

+

+	var defaultLogger = null;

+	log4javascript.getDefaultLogger = function() {

+		if (!defaultLogger) {

+			defaultLogger = new Logger();

+		}

+		return defaultLogger;

+	};

+

+	log4javascript.getLogger = log4javascript.getDefaultLogger;

+

+	var nullLogger = null;

+	log4javascript.getNullLogger = function() {

+		if (!nullLogger) {

+			nullLogger = new Logger();

+			nullLogger.setLevel(Level.OFF);

+		}

+		return nullLogger;

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Logging events

+

+	var LoggingEvent = function(logger, timeStamp, level, messages,

+			exception) {

+		this.logger = logger;

+		this.timeStamp = timeStamp;

+		this.level = level;

+		this.messages = messages;

+		this.exception = exception;

+	};

+

+	LoggingEvent.prototype = {

+		getThrowableStrRep: function() {

+			return this.exception ?

+				getExceptionStringRep(this.exception) : "";

+		},

+

+		getCombinedMessages: function() {

+			return (this.messages.length === 1) ? this.messages[0] :

+				   this.messages.join(newLine);

+		}

+	};

+

+	log4javascript.LoggingEvent = LoggingEvent;

+

+	// Ensure that the log4javascript object is available in the window. This

+	// is necessary for log4javascript to be available in IE if loaded using

+	// Dojo's module system

+	window.log4javascript = log4javascript;

+})();
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_production.js b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_production.js
new file mode 100644
index 0000000..1a31299
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_production.js
@@ -0,0 +1,188 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}

+return this.length;};}

+if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}

+this.length=this.length-1;return firstItem;}};}

+if(!Array.prototype.splice){Array.prototype.splice=function(startIndex,deleteCount){var itemsAfterDeleted=this.slice(startIndex+deleteCount);var itemsDeleted=this.slice(startIndex,startIndex+deleteCount);this.length=startIndex;var argumentsArray=[];for(var i=0,len=arguments.length;i<len;i++){argumentsArray[i]=arguments[i];}

+var itemsToAppend=(argumentsArray.length>2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i<len;i++){this.push(itemsToAppend[i]);}

+return itemsDeleted;};}

+var log4javascript=(function(){function isUndefined(obj){return typeof obj=="undefined";}

+function EventSupport(){}

+EventSupport.prototype={eventTypes:[],eventListeners:{},setEventTypes:function(eventTypesParam){if(eventTypesParam instanceof Array){this.eventTypes=eventTypesParam;this.eventListeners={};for(var i=0,len=this.eventTypes.length;i<len;i++){this.eventListeners[this.eventTypes[i]]=[];}}else{handleError("log4javascript.EventSupport ["+this+"]: setEventTypes: eventTypes parameter must be an Array");}},addEventListener:function(eventType,listener){if(typeof listener=="function"){if(!array_contains(this.eventTypes,eventType)){handleError("log4javascript.EventSupport ["+this+"]: addEventListener: no event called '"+eventType+"'");}

+this.eventListeners[eventType].push(listener);}else{handleError("log4javascript.EventSupport ["+this+"]: addEventListener: listener must be a function");}},removeEventListener:function(eventType,listener){if(typeof listener=="function"){if(!array_contains(this.eventTypes,eventType)){handleError("log4javascript.EventSupport ["+this+"]: removeEventListener: no event called '"+eventType+"'");}

+array_remove(this.eventListeners[eventType],listener);}else{handleError("log4javascript.EventSupport ["+this+"]: removeEventListener: listener must be a function");}},dispatchEvent:function(eventType,eventArgs){if(array_contains(this.eventTypes,eventType)){var listeners=this.eventListeners[eventType];for(var i=0,len=listeners.length;i<len;i++){listeners[i](this,eventType,eventArgs);}}else{handleError("log4javascript.EventSupport ["+this+"]: dispatchEvent: no event called '"+eventType+"'");}}};var applicationStartDate=new Date();var uniqueId="log4javascript_"+applicationStartDate.getTime()+"_"+

+Math.floor(Math.random()*100000000);var emptyFunction=function(){};var newLine="\r\n";var pageLoaded=false;function Log4JavaScript(){}

+Log4JavaScript.prototype=new EventSupport();log4javascript=new Log4JavaScript();log4javascript.version="1.4.6";log4javascript.edition="log4javascript_production";function toStr(obj){if(obj&&obj.toString){return obj.toString();}else{return String(obj);}}

+function getExceptionMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}else{return toStr(ex);}}

+function getUrlFileName(url){var lastSlashIndex=Math.max(url.lastIndexOf("/"),url.lastIndexOf("\\"));return url.substr(lastSlashIndex+1);}

+function getExceptionStringRep(ex){if(ex){var exStr="Exception: "+getExceptionMessage(ex);try{if(ex.lineNumber){exStr+=" on line number "+ex.lineNumber;}

+if(ex.fileName){exStr+=" in file "+getUrlFileName(ex.fileName);}}catch(localEx){logLog.warn("Unable to obtain file and line information for error");}

+if(showStackTraces&&ex.stack){exStr+=newLine+"Stack trace:"+newLine+ex.stack;}

+return exStr;}

+return null;}

+function bool(obj){return Boolean(obj);}

+function trim(str){return str.replace(/^\s+/,"").replace(/\s+$/,"");}

+function splitIntoLines(text){var text2=text.replace(/\r\n/g,"\n").replace(/\r/g,"\n");return text2.split("\n");}

+var urlEncode=(typeof window.encodeURIComponent!="undefined")?function(str){return encodeURIComponent(str);}:function(str){return escape(str).replace(/\+/g,"%2B").replace(/"/g,"%22").replace(/'/g,"%27").replace(/\//g,"%2F").replace(/=/g,"%3D");};var urlDecode=(typeof window.decodeURIComponent!="undefined")?function(str){return decodeURIComponent(str);}:function(str){return unescape(str).replace(/%2B/g,"+").replace(/%22/g,"\"").replace(/%27/g,"'").replace(/%2F/g,"/").replace(/%3D/g,"=");};function array_remove(arr,val){var index=-1;for(var i=0,len=arr.length;i<len;i++){if(arr[i]===val){index=i;break;}}

+if(index>=0){arr.splice(index,1);return true;}else{return false;}}

+function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}

+return false;}

+function extractBooleanFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return bool(param);}}

+function extractStringFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return String(param);}}

+function extractIntFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{try{var value=parseInt(param,10);return isNaN(value)?defaultValue:value;}catch(ex){logLog.warn("Invalid int param "+param,ex);return defaultValue;}}}

+function extractFunctionFromParam(param,defaultValue){if(typeof param=="function"){return param;}else{return defaultValue;}}

+function isError(err){return(err instanceof Error);}

+if(!Function.prototype.apply){Function.prototype.apply=function(obj,args){var methodName="__apply__";if(typeof obj[methodName]!="undefined"){methodName+=String(Math.random()).substr(2);}

+obj[methodName]=this;var argsStrings=[];for(var i=0,len=args.length;i<len;i++){argsStrings[i]="args["+i+"]";}

+var script="obj."+methodName+"("+argsStrings.join(",")+")";var returnValue=eval(script);delete obj[methodName];return returnValue;};}

+if(!Function.prototype.call){Function.prototype.call=function(obj){var args=[];for(var i=1,len=arguments.length;i<len;i++){args[i-1]=arguments[i];}

+return this.apply(obj,args);};}

+function getListenersPropertyName(eventName){return"__log4javascript_listeners__"+eventName;}

+function addEvent(node,eventName,listener,useCapture,win){win=win?win:window;if(node.addEventListener){node.addEventListener(eventName,listener,useCapture);}else if(node.attachEvent){node.attachEvent("on"+eventName,listener);}else{var propertyName=getListenersPropertyName(eventName);if(!node[propertyName]){node[propertyName]=[];node["on"+eventName]=function(evt){evt=getEvent(evt,win);var listenersPropertyName=getListenersPropertyName(eventName);var listeners=this[listenersPropertyName].concat([]);var currentListener;while((currentListener=listeners.shift())){currentListener.call(this,evt);}};}

+node[propertyName].push(listener);}}

+function removeEvent(node,eventName,listener,useCapture){if(node.removeEventListener){node.removeEventListener(eventName,listener,useCapture);}else if(node.detachEvent){node.detachEvent("on"+eventName,listener);}else{var propertyName=getListenersPropertyName(eventName);if(node[propertyName]){array_remove(node[propertyName],listener);}}}

+function getEvent(evt,win){win=win?win:window;return evt?evt:win.event;}

+function stopEventPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}

+evt.returnValue=false;}

+var logLog={quietMode:false,debugMessages:[],setQuietMode:function(quietMode){this.quietMode=bool(quietMode);},numberOfErrors:0,alertAllErrors:false,setAlertAllErrors:function(alertAllErrors){this.alertAllErrors=alertAllErrors;},debug:function(message){this.debugMessages.push(message);},displayDebug:function(){alert(this.debugMessages.join(newLine));},warn:function(message,exception){},error:function(message,exception){if(++this.numberOfErrors==1||this.alertAllErrors){if(!this.quietMode){var alertMessage="log4javascript error: "+message;if(exception){alertMessage+=newLine+newLine+"Original error: "+getExceptionStringRep(exception);}

+alert(alertMessage);}}}};log4javascript.logLog=logLog;log4javascript.setEventTypes(["load","error"]);function handleError(message,exception){logLog.error(message,exception);log4javascript.dispatchEvent("error",{"message":message,"exception":exception});}

+log4javascript.handleError=handleError;var enabled=!((typeof log4javascript_disabled!="undefined")&&log4javascript_disabled);log4javascript.setEnabled=function(enable){enabled=bool(enable);};log4javascript.isEnabled=function(){return enabled;};var useTimeStampsInMilliseconds=true;log4javascript.setTimeStampsInMilliseconds=function(timeStampsInMilliseconds){useTimeStampsInMilliseconds=bool(timeStampsInMilliseconds);};log4javascript.isTimeStampsInMilliseconds=function(){return useTimeStampsInMilliseconds;};log4javascript.evalInScope=function(expr){return eval(expr);};var showStackTraces=false;log4javascript.setShowStackTraces=function(show){showStackTraces=bool(show);};var Level=function(level,name){this.level=level;this.name=name;};Level.prototype={toString:function(){return this.name;},equals:function(level){return this.level==level.level;},isGreaterOrEqual:function(level){return this.level>=level.level;}};Level.ALL=new Level(Number.MIN_VALUE,"ALL");Level.TRACE=new Level(10000,"TRACE");Level.DEBUG=new Level(20000,"DEBUG");Level.INFO=new Level(30000,"INFO");Level.WARN=new Level(40000,"WARN");Level.ERROR=new Level(50000,"ERROR");Level.FATAL=new Level(60000,"FATAL");Level.OFF=new Level(Number.MAX_VALUE,"OFF");log4javascript.Level=Level;function Timer(name,level){this.name=name;this.level=isUndefined(level)?Level.INFO:level;this.start=new Date();}

+Timer.prototype.getElapsedTime=function(){return new Date().getTime()-this.start.getTime();};var anonymousLoggerName="[anonymous]";var defaultLoggerName="[default]";var nullLoggerName="[null]";var rootLoggerName="root";function Logger(name){this.name=name;this.parent=null;this.children=[];var appenders=[];var loggerLevel=null;var isRoot=(this.name===rootLoggerName);var isNull=(this.name===nullLoggerName);var appenderCache=null;var appenderCacheInvalidated=false;this.addChild=function(childLogger){this.children.push(childLogger);childLogger.parent=this;childLogger.invalidateAppenderCache();};var additive=true;this.getAdditivity=function(){return additive;};this.setAdditivity=function(additivity){var valueChanged=(additive!=additivity);additive=additivity;if(valueChanged){this.invalidateAppenderCache();}};this.addAppender=function(appender){if(isNull){handleError("Logger.addAppender: you may not add an appender to the null logger");}else{if(appender instanceof log4javascript.Appender){if(!array_contains(appenders,appender)){appenders.push(appender);appender.setAddedToLogger(this);this.invalidateAppenderCache();}}else{handleError("Logger.addAppender: appender supplied ('"+

+toStr(appender)+"') is not a subclass of Appender");}}};this.removeAppender=function(appender){array_remove(appenders,appender);appender.setRemovedFromLogger(this);this.invalidateAppenderCache();};this.removeAllAppenders=function(){var appenderCount=appenders.length;if(appenderCount>0){for(var i=0;i<appenderCount;i++){appenders[i].setRemovedFromLogger(this);}

+appenders.length=0;this.invalidateAppenderCache();}};this.getEffectiveAppenders=function(){if(appenderCache===null||appenderCacheInvalidated){var parentEffectiveAppenders=(isRoot||!this.getAdditivity())?[]:this.parent.getEffectiveAppenders();appenderCache=parentEffectiveAppenders.concat(appenders);appenderCacheInvalidated=false;}

+return appenderCache;};this.invalidateAppenderCache=function(){appenderCacheInvalidated=true;for(var i=0,len=this.children.length;i<len;i++){this.children[i].invalidateAppenderCache();}};this.log=function(level,params){if(enabled&&level.isGreaterOrEqual(this.getEffectiveLevel())){var exception;var finalParamIndex=params.length-1;var lastParam=params[finalParamIndex];if(params.length>1&&isError(lastParam)){exception=lastParam;finalParamIndex--;}

+var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];}

+var loggingEvent=new LoggingEvent(this,new Date(),level,messages,exception);this.callAppenders(loggingEvent);}};this.callAppenders=function(loggingEvent){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].doAppend(loggingEvent);}};this.setLevel=function(level){if(isRoot&&level===null){handleError("Logger.setLevel: you cannot set the level of the root logger to null");}else if(level instanceof Level){loggerLevel=level;}else{handleError("Logger.setLevel: level supplied to logger "+

+this.name+" is not an instance of log4javascript.Level");}};this.getLevel=function(){return loggerLevel;};this.getEffectiveLevel=function(){for(var logger=this;logger!==null;logger=logger.parent){var level=logger.getLevel();if(level!==null){return level;}}};this.group=function(name,initiallyExpanded){if(enabled){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].group(name,initiallyExpanded);}}};this.groupEnd=function(){if(enabled){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].groupEnd();}}};var timers={};this.time=function(name,level){if(enabled){if(isUndefined(name)){handleError("Logger.time: a name for the timer must be supplied");}else if(level&&!(level instanceof Level)){handleError("Logger.time: level supplied to timer "+

+name+" is not an instance of log4javascript.Level");}else{timers[name]=new Timer(name,level);}}};this.timeEnd=function(name){if(enabled){if(isUndefined(name)){handleError("Logger.timeEnd: a name for the timer must be supplied");}else if(timers[name]){var timer=timers[name];var milliseconds=timer.getElapsedTime();this.log(timer.level,["Timer "+toStr(name)+" completed in "+milliseconds+"ms"]);delete timers[name];}else{logLog.warn("Logger.timeEnd: no timer found with name "+name);}}};this.assert=function(expr){if(enabled&&!expr){var args=[];for(var i=1,len=arguments.length;i<len;i++){args.push(arguments[i]);}

+args=(args.length>0)?args:["Assertion Failure"];args.push(newLine);args.push(expr);this.log(Level.ERROR,args);}};this.toString=function(){return"Logger["+this.name+"]";};}

+Logger.prototype={trace:function(){this.log(Level.TRACE,arguments);},debug:function(){this.log(Level.DEBUG,arguments);},info:function(){this.log(Level.INFO,arguments);},warn:function(){this.log(Level.WARN,arguments);},error:function(){this.log(Level.ERROR,arguments);},fatal:function(){this.log(Level.FATAL,arguments);},isEnabledFor:function(level){return level.isGreaterOrEqual(this.getEffectiveLevel());},isTraceEnabled:function(){return this.isEnabledFor(Level.TRACE);},isDebugEnabled:function(){return this.isEnabledFor(Level.DEBUG);},isInfoEnabled:function(){return this.isEnabledFor(Level.INFO);},isWarnEnabled:function(){return this.isEnabledFor(Level.WARN);},isErrorEnabled:function(){return this.isEnabledFor(Level.ERROR);},isFatalEnabled:function(){return this.isEnabledFor(Level.FATAL);}};Logger.prototype.trace.isEntryPoint=true;Logger.prototype.debug.isEntryPoint=true;Logger.prototype.info.isEntryPoint=true;Logger.prototype.warn.isEntryPoint=true;Logger.prototype.error.isEntryPoint=true;Logger.prototype.fatal.isEntryPoint=true;var loggers={};var loggerNames=[];var ROOT_LOGGER_DEFAULT_LEVEL=Level.DEBUG;var rootLogger=new Logger(rootLoggerName);rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);log4javascript.getRootLogger=function(){return rootLogger;};log4javascript.getLogger=function(loggerName){if(!(typeof loggerName=="string")){loggerName=anonymousLoggerName;logLog.warn("log4javascript.getLogger: non-string logger name "+

+toStr(loggerName)+" supplied, returning anonymous logger");}

+if(loggerName==rootLoggerName){handleError("log4javascript.getLogger: root logger may not be obtained by name");}

+if(!loggers[loggerName]){var logger=new Logger(loggerName);loggers[loggerName]=logger;loggerNames.push(loggerName);var lastDotIndex=loggerName.lastIndexOf(".");var parentLogger;if(lastDotIndex>-1){var parentLoggerName=loggerName.substring(0,lastDotIndex);parentLogger=log4javascript.getLogger(parentLoggerName);}else{parentLogger=rootLogger;}

+parentLogger.addChild(logger);}

+return loggers[loggerName];};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=log4javascript.getLogger(defaultLoggerName);var a=new log4javascript.PopUpAppender();defaultLogger.addAppender(a);}

+return defaultLogger;};var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger(nullLoggerName);nullLogger.setLevel(Level.OFF);}

+return nullLogger;};log4javascript.resetConfiguration=function(){rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);loggers={};};var LoggingEvent=function(logger,timeStamp,level,messages,exception){this.logger=logger;this.timeStamp=timeStamp;this.timeStampInMilliseconds=timeStamp.getTime();this.timeStampInSeconds=Math.floor(this.timeStampInMilliseconds/1000);this.milliseconds=this.timeStamp.getMilliseconds();this.level=level;this.messages=messages;this.exception=exception;};LoggingEvent.prototype={getThrowableStrRep:function(){return this.exception?getExceptionStringRep(this.exception):"";},getCombinedMessages:function(){return(this.messages.length==1)?this.messages[0]:this.messages.join(newLine);},toString:function(){return"LoggingEvent["+this.level+"]";}};log4javascript.LoggingEvent=LoggingEvent;var Layout=function(){};Layout.prototype={defaults:{loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url"},loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url",batchHeader:"",batchFooter:"",batchSeparator:"",returnsPostData:false,overrideTimeStampsSetting:false,useTimeStampsInMilliseconds:null,format:function(){handleError("Layout.format: layout supplied has no format() method");},ignoresThrowable:function(){handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");},getContentType:function(){return"text/plain";},allowBatching:function(){return true;},setTimeStampsInMilliseconds:function(timeStampsInMilliseconds){this.overrideTimeStampsSetting=true;this.useTimeStampsInMilliseconds=bool(timeStampsInMilliseconds);},isTimeStampsInMilliseconds:function(){return this.overrideTimeStampsSetting?this.useTimeStampsInMilliseconds:useTimeStampsInMilliseconds;},getTimeStampValue:function(loggingEvent){return this.isTimeStampsInMilliseconds()?loggingEvent.timeStampInMilliseconds:loggingEvent.timeStampInSeconds;},getDataValues:function(loggingEvent,combineMessages){var dataValues=[[this.loggerKey,loggingEvent.logger.name],[this.timeStampKey,this.getTimeStampValue(loggingEvent)],[this.levelKey,loggingEvent.level.name],[this.urlKey,window.location.href],[this.messageKey,combineMessages?loggingEvent.getCombinedMessages():loggingEvent.messages]];if(!this.isTimeStampsInMilliseconds()){dataValues.push([this.millisecondsKey,loggingEvent.milliseconds]);}

+if(loggingEvent.exception){dataValues.push([this.exceptionKey,getExceptionStringRep(loggingEvent.exception)]);}

+if(this.hasCustomFields()){for(var i=0,len=this.customFields.length;i<len;i++){var val=this.customFields[i].value;if(typeof val==="function"){val=val(this,loggingEvent);}

+dataValues.push([this.customFields[i].name,val]);}}

+return dataValues;},setKeys:function(loggerKey,timeStampKey,levelKey,messageKey,exceptionKey,urlKey,millisecondsKey){this.loggerKey=extractStringFromParam(loggerKey,this.defaults.loggerKey);this.timeStampKey=extractStringFromParam(timeStampKey,this.defaults.timeStampKey);this.levelKey=extractStringFromParam(levelKey,this.defaults.levelKey);this.messageKey=extractStringFromParam(messageKey,this.defaults.messageKey);this.exceptionKey=extractStringFromParam(exceptionKey,this.defaults.exceptionKey);this.urlKey=extractStringFromParam(urlKey,this.defaults.urlKey);this.millisecondsKey=extractStringFromParam(millisecondsKey,this.defaults.millisecondsKey);},setCustomField:function(name,value){var fieldUpdated=false;for(var i=0,len=this.customFields.length;i<len;i++){if(this.customFields[i].name===name){this.customFields[i].value=value;fieldUpdated=true;}}

+if(!fieldUpdated){this.customFields.push({"name":name,"value":value});}},hasCustomFields:function(){return(this.customFields.length>0);},toString:function(){handleError("Layout.toString: all layouts must override this method");}};log4javascript.Layout=Layout;var Appender=function(){};Appender.prototype=new EventSupport();Appender.prototype.layout=new PatternLayout();Appender.prototype.threshold=Level.ALL;Appender.prototype.loggers=[];Appender.prototype.doAppend=function(loggingEvent){if(enabled&&loggingEvent.level.level>=this.threshold.level){this.append(loggingEvent);}};Appender.prototype.append=function(loggingEvent){};Appender.prototype.setLayout=function(layout){if(layout instanceof Layout){this.layout=layout;}else{handleError("Appender.setLayout: layout supplied to "+

+this.toString()+" is not a subclass of Layout");}};Appender.prototype.getLayout=function(){return this.layout;};Appender.prototype.setThreshold=function(threshold){if(threshold instanceof Level){this.threshold=threshold;}else{handleError("Appender.setThreshold: threshold supplied to "+

+this.toString()+" is not a subclass of Level");}};Appender.prototype.getThreshold=function(){return this.threshold;};Appender.prototype.setAddedToLogger=function(logger){this.loggers.push(logger);};Appender.prototype.setRemovedFromLogger=function(logger){array_remove(this.loggers,logger);};Appender.prototype.group=emptyFunction;Appender.prototype.groupEnd=emptyFunction;Appender.prototype.toString=function(){handleError("Appender.toString: all appenders must override this method");};log4javascript.Appender=Appender;function SimpleLayout(){this.customFields=[];}

+SimpleLayout.prototype=new Layout();SimpleLayout.prototype.format=function(loggingEvent){return loggingEvent.level.name+" - "+loggingEvent.getCombinedMessages();};SimpleLayout.prototype.ignoresThrowable=function(){return true;};SimpleLayout.prototype.toString=function(){return"SimpleLayout";};log4javascript.SimpleLayout=SimpleLayout;function NullLayout(){this.customFields=[];}

+NullLayout.prototype=new Layout();NullLayout.prototype.format=function(loggingEvent){return loggingEvent.messages;};NullLayout.prototype.ignoresThrowable=function(){return true;};NullLayout.prototype.toString=function(){return"NullLayout";};log4javascript.NullLayout=NullLayout;function XmlLayout(combineMessages){this.combineMessages=extractBooleanFromParam(combineMessages,true);this.customFields=[];}

+XmlLayout.prototype=new Layout();XmlLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};XmlLayout.prototype.getContentType=function(){return"text/xml";};XmlLayout.prototype.escapeCdata=function(str){return str.replace(/\]\]>/,"]]>]]&gt;<![CDATA[");};XmlLayout.prototype.format=function(loggingEvent){var layout=this;var i,len;function formatMessage(message){message=(typeof message==="string")?message:toStr(message);return"<log4javascript:message><![CDATA["+

+layout.escapeCdata(message)+"]]></log4javascript:message>";}

+var str="<log4javascript:event logger=\""+loggingEvent.logger.name+"\" timestamp=\""+this.getTimeStampValue(loggingEvent)+"\"";if(!this.isTimeStampsInMilliseconds()){str+=" milliseconds=\""+loggingEvent.milliseconds+"\"";}

+str+=" level=\""+loggingEvent.level.name+"\">"+newLine;if(this.combineMessages){str+=formatMessage(loggingEvent.getCombinedMessages());}else{str+="<log4javascript:messages>"+newLine;for(i=0,len=loggingEvent.messages.length;i<len;i++){str+=formatMessage(loggingEvent.messages[i])+newLine;}

+str+="</log4javascript:messages>"+newLine;}

+if(this.hasCustomFields()){for(i=0,len=this.customFields.length;i<len;i++){str+="<log4javascript:customfield name=\""+

+this.customFields[i].name+"\"><![CDATA["+

+this.customFields[i].value.toString()+"]]></log4javascript:customfield>"+newLine;}}

+if(loggingEvent.exception){str+="<log4javascript:exception><![CDATA["+

+getExceptionStringRep(loggingEvent.exception)+"]]></log4javascript:exception>"+newLine;}

+str+="</log4javascript:event>"+newLine+newLine;return str;};XmlLayout.prototype.ignoresThrowable=function(){return false;};XmlLayout.prototype.toString=function(){return"XmlLayout";};log4javascript.XmlLayout=XmlLayout;function escapeNewLines(str){return str.replace(/\r\n|\r|\n/g,"\\r\\n");}

+function JsonLayout(readable,combineMessages){this.readable=extractBooleanFromParam(readable,false);this.combineMessages=extractBooleanFromParam(combineMessages,true);this.batchHeader=this.readable?"["+newLine:"[";this.batchFooter=this.readable?"]"+newLine:"]";this.batchSeparator=this.readable?","+newLine:",";this.setKeys();this.colon=this.readable?": ":":";this.tab=this.readable?"\t":"";this.lineBreak=this.readable?newLine:"";this.customFields=[];}

+JsonLayout.prototype=new Layout();JsonLayout.prototype.isReadable=function(){return this.readable;};JsonLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};JsonLayout.prototype.format=function(loggingEvent){var layout=this;var dataValues=this.getDataValues(loggingEvent,this.combineMessages);var str="{"+this.lineBreak;var i,len;function formatValue(val,prefix,expand){var formattedValue;var valType=typeof val;if(val instanceof Date){formattedValue=String(val.getTime());}else if(expand&&(val instanceof Array)){formattedValue="["+layout.lineBreak;for(var i=0,len=val.length;i<len;i++){var childPrefix=prefix+layout.tab;formattedValue+=childPrefix+formatValue(val[i],childPrefix,false);if(i<val.length-1){formattedValue+=",";}

+formattedValue+=layout.lineBreak;}

+formattedValue+=prefix+"]";}else if(valType!=="number"&&valType!=="boolean"){formattedValue="\""+escapeNewLines(toStr(val).replace(/\"/g,"\\\""))+"\"";}else{formattedValue=val;}

+return formattedValue;}

+for(i=0,len=dataValues.length-1;i<=len;i++){str+=this.tab+"\""+dataValues[i][0]+"\""+this.colon+formatValue(dataValues[i][1],this.tab,true);if(i<len){str+=",";}

+str+=this.lineBreak;}

+str+="}"+this.lineBreak;return str;};JsonLayout.prototype.ignoresThrowable=function(){return false;};JsonLayout.prototype.toString=function(){return"JsonLayout";};JsonLayout.prototype.getContentType=function(){return"application/json";};log4javascript.JsonLayout=JsonLayout;function HttpPostDataLayout(){this.setKeys();this.customFields=[];this.returnsPostData=true;}

+HttpPostDataLayout.prototype=new Layout();HttpPostDataLayout.prototype.allowBatching=function(){return false;};HttpPostDataLayout.prototype.format=function(loggingEvent){var dataValues=this.getDataValues(loggingEvent);var queryBits=[];for(var i=0,len=dataValues.length;i<len;i++){var val=(dataValues[i][1]instanceof Date)?String(dataValues[i][1].getTime()):dataValues[i][1];queryBits.push(urlEncode(dataValues[i][0])+"="+urlEncode(val));}

+return queryBits.join("&");};HttpPostDataLayout.prototype.ignoresThrowable=function(loggingEvent){return false;};HttpPostDataLayout.prototype.toString=function(){return"HttpPostDataLayout";};log4javascript.HttpPostDataLayout=HttpPostDataLayout;function formatObjectExpansion(obj,depth,indentation){var objectsExpanded=[];function doFormat(obj,depth,indentation){var i,j,len,childDepth,childIndentation,childLines,expansion,childExpansion;if(!indentation){indentation="";}

+function formatString(text){var lines=splitIntoLines(text);for(var j=1,jLen=lines.length;j<jLen;j++){lines[j]=indentation+lines[j];}

+return lines.join(newLine);}

+if(obj===null){return"null";}else if(typeof obj=="undefined"){return"undefined";}else if(typeof obj=="string"){return formatString(obj);}else if(typeof obj=="object"&&array_contains(objectsExpanded,obj)){try{expansion=toStr(obj);}catch(ex){expansion="Error formatting property. Details: "+getExceptionStringRep(ex);}

+return expansion+" [already expanded]";}else if((obj instanceof Array)&&depth>0){objectsExpanded.push(obj);expansion="["+newLine;childDepth=depth-1;childIndentation=indentation+"  ";childLines=[];for(i=0,len=obj.length;i<len;i++){try{childExpansion=doFormat(obj[i],childDepth,childIndentation);childLines.push(childIndentation+childExpansion);}catch(ex){childLines.push(childIndentation+"Error formatting array member. Details: "+

+getExceptionStringRep(ex)+"");}}

+expansion+=childLines.join(","+newLine)+newLine+indentation+"]";return expansion;}else if(Object.prototype.toString.call(obj)=="[object Date]"){return obj.toString();}else if(typeof obj=="object"&&depth>0){objectsExpanded.push(obj);expansion="{"+newLine;childDepth=depth-1;childIndentation=indentation+"  ";childLines=[];for(i in obj){try{childExpansion=doFormat(obj[i],childDepth,childIndentation);childLines.push(childIndentation+i+": "+childExpansion);}catch(ex){childLines.push(childIndentation+i+": Error formatting property. Details: "+

+getExceptionStringRep(ex));}}

+expansion+=childLines.join(","+newLine)+newLine+indentation+"}";return expansion;}else{return formatString(toStr(obj));}}

+return doFormat(obj,depth,indentation);}

+var SimpleDateFormat;(function(){var regex=/('[^']*')|(G+|y+|M+|w+|W+|D+|d+|F+|E+|a+|H+|k+|K+|h+|m+|s+|S+|Z+)|([a-zA-Z]+)|([^a-zA-Z']+)/;var monthNames=["January","February","March","April","May","June","July","August","September","October","November","December"];var dayNames=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var TEXT2=0,TEXT3=1,NUMBER=2,YEAR=3,MONTH=4,TIMEZONE=5;var types={G:TEXT2,y:YEAR,M:MONTH,w:NUMBER,W:NUMBER,D:NUMBER,d:NUMBER,F:NUMBER,E:TEXT3,a:TEXT2,H:NUMBER,k:NUMBER,K:NUMBER,h:NUMBER,m:NUMBER,s:NUMBER,S:NUMBER,Z:TIMEZONE};var ONE_DAY=24*60*60*1000;var ONE_WEEK=7*ONE_DAY;var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK=1;var newDateAtMidnight=function(year,month,day){var d=new Date(year,month,day,0,0,0);d.setMilliseconds(0);return d;};Date.prototype.getDifference=function(date){return this.getTime()-date.getTime();};Date.prototype.isBefore=function(d){return this.getTime()<d.getTime();};Date.prototype.getUTCTime=function(){return Date.UTC(this.getFullYear(),this.getMonth(),this.getDate(),this.getHours(),this.getMinutes(),this.getSeconds(),this.getMilliseconds());};Date.prototype.getTimeSince=function(d){return this.getUTCTime()-d.getUTCTime();};Date.prototype.getPreviousSunday=function(){var midday=new Date(this.getFullYear(),this.getMonth(),this.getDate(),12,0,0);var previousSunday=new Date(midday.getTime()-this.getDay()*ONE_DAY);return newDateAtMidnight(previousSunday.getFullYear(),previousSunday.getMonth(),previousSunday.getDate());};Date.prototype.getWeekInYear=function(minimalDaysInFirstWeek){if(isUndefined(this.minimalDaysInFirstWeek)){minimalDaysInFirstWeek=DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;}

+var previousSunday=this.getPreviousSunday();var startOfYear=newDateAtMidnight(this.getFullYear(),0,1);var numberOfSundays=previousSunday.isBefore(startOfYear)?0:1+Math.floor(previousSunday.getTimeSince(startOfYear)/ONE_WEEK);var numberOfDaysInFirstWeek=7-startOfYear.getDay();var weekInYear=numberOfSundays;if(numberOfDaysInFirstWeek<minimalDaysInFirstWeek){weekInYear--;}

+return weekInYear;};Date.prototype.getWeekInMonth=function(minimalDaysInFirstWeek){if(isUndefined(this.minimalDaysInFirstWeek)){minimalDaysInFirstWeek=DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;}

+var previousSunday=this.getPreviousSunday();var startOfMonth=newDateAtMidnight(this.getFullYear(),this.getMonth(),1);var numberOfSundays=previousSunday.isBefore(startOfMonth)?0:1+Math.floor(previousSunday.getTimeSince(startOfMonth)/ONE_WEEK);var numberOfDaysInFirstWeek=7-startOfMonth.getDay();var weekInMonth=numberOfSundays;if(numberOfDaysInFirstWeek>=minimalDaysInFirstWeek){weekInMonth++;}

+return weekInMonth;};Date.prototype.getDayInYear=function(){var startOfYear=newDateAtMidnight(this.getFullYear(),0,1);return 1+Math.floor(this.getTimeSince(startOfYear)/ONE_DAY);};SimpleDateFormat=function(formatString){this.formatString=formatString;};SimpleDateFormat.prototype.setMinimalDaysInFirstWeek=function(days){this.minimalDaysInFirstWeek=days;};SimpleDateFormat.prototype.getMinimalDaysInFirstWeek=function(){return isUndefined(this.minimalDaysInFirstWeek)?DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK:this.minimalDaysInFirstWeek;};var padWithZeroes=function(str,len){while(str.length<len){str="0"+str;}

+return str;};var formatText=function(data,numberOfLetters,minLength){return(numberOfLetters>=4)?data:data.substr(0,Math.max(minLength,numberOfLetters));};var formatNumber=function(data,numberOfLetters){var dataString=""+data;return padWithZeroes(dataString,numberOfLetters);};SimpleDateFormat.prototype.format=function(date){var formattedString="";var result;var searchString=this.formatString;while((result=regex.exec(searchString))){var quotedString=result[1];var patternLetters=result[2];var otherLetters=result[3];var otherCharacters=result[4];if(quotedString){if(quotedString=="''"){formattedString+="'";}else{formattedString+=quotedString.substring(1,quotedString.length-1);}}else if(otherLetters){}else if(otherCharacters){formattedString+=otherCharacters;}else if(patternLetters){var patternLetter=patternLetters.charAt(0);var numberOfLetters=patternLetters.length;var rawData="";switch(patternLetter){case"G":rawData="AD";break;case"y":rawData=date.getFullYear();break;case"M":rawData=date.getMonth();break;case"w":rawData=date.getWeekInYear(this.getMinimalDaysInFirstWeek());break;case"W":rawData=date.getWeekInMonth(this.getMinimalDaysInFirstWeek());break;case"D":rawData=date.getDayInYear();break;case"d":rawData=date.getDate();break;case"F":rawData=1+Math.floor((date.getDate()-1)/7);break;case"E":rawData=dayNames[date.getDay()];break;case"a":rawData=(date.getHours()>=12)?"PM":"AM";break;case"H":rawData=date.getHours();break;case"k":rawData=date.getHours()||24;break;case"K":rawData=date.getHours()%12;break;case"h":rawData=(date.getHours()%12)||12;break;case"m":rawData=date.getMinutes();break;case"s":rawData=date.getSeconds();break;case"S":rawData=date.getMilliseconds();break;case"Z":rawData=date.getTimezoneOffset();break;}

+switch(types[patternLetter]){case TEXT2:formattedString+=formatText(rawData,numberOfLetters,2);break;case TEXT3:formattedString+=formatText(rawData,numberOfLetters,3);break;case NUMBER:formattedString+=formatNumber(rawData,numberOfLetters);break;case YEAR:if(numberOfLetters<=3){var dataString=""+rawData;formattedString+=dataString.substr(2,2);}else{formattedString+=formatNumber(rawData,numberOfLetters);}

+break;case MONTH:if(numberOfLetters>=3){formattedString+=formatText(monthNames[rawData],numberOfLetters,numberOfLetters);}else{formattedString+=formatNumber(rawData+1,numberOfLetters);}

+break;case TIMEZONE:var isPositive=(rawData>0);var prefix=isPositive?"-":"+";var absData=Math.abs(rawData);var hours=""+Math.floor(absData/60);hours=padWithZeroes(hours,2);var minutes=""+(absData%60);minutes=padWithZeroes(minutes,2);formattedString+=prefix+hours+minutes;break;}}

+searchString=searchString.substr(result.index+result[0].length);}

+return formattedString;};})();log4javascript.SimpleDateFormat=SimpleDateFormat;function PatternLayout(pattern){if(pattern){this.pattern=pattern;}else{this.pattern=PatternLayout.DEFAULT_CONVERSION_PATTERN;}

+this.customFields=[];}

+PatternLayout.TTCC_CONVERSION_PATTERN="%r %p %c - %m%n";PatternLayout.DEFAULT_CONVERSION_PATTERN="%m%n";PatternLayout.ISO8601_DATEFORMAT="yyyy-MM-dd HH:mm:ss,SSS";PatternLayout.DATETIME_DATEFORMAT="dd MMM yyyy HH:mm:ss,SSS";PatternLayout.ABSOLUTETIME_DATEFORMAT="HH:mm:ss,SSS";PatternLayout.prototype=new Layout();PatternLayout.prototype.format=function(loggingEvent){var regex=/%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;var formattedString="";var result;var searchString=this.pattern;while((result=regex.exec(searchString))){var matchedString=result[0];var padding=result[1];var truncation=result[2];var conversionCharacter=result[3];var specifier=result[5];var text=result[6];if(text){formattedString+=""+text;}else{var replacement="";switch(conversionCharacter){case"a":case"m":var depth=0;if(specifier){depth=parseInt(specifier,10);if(isNaN(depth)){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character '"+conversionCharacter+"' - should be a number");depth=0;}}

+var messages=(conversionCharacter==="a")?loggingEvent.messages[0]:loggingEvent.messages;for(var i=0,len=messages.length;i<len;i++){if(i>0&&(replacement.charAt(replacement.length-1)!==" ")){replacement+=" ";}

+if(depth===0){replacement+=messages[i];}else{replacement+=formatObjectExpansion(messages[i],depth);}}

+break;case"c":var loggerName=loggingEvent.logger.name;if(specifier){var precision=parseInt(specifier,10);var loggerNameBits=loggingEvent.logger.name.split(".");if(precision>=loggerNameBits.length){replacement=loggerName;}else{replacement=loggerNameBits.slice(loggerNameBits.length-precision).join(".");}}else{replacement=loggerName;}

+break;case"d":var dateFormat=PatternLayout.ISO8601_DATEFORMAT;if(specifier){dateFormat=specifier;if(dateFormat=="ISO8601"){dateFormat=PatternLayout.ISO8601_DATEFORMAT;}else if(dateFormat=="ABSOLUTE"){dateFormat=PatternLayout.ABSOLUTETIME_DATEFORMAT;}else if(dateFormat=="DATE"){dateFormat=PatternLayout.DATETIME_DATEFORMAT;}}

+replacement=(new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);break;case"f":if(this.hasCustomFields()){var fieldIndex=0;if(specifier){fieldIndex=parseInt(specifier,10);if(isNaN(fieldIndex)){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - should be a number");}else if(fieldIndex===0){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - must be greater than zero");}else if(fieldIndex>this.customFields.length){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - there aren't that many custom fields");}else{fieldIndex=fieldIndex-1;}}

+var val=this.customFields[fieldIndex].value;if(typeof val=="function"){val=val(this,loggingEvent);}

+replacement=val;}

+break;case"n":replacement=newLine;break;case"p":replacement=loggingEvent.level.name;break;case"r":replacement=""+loggingEvent.timeStamp.getDifference(applicationStartDate);break;case"%":replacement="%";break;default:replacement=matchedString;break;}

+var l;if(truncation){l=parseInt(truncation.substr(1),10);var strLen=replacement.length;if(l<strLen){replacement=replacement.substring(strLen-l,strLen);}}

+if(padding){if(padding.charAt(0)=="-"){l=parseInt(padding.substr(1),10);while(replacement.length<l){replacement+=" ";}}else{l=parseInt(padding,10);while(replacement.length<l){replacement=" "+replacement;}}}

+formattedString+=replacement;}

+searchString=searchString.substr(result.index+result[0].length);}

+return formattedString;};PatternLayout.prototype.ignoresThrowable=function(){return true;};PatternLayout.prototype.toString=function(){return"PatternLayout";};log4javascript.PatternLayout=PatternLayout;var xmlHttpFactories=[function(){return new XMLHttpRequest();},function(){return new ActiveXObject("Msxml2.XMLHTTP");},function(){return new ActiveXObject("Microsoft.XMLHTTP");}];var getXmlHttp=function(errorHandler){var xmlHttp=null,factory;for(var i=0,len=xmlHttpFactories.length;i<len;i++){factory=xmlHttpFactories[i];try{xmlHttp=factory();getXmlHttp=factory;return xmlHttp;}catch(e){}}

+if(errorHandler){errorHandler();}else{handleError("getXmlHttp: unable to obtain XMLHttpRequest object");}};function isHttpRequestSuccessful(xmlHttp){return isUndefined(xmlHttp.status)||xmlHttp.status===0||(xmlHttp.status>=200&&xmlHttp.status<300)||xmlHttp.status==1223;}

+function AjaxAppender(url){var appender=this;var isSupported=true;if(!url){handleError("AjaxAppender: URL must be specified in constructor");isSupported=false;}

+var timed=this.defaults.timed;var waitForResponse=this.defaults.waitForResponse;var batchSize=this.defaults.batchSize;var timerInterval=this.defaults.timerInterval;var requestSuccessCallback=this.defaults.requestSuccessCallback;var failCallback=this.defaults.failCallback;var postVarName=this.defaults.postVarName;var sendAllOnUnload=this.defaults.sendAllOnUnload;var contentType=this.defaults.contentType;var sessionId=null;var queuedLoggingEvents=[];var queuedRequests=[];var headers=[];var sending=false;var initialized=false;function checkCanConfigure(configOptionName){if(initialized){handleError("AjaxAppender: configuration option '"+

+configOptionName+"' may not be set after the appender has been initialized");return false;}

+return true;}

+this.getSessionId=function(){return sessionId;};this.setSessionId=function(sessionIdParam){sessionId=extractStringFromParam(sessionIdParam,null);this.layout.setCustomField("sessionid",sessionId);};this.setLayout=function(layoutParam){if(checkCanConfigure("layout")){this.layout=layoutParam;if(sessionId!==null){this.setSessionId(sessionId);}}};this.isTimed=function(){return timed;};this.setTimed=function(timedParam){if(checkCanConfigure("timed")){timed=bool(timedParam);}};this.getTimerInterval=function(){return timerInterval;};this.setTimerInterval=function(timerIntervalParam){if(checkCanConfigure("timerInterval")){timerInterval=extractIntFromParam(timerIntervalParam,timerInterval);}};this.isWaitForResponse=function(){return waitForResponse;};this.setWaitForResponse=function(waitForResponseParam){if(checkCanConfigure("waitForResponse")){waitForResponse=bool(waitForResponseParam);}};this.getBatchSize=function(){return batchSize;};this.setBatchSize=function(batchSizeParam){if(checkCanConfigure("batchSize")){batchSize=extractIntFromParam(batchSizeParam,batchSize);}};this.isSendAllOnUnload=function(){return sendAllOnUnload;};this.setSendAllOnUnload=function(sendAllOnUnloadParam){if(checkCanConfigure("sendAllOnUnload")){sendAllOnUnload=extractBooleanFromParam(sendAllOnUnloadParam,sendAllOnUnload);}};this.setRequestSuccessCallback=function(requestSuccessCallbackParam){requestSuccessCallback=extractFunctionFromParam(requestSuccessCallbackParam,requestSuccessCallback);};this.setFailCallback=function(failCallbackParam){failCallback=extractFunctionFromParam(failCallbackParam,failCallback);};this.getPostVarName=function(){return postVarName;};this.setPostVarName=function(postVarNameParam){if(checkCanConfigure("postVarName")){postVarName=extractStringFromParam(postVarNameParam,postVarName);}};this.getHeaders=function(){return headers;};this.addHeader=function(name,value){if(name.toLowerCase()=="content-type"){contentType=value;}else{headers.push({name:name,value:value});}};function sendAll(){if(isSupported&&enabled){sending=true;var currentRequestBatch;if(waitForResponse){if(queuedRequests.length>0){currentRequestBatch=queuedRequests.shift();sendRequest(preparePostData(currentRequestBatch),sendAll);}else{sending=false;if(timed){scheduleSending();}}}else{while((currentRequestBatch=queuedRequests.shift())){sendRequest(preparePostData(currentRequestBatch));}

+sending=false;if(timed){scheduleSending();}}}}

+this.sendAll=sendAll;function sendAllRemaining(){var sendingAnything=false;if(isSupported&&enabled){var actualBatchSize=appender.getLayout().allowBatching()?batchSize:1;var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);if(queuedLoggingEvents.length>=actualBatchSize){queuedRequests.push(batchedLoggingEvents);batchedLoggingEvents=[];}}

+if(batchedLoggingEvents.length>0){queuedRequests.push(batchedLoggingEvents);}

+sendingAnything=(queuedRequests.length>0);waitForResponse=false;timed=false;sendAll();}

+return sendingAnything;}

+this.sendAllRemaining=sendAllRemaining;function preparePostData(batchedLoggingEvents){var formattedMessages=[];var currentLoggingEvent;var postData="";while((currentLoggingEvent=batchedLoggingEvents.shift())){var currentFormattedMessage=appender.getLayout().format(currentLoggingEvent);if(appender.getLayout().ignoresThrowable()){currentFormattedMessage+=currentLoggingEvent.getThrowableStrRep();}

+formattedMessages.push(currentFormattedMessage);}

+if(batchedLoggingEvents.length==1){postData=formattedMessages.join("");}else{postData=appender.getLayout().batchHeader+

+formattedMessages.join(appender.getLayout().batchSeparator)+

+appender.getLayout().batchFooter;}

+if(contentType==appender.defaults.contentType){postData=appender.getLayout().returnsPostData?postData:urlEncode(postVarName)+"="+urlEncode(postData);if(postData.length>0){postData+="&";}

+postData+="layout="+urlEncode(appender.getLayout().toString());}

+return postData;}

+function scheduleSending(){window.setTimeout(sendAll,timerInterval);}

+function xmlHttpErrorHandler(){var msg="AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}}

+function sendRequest(postData,successCallback){try{var xmlHttp=getXmlHttp(xmlHttpErrorHandler);if(isSupported){if(xmlHttp.overrideMimeType){xmlHttp.overrideMimeType(appender.getLayout().getContentType());}

+xmlHttp.onreadystatechange=function(){if(xmlHttp.readyState==4){if(isHttpRequestSuccessful(xmlHttp)){if(requestSuccessCallback){requestSuccessCallback(xmlHttp);}

+if(successCallback){successCallback(xmlHttp);}}else{var msg="AjaxAppender.append: XMLHttpRequest request to URL "+

+url+" returned status code "+xmlHttp.status;handleError(msg);if(failCallback){failCallback(msg);}}

+xmlHttp.onreadystatechange=emptyFunction;xmlHttp=null;}};xmlHttp.open("POST",url,true);try{for(var i=0,header;header=headers[i++];){xmlHttp.setRequestHeader(header.name,header.value);}

+xmlHttp.setRequestHeader("Content-Type",contentType);}catch(headerEx){var msg="AjaxAppender.append: your browser's XMLHttpRequest implementation"+" does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}

+return;}

+xmlHttp.send(postData);}}catch(ex){var errMsg="AjaxAppender.append: error sending log message to "+url;handleError(errMsg,ex);isSupported=false;if(failCallback){failCallback(errMsg+". Details: "+getExceptionStringRep(ex));}}}

+this.append=function(loggingEvent){if(isSupported){if(!initialized){init();}

+queuedLoggingEvents.push(loggingEvent);var actualBatchSize=this.getLayout().allowBatching()?batchSize:1;if(queuedLoggingEvents.length>=actualBatchSize){var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);}

+queuedRequests.push(batchedLoggingEvents);if(!timed&&(!waitForResponse||(waitForResponse&&!sending))){sendAll();}}}};function init(){initialized=true;if(sendAllOnUnload){var oldBeforeUnload=window.onbeforeunload;window.onbeforeunload=function(){if(oldBeforeUnload){oldBeforeUnload();}

+if(sendAllRemaining()){return"Sending log messages";}};}

+if(timed){scheduleSending();}}}

+AjaxAppender.prototype=new Appender();AjaxAppender.prototype.defaults={waitForResponse:false,timed:false,timerInterval:1000,batchSize:1,sendAllOnUnload:false,requestSuccessCallback:null,failCallback:null,postVarName:"data",contentType:"application/x-www-form-urlencoded"};AjaxAppender.prototype.layout=new HttpPostDataLayout();AjaxAppender.prototype.toString=function(){return"AjaxAppender";};log4javascript.AjaxAppender=AjaxAppender;log4javascript.setDocumentReady=function(){pageLoaded=true;log4javascript.dispatchEvent("load",{});};if(window.addEventListener){window.addEventListener("load",log4javascript.setDocumentReady,false);}else if(window.attachEvent){window.attachEvent("onload",log4javascript.setDocumentReady);}else{var oldOnload=window.onload;if(typeof window.onload!="function"){window.onload=log4javascript.setDocumentReady;}else{window.onload=function(evt){if(oldOnload){oldOnload(evt);}

+log4javascript.setDocumentReady();};}}

+window.log4javascript=log4javascript;return log4javascript;})();

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_production_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_production_uncompressed.js
new file mode 100644
index 0000000..1a29621
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_production_uncompressed.js
@@ -0,0 +1,2290 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+/**

+ * log4javascript

+ *

+ * log4javascript is a logging framework for JavaScript based on log4j

+ * for Java. This file contains all core log4javascript code and is the only

+ * file required to use log4javascript, unless you require support for

+ * document.domain, in which case you will also need console.html, which must be

+ * stored in the same directory as the main log4javascript.js file.

+ *

+ * Author: Tim Down <tim@log4javascript.org>

+ * Version: 1.4.6

+ * Edition: log4javascript_production

+ * Build date: 19 March 2013

+ * Website: http://log4javascript.org

+ */

+

+/* -------------------------------------------------------------------------- */

+// Array-related stuff

+

+// Next three methods are solely for IE5, which is missing them

+if (!Array.prototype.push) {

+	Array.prototype.push = function() {

+		for (var i = 0, len = arguments.length; i < len; i++){

+			this[this.length] = arguments[i];

+		}

+		return this.length;

+	};

+}

+

+if (!Array.prototype.shift) {

+	Array.prototype.shift = function() {

+		if (this.length > 0) {

+			var firstItem = this[0];

+			for (var i = 0, len = this.length - 1; i < len; i++) {

+				this[i] = this[i + 1];

+			}

+			this.length = this.length - 1;

+			return firstItem;

+		}

+	};

+}

+

+if (!Array.prototype.splice) {

+	Array.prototype.splice = function(startIndex, deleteCount) {

+		var itemsAfterDeleted = this.slice(startIndex + deleteCount);

+		var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);

+		this.length = startIndex;

+		// Copy the arguments into a proper Array object

+		var argumentsArray = [];

+		for (var i = 0, len = arguments.length; i < len; i++) {

+			argumentsArray[i] = arguments[i];

+		}

+		var itemsToAppend = (argumentsArray.length > 2) ?

+			itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;

+		for (i = 0, len = itemsToAppend.length; i < len; i++) {

+			this.push(itemsToAppend[i]);

+		}

+		return itemsDeleted;

+	};

+}

+

+/* -------------------------------------------------------------------------- */

+

+var log4javascript = (function() {

+

+	function isUndefined(obj) {

+		return typeof obj == "undefined";

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// Custom event support

+

+	function EventSupport() {}

+

+	EventSupport.prototype = {

+		eventTypes: [],

+		eventListeners: {},

+		setEventTypes: function(eventTypesParam) {

+			if (eventTypesParam instanceof Array) {

+				this.eventTypes = eventTypesParam;

+				this.eventListeners = {};

+				for (var i = 0, len = this.eventTypes.length; i < len; i++) {

+					this.eventListeners[this.eventTypes[i]] = [];

+				}

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: setEventTypes: eventTypes parameter must be an Array");

+			}

+		},

+

+		addEventListener: function(eventType, listener) {

+			if (typeof listener == "function") {

+				if (!array_contains(this.eventTypes, eventType)) {

+					handleError("log4javascript.EventSupport [" + this + "]: addEventListener: no event called '" + eventType + "'");

+				}

+				this.eventListeners[eventType].push(listener);

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: addEventListener: listener must be a function");

+			}

+		},

+

+		removeEventListener: function(eventType, listener) {

+			if (typeof listener == "function") {

+				if (!array_contains(this.eventTypes, eventType)) {

+					handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: no event called '" + eventType + "'");

+				}

+				array_remove(this.eventListeners[eventType], listener);

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: listener must be a function");

+			}

+		},

+

+		dispatchEvent: function(eventType, eventArgs) {

+			if (array_contains(this.eventTypes, eventType)) {

+				var listeners = this.eventListeners[eventType];

+				for (var i = 0, len = listeners.length; i < len; i++) {

+					listeners[i](this, eventType, eventArgs);

+				}

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: dispatchEvent: no event called '" + eventType + "'");

+			}

+		}

+	};

+

+	/* -------------------------------------------------------------------------- */

+

+	var applicationStartDate = new Date();

+	var uniqueId = "log4javascript_" + applicationStartDate.getTime() + "_" +

+		Math.floor(Math.random() * 100000000);

+	var emptyFunction = function() {};

+	var newLine = "\r\n";

+	var pageLoaded = false;

+

+	// Create main log4javascript object; this will be assigned public properties

+	function Log4JavaScript() {}

+	Log4JavaScript.prototype = new EventSupport();

+

+	log4javascript = new Log4JavaScript();

+	log4javascript.version = "1.4.6";

+	log4javascript.edition = "log4javascript_production";

+

+	/* -------------------------------------------------------------------------- */

+	// Utility functions

+

+	function toStr(obj) {

+		if (obj && obj.toString) {

+			return obj.toString();

+		} else {

+			return String(obj);

+		}

+	}

+

+	function getExceptionMessage(ex) {

+		if (ex.message) {

+			return ex.message;

+		} else if (ex.description) {

+			return ex.description;

+		} else {

+			return toStr(ex);

+		}

+	}

+

+	// Gets the portion of the URL after the last slash

+	function getUrlFileName(url) {

+		var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\"));

+		return url.substr(lastSlashIndex + 1);

+	}

+

+	// Returns a nicely formatted representation of an error

+	function getExceptionStringRep(ex) {

+		if (ex) {

+			var exStr = "Exception: " + getExceptionMessage(ex);

+			try {

+				if (ex.lineNumber) {

+					exStr += " on line number " + ex.lineNumber;

+				}

+				if (ex.fileName) {

+					exStr += " in file " + getUrlFileName(ex.fileName);

+				}

+			} catch (localEx) {

+				logLog.warn("Unable to obtain file and line information for error");

+			}

+			if (showStackTraces && ex.stack) {

+				exStr += newLine + "Stack trace:" + newLine + ex.stack;

+			}

+			return exStr;

+		}

+		return null;

+	}

+

+	function bool(obj) {

+		return Boolean(obj);

+	}

+

+	function trim(str) {

+		return str.replace(/^\s+/, "").replace(/\s+$/, "");

+	}

+

+	function splitIntoLines(text) {

+		// Ensure all line breaks are \n only

+		var text2 = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");

+		return text2.split("\n");

+	}

+

+	var urlEncode = (typeof window.encodeURIComponent != "undefined") ?

+		function(str) {

+			return encodeURIComponent(str);

+		}: 

+		function(str) {

+			return escape(str).replace(/\+/g, "%2B").replace(/"/g, "%22").replace(/'/g, "%27").replace(/\//g, "%2F").replace(/=/g, "%3D");

+		};

+

+	var urlDecode = (typeof window.decodeURIComponent != "undefined") ?

+		function(str) {

+			return decodeURIComponent(str);

+		}: 

+		function(str) {

+			return unescape(str).replace(/%2B/g, "+").replace(/%22/g, "\"").replace(/%27/g, "'").replace(/%2F/g, "/").replace(/%3D/g, "=");

+		};

+

+	function array_remove(arr, val) {

+		var index = -1;

+		for (var i = 0, len = arr.length; i < len; i++) {

+			if (arr[i] === val) {

+				index = i;

+				break;

+			}

+		}

+		if (index >= 0) {

+			arr.splice(index, 1);

+			return true;

+		} else {

+			return false;

+		}

+	}

+

+	function array_contains(arr, val) {

+		for(var i = 0, len = arr.length; i < len; i++) {

+			if (arr[i] == val) {

+				return true;

+			}

+		}

+		return false;

+	}

+

+	function extractBooleanFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			return bool(param);

+		}

+	}

+

+	function extractStringFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			return String(param);

+		}

+	}

+

+	function extractIntFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			try {

+				var value = parseInt(param, 10);

+				return isNaN(value) ? defaultValue : value;

+			} catch (ex) {

+				logLog.warn("Invalid int param " + param, ex);

+				return defaultValue;

+			}

+		}

+	}

+

+	function extractFunctionFromParam(param, defaultValue) {

+		if (typeof param == "function") {

+			return param;

+		} else {

+			return defaultValue;

+		}

+	}

+

+	function isError(err) {

+		return (err instanceof Error);

+	}

+

+	if (!Function.prototype.apply){

+		Function.prototype.apply = function(obj, args) {

+			var methodName = "__apply__";

+			if (typeof obj[methodName] != "undefined") {

+				methodName += String(Math.random()).substr(2);

+			}

+			obj[methodName] = this;

+

+			var argsStrings = [];

+			for (var i = 0, len = args.length; i < len; i++) {

+				argsStrings[i] = "args[" + i + "]";

+			}

+			var script = "obj." + methodName + "(" + argsStrings.join(",") + ")";

+			var returnValue = eval(script);

+			delete obj[methodName];

+			return returnValue;

+		};

+	}

+

+	if (!Function.prototype.call){

+		Function.prototype.call = function(obj) {

+			var args = [];

+			for (var i = 1, len = arguments.length; i < len; i++) {

+				args[i - 1] = arguments[i];

+			}

+			return this.apply(obj, args);

+		};

+	}

+

+	function getListenersPropertyName(eventName) {

+		return "__log4javascript_listeners__" + eventName;

+	}

+

+	function addEvent(node, eventName, listener, useCapture, win) {

+		win = win ? win : window;

+		if (node.addEventListener) {

+			node.addEventListener(eventName, listener, useCapture);

+		} else if (node.attachEvent) {

+			node.attachEvent("on" + eventName, listener);

+		} else {

+			var propertyName = getListenersPropertyName(eventName);

+			if (!node[propertyName]) {

+				node[propertyName] = [];

+				// Set event handler

+				node["on" + eventName] = function(evt) {

+					evt = getEvent(evt, win);

+					var listenersPropertyName = getListenersPropertyName(eventName);

+

+					// Clone the array of listeners to leave the original untouched

+					var listeners = this[listenersPropertyName].concat([]);

+					var currentListener;

+

+					// Call each listener in turn

+					while ((currentListener = listeners.shift())) {

+						currentListener.call(this, evt);

+					}

+				};

+			}

+			node[propertyName].push(listener);

+		}

+	}

+

+	function removeEvent(node, eventName, listener, useCapture) {

+		if (node.removeEventListener) {

+			node.removeEventListener(eventName, listener, useCapture);

+		} else if (node.detachEvent) {

+			node.detachEvent("on" + eventName, listener);

+		} else {

+			var propertyName = getListenersPropertyName(eventName);

+			if (node[propertyName]) {

+				array_remove(node[propertyName], listener);

+			}

+		}

+	}

+

+	function getEvent(evt, win) {

+		win = win ? win : window;

+		return evt ? evt : win.event;

+	}

+

+	function stopEventPropagation(evt) {

+		if (evt.stopPropagation) {

+			evt.stopPropagation();

+		} else if (typeof evt.cancelBubble != "undefined") {

+			evt.cancelBubble = true;

+		}

+		evt.returnValue = false;

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// Simple logging for log4javascript itself

+

+	var logLog = {

+		quietMode: false,

+

+		debugMessages: [],

+

+		setQuietMode: function(quietMode) {

+			this.quietMode = bool(quietMode);

+		},

+

+		numberOfErrors: 0,

+

+		alertAllErrors: false,

+

+		setAlertAllErrors: function(alertAllErrors) {

+			this.alertAllErrors = alertAllErrors;

+		},

+

+		debug: function(message) {

+			this.debugMessages.push(message);

+		},

+

+		displayDebug: function() {

+			alert(this.debugMessages.join(newLine));

+		},

+

+		warn: function(message, exception) {

+		},

+

+		error: function(message, exception) {

+			if (++this.numberOfErrors == 1 || this.alertAllErrors) {

+				if (!this.quietMode) {

+					var alertMessage = "log4javascript error: " + message;

+					if (exception) {

+						alertMessage += newLine + newLine + "Original error: " + getExceptionStringRep(exception);

+					}

+					alert(alertMessage);

+				}

+			}

+		}

+	};

+	log4javascript.logLog = logLog;

+

+	log4javascript.setEventTypes(["load", "error"]);

+

+	function handleError(message, exception) {

+		logLog.error(message, exception);

+		log4javascript.dispatchEvent("error", { "message": message, "exception": exception });

+	}

+

+	log4javascript.handleError = handleError;

+

+	/* ---------------------------------------------------------------------- */

+

+	var enabled = !((typeof log4javascript_disabled != "undefined") &&

+					log4javascript_disabled);

+

+	log4javascript.setEnabled = function(enable) {

+		enabled = bool(enable);

+	};

+

+	log4javascript.isEnabled = function() {

+		return enabled;

+	};

+

+	var useTimeStampsInMilliseconds = true;

+

+	log4javascript.setTimeStampsInMilliseconds = function(timeStampsInMilliseconds) {

+		useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);

+	};

+

+	log4javascript.isTimeStampsInMilliseconds = function() {

+		return useTimeStampsInMilliseconds;

+	};

+	

+

+	// This evaluates the given expression in the current scope, thus allowing

+	// scripts to access private variables. Particularly useful for testing

+	log4javascript.evalInScope = function(expr) {

+		return eval(expr);

+	};

+

+	var showStackTraces = false;

+

+	log4javascript.setShowStackTraces = function(show) {

+		showStackTraces = bool(show);

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Levels

+

+	var Level = function(level, name) {

+		this.level = level;

+		this.name = name;

+	};

+

+	Level.prototype = {

+		toString: function() {

+			return this.name;

+		},

+		equals: function(level) {

+			return this.level == level.level;

+		},

+		isGreaterOrEqual: function(level) {

+			return this.level >= level.level;

+		}

+	};

+

+	Level.ALL = new Level(Number.MIN_VALUE, "ALL");

+	Level.TRACE = new Level(10000, "TRACE");

+	Level.DEBUG = new Level(20000, "DEBUG");

+	Level.INFO = new Level(30000, "INFO");

+	Level.WARN = new Level(40000, "WARN");

+	Level.ERROR = new Level(50000, "ERROR");

+	Level.FATAL = new Level(60000, "FATAL");

+	Level.OFF = new Level(Number.MAX_VALUE, "OFF");

+

+	log4javascript.Level = Level;

+

+	/* ---------------------------------------------------------------------- */

+	// Timers

+

+	function Timer(name, level) {

+		this.name = name;

+		this.level = isUndefined(level) ? Level.INFO : level;

+		this.start = new Date();

+	}

+

+	Timer.prototype.getElapsedTime = function() {

+		return new Date().getTime() - this.start.getTime();

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Loggers

+

+	var anonymousLoggerName = "[anonymous]";

+	var defaultLoggerName = "[default]";

+	var nullLoggerName = "[null]";

+	var rootLoggerName = "root";

+

+	function Logger(name) {

+		this.name = name;

+		this.parent = null;

+		this.children = [];

+

+		var appenders = [];

+		var loggerLevel = null;

+		var isRoot = (this.name === rootLoggerName);

+		var isNull = (this.name === nullLoggerName);

+

+		var appenderCache = null;

+		var appenderCacheInvalidated = false;

+		

+		this.addChild = function(childLogger) {

+			this.children.push(childLogger);

+			childLogger.parent = this;

+			childLogger.invalidateAppenderCache();

+		};

+

+		// Additivity

+		var additive = true;

+		this.getAdditivity = function() {

+			return additive;

+		};

+

+		this.setAdditivity = function(additivity) {

+			var valueChanged = (additive != additivity);

+			additive = additivity;

+			if (valueChanged) {

+				this.invalidateAppenderCache();

+			}

+		};

+

+		// Create methods that use the appenders variable in this scope

+		this.addAppender = function(appender) {

+			if (isNull) {

+				handleError("Logger.addAppender: you may not add an appender to the null logger");

+			} else {

+				if (appender instanceof log4javascript.Appender) {

+					if (!array_contains(appenders, appender)) {

+						appenders.push(appender);

+						appender.setAddedToLogger(this);

+						this.invalidateAppenderCache();

+					}

+				} else {

+					handleError("Logger.addAppender: appender supplied ('" +

+						toStr(appender) + "') is not a subclass of Appender");

+				}

+			}

+		};

+

+		this.removeAppender = function(appender) {

+			array_remove(appenders, appender);

+			appender.setRemovedFromLogger(this);

+			this.invalidateAppenderCache();

+		};

+

+		this.removeAllAppenders = function() {

+			var appenderCount = appenders.length;

+			if (appenderCount > 0) {

+				for (var i = 0; i < appenderCount; i++) {

+					appenders[i].setRemovedFromLogger(this);

+				}

+				appenders.length = 0;

+				this.invalidateAppenderCache();

+			}

+		};

+

+		this.getEffectiveAppenders = function() {

+			if (appenderCache === null || appenderCacheInvalidated) {

+				// Build appender cache

+				var parentEffectiveAppenders = (isRoot || !this.getAdditivity()) ?

+					[] : this.parent.getEffectiveAppenders();

+				appenderCache = parentEffectiveAppenders.concat(appenders);

+				appenderCacheInvalidated = false;

+			}

+			return appenderCache;

+		};

+		

+		this.invalidateAppenderCache = function() {

+			appenderCacheInvalidated = true;

+			for (var i = 0, len = this.children.length; i < len; i++) {

+				this.children[i].invalidateAppenderCache();

+			}

+		};

+

+		this.log = function(level, params) {

+			if (enabled && level.isGreaterOrEqual(this.getEffectiveLevel())) {

+				// Check whether last param is an exception

+				var exception;

+				var finalParamIndex = params.length - 1;

+				var lastParam = params[finalParamIndex];

+				if (params.length > 1 && isError(lastParam)) {

+					exception = lastParam;

+					finalParamIndex--;

+				}

+

+				// Construct genuine array for the params

+				var messages = [];

+				for (var i = 0; i <= finalParamIndex; i++) {

+					messages[i] = params[i];

+				}

+

+				var loggingEvent = new LoggingEvent(

+					this, new Date(), level, messages, exception);

+

+				this.callAppenders(loggingEvent);

+			}

+		};

+

+		this.callAppenders = function(loggingEvent) {

+			var effectiveAppenders = this.getEffectiveAppenders();

+			for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+				effectiveAppenders[i].doAppend(loggingEvent);

+			}

+		};

+

+		this.setLevel = function(level) {

+			// Having a level of null on the root logger would be very bad.

+			if (isRoot && level === null) {

+				handleError("Logger.setLevel: you cannot set the level of the root logger to null");

+			} else if (level instanceof Level) {

+				loggerLevel = level;

+			} else {

+				handleError("Logger.setLevel: level supplied to logger " +

+					this.name + " is not an instance of log4javascript.Level");

+			}

+		};

+

+		this.getLevel = function() {

+			return loggerLevel;

+		};

+

+		this.getEffectiveLevel = function() {

+			for (var logger = this; logger !== null; logger = logger.parent) {

+				var level = logger.getLevel();

+				if (level !== null) {

+					return level;

+				}

+			}

+		};

+

+		this.group = function(name, initiallyExpanded) {

+			if (enabled) {

+				var effectiveAppenders = this.getEffectiveAppenders();

+				for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+					effectiveAppenders[i].group(name, initiallyExpanded);

+				}

+			}

+		};

+

+		this.groupEnd = function() {

+			if (enabled) {

+				var effectiveAppenders = this.getEffectiveAppenders();

+				for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+					effectiveAppenders[i].groupEnd();

+				}

+			}

+		};

+

+		var timers = {};

+

+		this.time = function(name, level) {

+			if (enabled) {

+				if (isUndefined(name)) {

+					handleError("Logger.time: a name for the timer must be supplied");

+				} else if (level && !(level instanceof Level)) {

+					handleError("Logger.time: level supplied to timer " +

+						name + " is not an instance of log4javascript.Level");

+				} else {

+					timers[name] = new Timer(name, level);

+				}

+			}

+		};

+

+		this.timeEnd = function(name) {

+			if (enabled) {

+				if (isUndefined(name)) {

+					handleError("Logger.timeEnd: a name for the timer must be supplied");

+				} else if (timers[name]) {

+					var timer = timers[name];

+					var milliseconds = timer.getElapsedTime();

+					this.log(timer.level, ["Timer " + toStr(name) + " completed in " + milliseconds + "ms"]);

+					delete timers[name];

+				} else {

+					logLog.warn("Logger.timeEnd: no timer found with name " + name);

+				}

+			}

+		};

+

+		this.assert = function(expr) {

+			if (enabled && !expr) {

+				var args = [];

+				for (var i = 1, len = arguments.length; i < len; i++) {

+					args.push(arguments[i]);

+				}

+				args = (args.length > 0) ? args : ["Assertion Failure"];

+				args.push(newLine);

+				args.push(expr);

+				this.log(Level.ERROR, args);

+			}

+		};

+

+		this.toString = function() {

+			return "Logger[" + this.name + "]";

+		};

+	}

+

+	Logger.prototype = {

+		trace: function() {

+			this.log(Level.TRACE, arguments);

+		},

+

+		debug: function() {

+			this.log(Level.DEBUG, arguments);

+		},

+

+		info: function() {

+			this.log(Level.INFO, arguments);

+		},

+

+		warn: function() {

+			this.log(Level.WARN, arguments);

+		},

+

+		error: function() {

+			this.log(Level.ERROR, arguments);

+		},

+

+		fatal: function() {

+			this.log(Level.FATAL, arguments);

+		},

+

+		isEnabledFor: function(level) {

+			return level.isGreaterOrEqual(this.getEffectiveLevel());

+		},

+

+		isTraceEnabled: function() {

+			return this.isEnabledFor(Level.TRACE);

+		},

+

+		isDebugEnabled: function() {

+			return this.isEnabledFor(Level.DEBUG);

+		},

+

+		isInfoEnabled: function() {

+			return this.isEnabledFor(Level.INFO);

+		},

+

+		isWarnEnabled: function() {

+			return this.isEnabledFor(Level.WARN);

+		},

+

+		isErrorEnabled: function() {

+			return this.isEnabledFor(Level.ERROR);

+		},

+

+		isFatalEnabled: function() {

+			return this.isEnabledFor(Level.FATAL);

+		}

+	};

+

+	Logger.prototype.trace.isEntryPoint = true;

+	Logger.prototype.debug.isEntryPoint = true;

+	Logger.prototype.info.isEntryPoint = true;

+	Logger.prototype.warn.isEntryPoint = true;

+	Logger.prototype.error.isEntryPoint = true;

+	Logger.prototype.fatal.isEntryPoint = true;

+

+	/* ---------------------------------------------------------------------- */

+	// Logger access methods

+

+	// Hashtable of loggers keyed by logger name

+	var loggers = {};

+	var loggerNames = [];

+

+	var ROOT_LOGGER_DEFAULT_LEVEL = Level.DEBUG;

+	var rootLogger = new Logger(rootLoggerName);

+	rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);

+

+	log4javascript.getRootLogger = function() {

+		return rootLogger;

+	};

+

+	log4javascript.getLogger = function(loggerName) {

+		// Use default logger if loggerName is not specified or invalid

+		if (!(typeof loggerName == "string")) {

+			loggerName = anonymousLoggerName;

+			logLog.warn("log4javascript.getLogger: non-string logger name "	+

+				toStr(loggerName) + " supplied, returning anonymous logger");

+		}

+

+		// Do not allow retrieval of the root logger by name

+		if (loggerName == rootLoggerName) {

+			handleError("log4javascript.getLogger: root logger may not be obtained by name");

+		}

+

+		// Create the logger for this name if it doesn't already exist

+		if (!loggers[loggerName]) {

+			var logger = new Logger(loggerName);

+			loggers[loggerName] = logger;

+			loggerNames.push(loggerName);

+

+			// Set up parent logger, if it doesn't exist

+			var lastDotIndex = loggerName.lastIndexOf(".");

+			var parentLogger;

+			if (lastDotIndex > -1) {

+				var parentLoggerName = loggerName.substring(0, lastDotIndex);

+				parentLogger = log4javascript.getLogger(parentLoggerName); // Recursively sets up grandparents etc.

+			} else {

+				parentLogger = rootLogger;

+			}

+			parentLogger.addChild(logger);

+		}

+		return loggers[loggerName];

+	};

+

+	var defaultLogger = null;

+	log4javascript.getDefaultLogger = function() {

+		if (!defaultLogger) {

+			defaultLogger = log4javascript.getLogger(defaultLoggerName);

+			var a = new log4javascript.PopUpAppender();

+			defaultLogger.addAppender(a);

+		}

+		return defaultLogger;

+	};

+

+	var nullLogger = null;

+	log4javascript.getNullLogger = function() {

+		if (!nullLogger) {

+			nullLogger = new Logger(nullLoggerName);

+			nullLogger.setLevel(Level.OFF);

+		}

+		return nullLogger;

+	};

+

+	// Destroys all loggers

+	log4javascript.resetConfiguration = function() {

+		rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);

+		loggers = {};

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Logging events

+

+	var LoggingEvent = function(logger, timeStamp, level, messages,

+			exception) {

+		this.logger = logger;

+		this.timeStamp = timeStamp;

+		this.timeStampInMilliseconds = timeStamp.getTime();

+		this.timeStampInSeconds = Math.floor(this.timeStampInMilliseconds / 1000);

+		this.milliseconds = this.timeStamp.getMilliseconds();

+		this.level = level;

+		this.messages = messages;

+		this.exception = exception;

+	};

+

+	LoggingEvent.prototype = {

+		getThrowableStrRep: function() {

+			return this.exception ?

+				getExceptionStringRep(this.exception) : "";

+		},

+		getCombinedMessages: function() {

+			return (this.messages.length == 1) ? this.messages[0] :

+				   this.messages.join(newLine);

+		},

+		toString: function() {

+			return "LoggingEvent[" + this.level + "]";

+		}

+	};

+

+	log4javascript.LoggingEvent = LoggingEvent;

+

+	/* ---------------------------------------------------------------------- */

+	// Layout prototype

+

+	var Layout = function() {

+	};

+

+	Layout.prototype = {

+		defaults: {

+			loggerKey: "logger",

+			timeStampKey: "timestamp",

+			millisecondsKey: "milliseconds",

+			levelKey: "level",

+			messageKey: "message",

+			exceptionKey: "exception",

+			urlKey: "url"

+		},

+		loggerKey: "logger",

+		timeStampKey: "timestamp",

+		millisecondsKey: "milliseconds",

+		levelKey: "level",

+		messageKey: "message",

+		exceptionKey: "exception",

+		urlKey: "url",

+		batchHeader: "",

+		batchFooter: "",

+		batchSeparator: "",

+		returnsPostData: false,

+		overrideTimeStampsSetting: false,

+		useTimeStampsInMilliseconds: null,

+

+		format: function() {

+			handleError("Layout.format: layout supplied has no format() method");

+		},

+

+		ignoresThrowable: function() {

+			handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");

+		},

+

+		getContentType: function() {

+			return "text/plain";

+		},

+

+		allowBatching: function() {

+			return true;

+		},

+

+		setTimeStampsInMilliseconds: function(timeStampsInMilliseconds) {

+			this.overrideTimeStampsSetting = true;

+			this.useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);

+		},

+

+		isTimeStampsInMilliseconds: function() {

+			return this.overrideTimeStampsSetting ?

+				this.useTimeStampsInMilliseconds : useTimeStampsInMilliseconds;

+		},

+

+		getTimeStampValue: function(loggingEvent) {

+			return this.isTimeStampsInMilliseconds() ?

+				loggingEvent.timeStampInMilliseconds : loggingEvent.timeStampInSeconds;

+		},

+

+		getDataValues: function(loggingEvent, combineMessages) {

+			var dataValues = [

+				[this.loggerKey, loggingEvent.logger.name],

+				[this.timeStampKey, this.getTimeStampValue(loggingEvent)],

+				[this.levelKey, loggingEvent.level.name],

+				[this.urlKey, window.location.href],

+				[this.messageKey, combineMessages ? loggingEvent.getCombinedMessages() : loggingEvent.messages]

+			];

+			if (!this.isTimeStampsInMilliseconds()) {

+				dataValues.push([this.millisecondsKey, loggingEvent.milliseconds]);

+			}

+			if (loggingEvent.exception) {

+				dataValues.push([this.exceptionKey, getExceptionStringRep(loggingEvent.exception)]);

+			}

+			if (this.hasCustomFields()) {

+				for (var i = 0, len = this.customFields.length; i < len; i++) {

+					var val = this.customFields[i].value;

+

+					// Check if the value is a function. If so, execute it, passing it the

+					// current layout and the logging event

+					if (typeof val === "function") {

+						val = val(this, loggingEvent);

+					}

+					dataValues.push([this.customFields[i].name, val]);

+				}

+			}

+			return dataValues;

+		},

+

+		setKeys: function(loggerKey, timeStampKey, levelKey, messageKey,

+				exceptionKey, urlKey, millisecondsKey) {

+			this.loggerKey = extractStringFromParam(loggerKey, this.defaults.loggerKey);

+			this.timeStampKey = extractStringFromParam(timeStampKey, this.defaults.timeStampKey);

+			this.levelKey = extractStringFromParam(levelKey, this.defaults.levelKey);

+			this.messageKey = extractStringFromParam(messageKey, this.defaults.messageKey);

+			this.exceptionKey = extractStringFromParam(exceptionKey, this.defaults.exceptionKey);

+			this.urlKey = extractStringFromParam(urlKey, this.defaults.urlKey);

+			this.millisecondsKey = extractStringFromParam(millisecondsKey, this.defaults.millisecondsKey);

+		},

+

+		setCustomField: function(name, value) {

+			var fieldUpdated = false;

+			for (var i = 0, len = this.customFields.length; i < len; i++) {

+				if (this.customFields[i].name === name) {

+					this.customFields[i].value = value;

+					fieldUpdated = true;

+				}

+			}

+			if (!fieldUpdated) {

+				this.customFields.push({"name": name, "value": value});

+			}

+		},

+

+		hasCustomFields: function() {

+			return (this.customFields.length > 0);

+		},

+

+		toString: function() {

+			handleError("Layout.toString: all layouts must override this method");

+		}

+	};

+

+	log4javascript.Layout = Layout;

+

+	/* ---------------------------------------------------------------------- */

+	// Appender prototype

+

+	var Appender = function() {};

+

+	Appender.prototype = new EventSupport();

+

+	Appender.prototype.layout = new PatternLayout();

+	Appender.prototype.threshold = Level.ALL;

+	Appender.prototype.loggers = [];

+

+	// Performs threshold checks before delegating actual logging to the

+	// subclass's specific append method.

+	Appender.prototype.doAppend = function(loggingEvent) {

+		if (enabled && loggingEvent.level.level >= this.threshold.level) {

+			this.append(loggingEvent);

+		}

+	};

+

+	Appender.prototype.append = function(loggingEvent) {};

+

+	Appender.prototype.setLayout = function(layout) {

+		if (layout instanceof Layout) {

+			this.layout = layout;

+		} else {

+			handleError("Appender.setLayout: layout supplied to " +

+				this.toString() + " is not a subclass of Layout");

+		}

+	};

+

+	Appender.prototype.getLayout = function() {

+		return this.layout;

+	};

+

+	Appender.prototype.setThreshold = function(threshold) {

+		if (threshold instanceof Level) {

+			this.threshold = threshold;

+		} else {

+			handleError("Appender.setThreshold: threshold supplied to " +

+				this.toString() + " is not a subclass of Level");

+		}

+	};

+

+	Appender.prototype.getThreshold = function() {

+		return this.threshold;

+	};

+

+	Appender.prototype.setAddedToLogger = function(logger) {

+		this.loggers.push(logger);

+	};

+

+	Appender.prototype.setRemovedFromLogger = function(logger) {

+		array_remove(this.loggers, logger);

+	};

+

+	Appender.prototype.group = emptyFunction;

+	Appender.prototype.groupEnd = emptyFunction;

+

+	Appender.prototype.toString = function() {

+		handleError("Appender.toString: all appenders must override this method");

+	};

+

+	log4javascript.Appender = Appender;

+

+	/* ---------------------------------------------------------------------- */

+	// SimpleLayout 

+

+	function SimpleLayout() {

+		this.customFields = [];

+	}

+

+	SimpleLayout.prototype = new Layout();

+

+	SimpleLayout.prototype.format = function(loggingEvent) {

+		return loggingEvent.level.name + " - " + loggingEvent.getCombinedMessages();

+	};

+

+	SimpleLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	SimpleLayout.prototype.toString = function() {

+	    return "SimpleLayout";

+	};

+

+	log4javascript.SimpleLayout = SimpleLayout;

+	/* ----------------------------------------------------------------------- */

+	// NullLayout 

+

+	function NullLayout() {

+		this.customFields = [];

+	}

+

+	NullLayout.prototype = new Layout();

+

+	NullLayout.prototype.format = function(loggingEvent) {

+		return loggingEvent.messages;

+	};

+

+	NullLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	NullLayout.prototype.toString = function() {

+	    return "NullLayout";

+	};

+

+	log4javascript.NullLayout = NullLayout;

+/* ---------------------------------------------------------------------- */

+	// XmlLayout

+

+	function XmlLayout(combineMessages) {

+		this.combineMessages = extractBooleanFromParam(combineMessages, true);

+		this.customFields = [];

+	}

+

+	XmlLayout.prototype = new Layout();

+

+	XmlLayout.prototype.isCombinedMessages = function() {

+		return this.combineMessages;

+	};

+

+	XmlLayout.prototype.getContentType = function() {

+		return "text/xml";

+	};

+

+	XmlLayout.prototype.escapeCdata = function(str) {

+		return str.replace(/\]\]>/, "]]>]]&gt;<![CDATA[");

+	};

+

+	XmlLayout.prototype.format = function(loggingEvent) {

+		var layout = this;

+		var i, len;

+		function formatMessage(message) {

+			message = (typeof message === "string") ? message : toStr(message);

+			return "<log4javascript:message><![CDATA[" +

+				layout.escapeCdata(message) + "]]></log4javascript:message>";

+		}

+

+		var str = "<log4javascript:event logger=\"" + loggingEvent.logger.name +

+			"\" timestamp=\"" + this.getTimeStampValue(loggingEvent) + "\"";

+		if (!this.isTimeStampsInMilliseconds()) {

+			str += " milliseconds=\"" + loggingEvent.milliseconds + "\"";

+		}

+		str += " level=\"" + loggingEvent.level.name + "\">" + newLine;

+		if (this.combineMessages) {

+			str += formatMessage(loggingEvent.getCombinedMessages());

+		} else {

+			str += "<log4javascript:messages>" + newLine;

+			for (i = 0, len = loggingEvent.messages.length; i < len; i++) {

+				str += formatMessage(loggingEvent.messages[i]) + newLine;

+			}

+			str += "</log4javascript:messages>" + newLine;

+		}

+		if (this.hasCustomFields()) {

+			for (i = 0, len = this.customFields.length; i < len; i++) {

+				str += "<log4javascript:customfield name=\"" +

+					this.customFields[i].name + "\"><![CDATA[" +

+					this.customFields[i].value.toString() +

+					"]]></log4javascript:customfield>" + newLine;

+			}

+		}

+		if (loggingEvent.exception) {

+			str += "<log4javascript:exception><![CDATA[" +

+				getExceptionStringRep(loggingEvent.exception) +

+				"]]></log4javascript:exception>" + newLine;

+		}

+		str += "</log4javascript:event>" + newLine + newLine;

+		return str;

+	};

+

+	XmlLayout.prototype.ignoresThrowable = function() {

+	    return false;

+	};

+

+	XmlLayout.prototype.toString = function() {

+	    return "XmlLayout";

+	};

+

+	log4javascript.XmlLayout = XmlLayout;

+	/* ---------------------------------------------------------------------- */

+	// JsonLayout related

+

+	function escapeNewLines(str) {

+		return str.replace(/\r\n|\r|\n/g, "\\r\\n");

+	}

+

+	function JsonLayout(readable, combineMessages) {

+		this.readable = extractBooleanFromParam(readable, false);

+		this.combineMessages = extractBooleanFromParam(combineMessages, true);

+		this.batchHeader = this.readable ? "[" + newLine : "[";

+		this.batchFooter = this.readable ? "]" + newLine : "]";

+		this.batchSeparator = this.readable ? "," + newLine : ",";

+		this.setKeys();

+		this.colon = this.readable ? ": " : ":";

+		this.tab = this.readable ? "\t" : "";

+		this.lineBreak = this.readable ? newLine : "";

+		this.customFields = [];

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// JsonLayout

+

+	JsonLayout.prototype = new Layout();

+

+	JsonLayout.prototype.isReadable = function() {

+		return this.readable;

+	};

+

+	JsonLayout.prototype.isCombinedMessages = function() {

+		return this.combineMessages;

+	};

+

+    JsonLayout.prototype.format = function(loggingEvent) {

+        var layout = this;

+        var dataValues = this.getDataValues(loggingEvent, this.combineMessages);

+        var str = "{" + this.lineBreak;

+        var i, len;

+

+        function formatValue(val, prefix, expand) {

+            // Check the type of the data value to decide whether quotation marks

+            // or expansion are required

+            var formattedValue;

+            var valType = typeof val;

+            if (val instanceof Date) {

+                formattedValue = String(val.getTime());

+            } else if (expand && (val instanceof Array)) {

+                formattedValue = "[" + layout.lineBreak;

+                for (var i = 0, len = val.length; i < len; i++) {

+                    var childPrefix = prefix + layout.tab;

+                    formattedValue += childPrefix + formatValue(val[i], childPrefix, false);

+                    if (i < val.length - 1) {

+                        formattedValue += ",";

+                    }

+                    formattedValue += layout.lineBreak;

+                }

+                formattedValue += prefix + "]";

+            } else if (valType !== "number" && valType !== "boolean") {

+                formattedValue = "\"" + escapeNewLines(toStr(val).replace(/\"/g, "\\\"")) + "\"";

+            } else {

+                formattedValue = val;

+            }

+            return formattedValue;

+        }

+

+        for (i = 0, len = dataValues.length - 1; i <= len; i++) {

+            str += this.tab + "\"" + dataValues[i][0] + "\"" + this.colon + formatValue(dataValues[i][1], this.tab, true);

+            if (i < len) {

+                str += ",";

+            }

+            str += this.lineBreak;

+        }

+

+        str += "}" + this.lineBreak;

+        return str;

+    };

+

+	JsonLayout.prototype.ignoresThrowable = function() {

+	    return false;

+	};

+

+	JsonLayout.prototype.toString = function() {

+	    return "JsonLayout";

+	};

+

+	JsonLayout.prototype.getContentType = function() {

+		return "application/json";

+	};

+

+	log4javascript.JsonLayout = JsonLayout;

+	/* ---------------------------------------------------------------------- */

+	// HttpPostDataLayout

+

+	function HttpPostDataLayout() {

+		this.setKeys();

+		this.customFields = [];

+		this.returnsPostData = true;

+	}

+

+	HttpPostDataLayout.prototype = new Layout();

+

+	// Disable batching

+	HttpPostDataLayout.prototype.allowBatching = function() {

+		return false;

+	};

+

+	HttpPostDataLayout.prototype.format = function(loggingEvent) {

+		var dataValues = this.getDataValues(loggingEvent);

+		var queryBits = [];

+		for (var i = 0, len = dataValues.length; i < len; i++) {

+			var val = (dataValues[i][1] instanceof Date) ?

+				String(dataValues[i][1].getTime()) : dataValues[i][1];

+			queryBits.push(urlEncode(dataValues[i][0]) + "=" + urlEncode(val));

+		}

+		return queryBits.join("&");

+	};

+

+	HttpPostDataLayout.prototype.ignoresThrowable = function(loggingEvent) {

+	    return false;

+	};

+

+	HttpPostDataLayout.prototype.toString = function() {

+	    return "HttpPostDataLayout";

+	};

+

+	log4javascript.HttpPostDataLayout = HttpPostDataLayout;

+	/* ---------------------------------------------------------------------- */

+	// formatObjectExpansion

+

+	function formatObjectExpansion(obj, depth, indentation) {

+		var objectsExpanded = [];

+

+		function doFormat(obj, depth, indentation) {

+			var i, j, len, childDepth, childIndentation, childLines, expansion,

+				childExpansion;

+

+			if (!indentation) {

+				indentation = "";

+			}

+

+			function formatString(text) {

+				var lines = splitIntoLines(text);

+				for (var j = 1, jLen = lines.length; j < jLen; j++) {

+					lines[j] = indentation + lines[j];

+				}

+				return lines.join(newLine);

+			}

+

+			if (obj === null) {

+				return "null";

+			} else if (typeof obj == "undefined") {

+				return "undefined";

+			} else if (typeof obj == "string") {

+				return formatString(obj);

+			} else if (typeof obj == "object" && array_contains(objectsExpanded, obj)) {

+				try {

+					expansion = toStr(obj);

+				} catch (ex) {

+					expansion = "Error formatting property. Details: " + getExceptionStringRep(ex);

+				}

+				return expansion + " [already expanded]";

+			} else if ((obj instanceof Array) && depth > 0) {

+				objectsExpanded.push(obj);

+				expansion = "[" + newLine;

+				childDepth = depth - 1;

+				childIndentation = indentation + "  ";

+				childLines = [];

+				for (i = 0, len = obj.length; i < len; i++) {

+					try {

+						childExpansion = doFormat(obj[i], childDepth, childIndentation);

+						childLines.push(childIndentation + childExpansion);

+					} catch (ex) {

+						childLines.push(childIndentation + "Error formatting array member. Details: " +

+							getExceptionStringRep(ex) + "");

+					}

+				}

+				expansion += childLines.join("," + newLine) + newLine + indentation + "]";

+				return expansion;

+            } else if (Object.prototype.toString.call(obj) == "[object Date]") {

+                return obj.toString();

+			} else if (typeof obj == "object" && depth > 0) {

+				objectsExpanded.push(obj);

+				expansion = "{" + newLine;

+				childDepth = depth - 1;

+				childIndentation = indentation + "  ";

+				childLines = [];

+				for (i in obj) {

+					try {

+						childExpansion = doFormat(obj[i], childDepth, childIndentation);

+						childLines.push(childIndentation + i + ": " + childExpansion);

+					} catch (ex) {

+						childLines.push(childIndentation + i + ": Error formatting property. Details: " +

+							getExceptionStringRep(ex));

+					}

+				}

+				expansion += childLines.join("," + newLine) + newLine + indentation + "}";

+				return expansion;

+			} else {

+				return formatString(toStr(obj));

+			}

+		}

+		return doFormat(obj, depth, indentation);

+	}

+	/* ---------------------------------------------------------------------- */

+	// Date-related stuff

+

+	var SimpleDateFormat;

+

+	(function() {

+		var regex = /('[^']*')|(G+|y+|M+|w+|W+|D+|d+|F+|E+|a+|H+|k+|K+|h+|m+|s+|S+|Z+)|([a-zA-Z]+)|([^a-zA-Z']+)/;

+		var monthNames = ["January", "February", "March", "April", "May", "June",

+			"July", "August", "September", "October", "November", "December"];

+		var dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

+		var TEXT2 = 0, TEXT3 = 1, NUMBER = 2, YEAR = 3, MONTH = 4, TIMEZONE = 5;

+		var types = {

+			G : TEXT2,

+			y : YEAR,

+			M : MONTH,

+			w : NUMBER,

+			W : NUMBER,

+			D : NUMBER,

+			d : NUMBER,

+			F : NUMBER,

+			E : TEXT3,

+			a : TEXT2,

+			H : NUMBER,

+			k : NUMBER,

+			K : NUMBER,

+			h : NUMBER,

+			m : NUMBER,

+			s : NUMBER,

+			S : NUMBER,

+			Z : TIMEZONE

+		};

+		var ONE_DAY = 24 * 60 * 60 * 1000;

+		var ONE_WEEK = 7 * ONE_DAY;

+		var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK = 1;

+

+		var newDateAtMidnight = function(year, month, day) {

+			var d = new Date(year, month, day, 0, 0, 0);

+			d.setMilliseconds(0);

+			return d;

+		};

+

+		Date.prototype.getDifference = function(date) {

+			return this.getTime() - date.getTime();

+		};

+

+		Date.prototype.isBefore = function(d) {

+			return this.getTime() < d.getTime();

+		};

+

+		Date.prototype.getUTCTime = function() {

+			return Date.UTC(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours(), this.getMinutes(),

+					this.getSeconds(), this.getMilliseconds());

+		};

+

+		Date.prototype.getTimeSince = function(d) {

+			return this.getUTCTime() - d.getUTCTime();

+		};

+

+		Date.prototype.getPreviousSunday = function() {

+			// Using midday avoids any possibility of DST messing things up

+			var midday = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 12, 0, 0);

+			var previousSunday = new Date(midday.getTime() - this.getDay() * ONE_DAY);

+			return newDateAtMidnight(previousSunday.getFullYear(), previousSunday.getMonth(),

+					previousSunday.getDate());

+		};

+

+		Date.prototype.getWeekInYear = function(minimalDaysInFirstWeek) {

+			if (isUndefined(this.minimalDaysInFirstWeek)) {

+				minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;

+			}

+			var previousSunday = this.getPreviousSunday();

+			var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);

+			var numberOfSundays = previousSunday.isBefore(startOfYear) ?

+				0 : 1 + Math.floor(previousSunday.getTimeSince(startOfYear) / ONE_WEEK);

+			var numberOfDaysInFirstWeek =  7 - startOfYear.getDay();

+			var weekInYear = numberOfSundays;

+			if (numberOfDaysInFirstWeek < minimalDaysInFirstWeek) {

+				weekInYear--;

+			}

+			return weekInYear;

+		};

+

+		Date.prototype.getWeekInMonth = function(minimalDaysInFirstWeek) {

+			if (isUndefined(this.minimalDaysInFirstWeek)) {

+				minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;

+			}

+			var previousSunday = this.getPreviousSunday();

+			var startOfMonth = newDateAtMidnight(this.getFullYear(), this.getMonth(), 1);

+			var numberOfSundays = previousSunday.isBefore(startOfMonth) ?

+				0 : 1 + Math.floor(previousSunday.getTimeSince(startOfMonth) / ONE_WEEK);

+			var numberOfDaysInFirstWeek =  7 - startOfMonth.getDay();

+			var weekInMonth = numberOfSundays;

+			if (numberOfDaysInFirstWeek >= minimalDaysInFirstWeek) {

+				weekInMonth++;

+			}

+			return weekInMonth;

+		};

+

+		Date.prototype.getDayInYear = function() {

+			var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);

+			return 1 + Math.floor(this.getTimeSince(startOfYear) / ONE_DAY);

+		};

+

+		/* ------------------------------------------------------------------ */

+

+		SimpleDateFormat = function(formatString) {

+			this.formatString = formatString;

+		};

+

+		/**

+		 * Sets the minimum number of days in a week in order for that week to

+		 * be considered as belonging to a particular month or year

+		 */

+		SimpleDateFormat.prototype.setMinimalDaysInFirstWeek = function(days) {

+			this.minimalDaysInFirstWeek = days;

+		};

+

+		SimpleDateFormat.prototype.getMinimalDaysInFirstWeek = function() {

+			return isUndefined(this.minimalDaysInFirstWeek)	?

+				DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK : this.minimalDaysInFirstWeek;

+		};

+

+		var padWithZeroes = function(str, len) {

+			while (str.length < len) {

+				str = "0" + str;

+			}

+			return str;

+		};

+

+		var formatText = function(data, numberOfLetters, minLength) {

+			return (numberOfLetters >= 4) ? data : data.substr(0, Math.max(minLength, numberOfLetters));

+		};

+

+		var formatNumber = function(data, numberOfLetters) {

+			var dataString = "" + data;

+			// Pad with 0s as necessary

+			return padWithZeroes(dataString, numberOfLetters);

+		};

+

+		SimpleDateFormat.prototype.format = function(date) {

+			var formattedString = "";

+			var result;

+			var searchString = this.formatString;

+			while ((result = regex.exec(searchString))) {

+				var quotedString = result[1];

+				var patternLetters = result[2];

+				var otherLetters = result[3];

+				var otherCharacters = result[4];

+

+				// If the pattern matched is quoted string, output the text between the quotes

+				if (quotedString) {

+					if (quotedString == "''") {

+						formattedString += "'";

+					} else {

+						formattedString += quotedString.substring(1, quotedString.length - 1);

+					}

+				} else if (otherLetters) {

+					// Swallow non-pattern letters by doing nothing here

+				} else if (otherCharacters) {

+					// Simply output other characters

+					formattedString += otherCharacters;

+				} else if (patternLetters) {

+					// Replace pattern letters

+					var patternLetter = patternLetters.charAt(0);

+					var numberOfLetters = patternLetters.length;

+					var rawData = "";

+					switch(patternLetter) {

+						case "G":

+							rawData = "AD";

+							break;

+						case "y":

+							rawData = date.getFullYear();

+							break;

+						case "M":

+							rawData = date.getMonth();

+							break;

+						case "w":

+							rawData = date.getWeekInYear(this.getMinimalDaysInFirstWeek());

+							break;

+						case "W":

+							rawData = date.getWeekInMonth(this.getMinimalDaysInFirstWeek());

+							break;

+						case "D":

+							rawData = date.getDayInYear();

+							break;

+						case "d":

+							rawData = date.getDate();

+							break;

+						case "F":

+							rawData = 1 + Math.floor((date.getDate() - 1) / 7);

+							break;

+						case "E":

+							rawData = dayNames[date.getDay()];

+							break;

+						case "a":

+							rawData = (date.getHours() >= 12) ? "PM" : "AM";

+							break;

+						case "H":

+							rawData = date.getHours();

+							break;

+						case "k":

+							rawData = date.getHours() || 24;

+							break;

+						case "K":

+							rawData = date.getHours() % 12;

+							break;

+						case "h":

+							rawData = (date.getHours() % 12) || 12;

+							break;

+						case "m":

+							rawData = date.getMinutes();

+							break;

+						case "s":

+							rawData = date.getSeconds();

+							break;

+						case "S":

+							rawData = date.getMilliseconds();

+							break;

+						case "Z":

+							rawData = date.getTimezoneOffset(); // This returns the number of minutes since GMT was this time.

+							break;

+					}

+					// Format the raw data depending on the type

+					switch(types[patternLetter]) {

+						case TEXT2:

+							formattedString += formatText(rawData, numberOfLetters, 2);

+							break;

+						case TEXT3:

+							formattedString += formatText(rawData, numberOfLetters, 3);

+							break;

+						case NUMBER:

+							formattedString += formatNumber(rawData, numberOfLetters);

+							break;

+						case YEAR:

+							if (numberOfLetters <= 3) {

+								// Output a 2-digit year

+								var dataString = "" + rawData;

+								formattedString += dataString.substr(2, 2);

+							} else {

+								formattedString += formatNumber(rawData, numberOfLetters);

+							}

+							break;

+						case MONTH:

+							if (numberOfLetters >= 3) {

+								formattedString += formatText(monthNames[rawData], numberOfLetters, numberOfLetters);

+							} else {

+								// NB. Months returned by getMonth are zero-based

+								formattedString += formatNumber(rawData + 1, numberOfLetters);

+							}

+							break;

+						case TIMEZONE:

+							var isPositive = (rawData > 0);

+							// The following line looks like a mistake but isn't

+							// because of the way getTimezoneOffset measures.

+							var prefix = isPositive ? "-" : "+";

+							var absData = Math.abs(rawData);

+

+							// Hours

+							var hours = "" + Math.floor(absData / 60);

+							hours = padWithZeroes(hours, 2);

+							// Minutes

+							var minutes = "" + (absData % 60);

+							minutes = padWithZeroes(minutes, 2);

+

+							formattedString += prefix + hours + minutes;

+							break;

+					}

+				}

+				searchString = searchString.substr(result.index + result[0].length);

+			}

+			return formattedString;

+		};

+	})();

+

+	log4javascript.SimpleDateFormat = SimpleDateFormat;

+

+	/* ---------------------------------------------------------------------- */

+	// PatternLayout

+

+	function PatternLayout(pattern) {

+		if (pattern) {

+			this.pattern = pattern;

+		} else {

+			this.pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;

+		}

+		this.customFields = [];

+	}

+

+	PatternLayout.TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n";

+	PatternLayout.DEFAULT_CONVERSION_PATTERN = "%m%n";

+	PatternLayout.ISO8601_DATEFORMAT = "yyyy-MM-dd HH:mm:ss,SSS";

+	PatternLayout.DATETIME_DATEFORMAT = "dd MMM yyyy HH:mm:ss,SSS";

+	PatternLayout.ABSOLUTETIME_DATEFORMAT = "HH:mm:ss,SSS";

+

+	PatternLayout.prototype = new Layout();

+

+	PatternLayout.prototype.format = function(loggingEvent) {

+		var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;

+		var formattedString = "";

+		var result;

+		var searchString = this.pattern;

+

+		// Cannot use regex global flag since it doesn't work with exec in IE5

+		while ((result = regex.exec(searchString))) {

+			var matchedString = result[0];

+			var padding = result[1];

+			var truncation = result[2];

+			var conversionCharacter = result[3];

+			var specifier = result[5];

+			var text = result[6];

+

+			// Check if the pattern matched was just normal text

+			if (text) {

+				formattedString += "" + text;

+			} else {

+				// Create a raw replacement string based on the conversion

+				// character and specifier

+				var replacement = "";

+				switch(conversionCharacter) {

+					case "a": // Array of messages

+					case "m": // Message

+						var depth = 0;

+						if (specifier) {

+							depth = parseInt(specifier, 10);

+							if (isNaN(depth)) {

+								handleError("PatternLayout.format: invalid specifier '" +

+									specifier + "' for conversion character '" + conversionCharacter +

+									"' - should be a number");

+								depth = 0;

+							}

+						}

+						var messages = (conversionCharacter === "a") ? loggingEvent.messages[0] : loggingEvent.messages;

+						for (var i = 0, len = messages.length; i < len; i++) {

+							if (i > 0 && (replacement.charAt(replacement.length - 1) !== " ")) {

+								replacement += " ";

+							}

+							if (depth === 0) {

+								replacement += messages[i];

+							} else {

+								replacement += formatObjectExpansion(messages[i], depth);

+							}

+						}

+						break;

+					case "c": // Logger name

+						var loggerName = loggingEvent.logger.name;

+						if (specifier) {

+							var precision = parseInt(specifier, 10);

+							var loggerNameBits = loggingEvent.logger.name.split(".");

+							if (precision >= loggerNameBits.length) {

+								replacement = loggerName;

+							} else {

+								replacement = loggerNameBits.slice(loggerNameBits.length - precision).join(".");

+							}

+						} else {

+							replacement = loggerName;

+						}

+						break;

+					case "d": // Date

+						var dateFormat = PatternLayout.ISO8601_DATEFORMAT;

+						if (specifier) {

+							dateFormat = specifier;

+							// Pick up special cases

+							if (dateFormat == "ISO8601") {

+								dateFormat = PatternLayout.ISO8601_DATEFORMAT;

+							} else if (dateFormat == "ABSOLUTE") {

+								dateFormat = PatternLayout.ABSOLUTETIME_DATEFORMAT;

+							} else if (dateFormat == "DATE") {

+								dateFormat = PatternLayout.DATETIME_DATEFORMAT;

+							}

+						}

+						// Format the date

+						replacement = (new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);

+						break;

+					case "f": // Custom field

+						if (this.hasCustomFields()) {

+							var fieldIndex = 0;

+							if (specifier) {

+								fieldIndex = parseInt(specifier, 10);

+								if (isNaN(fieldIndex)) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - should be a number");

+								} else if (fieldIndex === 0) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - must be greater than zero");

+								} else if (fieldIndex > this.customFields.length) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - there aren't that many custom fields");

+								} else {

+									fieldIndex = fieldIndex - 1;

+								}

+							}

+                            var val = this.customFields[fieldIndex].value;

+                            if (typeof val == "function") {

+                                val = val(this, loggingEvent);

+                            }

+                            replacement = val;

+						}

+						break;

+					case "n": // New line

+						replacement = newLine;

+						break;

+					case "p": // Level

+						replacement = loggingEvent.level.name;

+						break;

+					case "r": // Milliseconds since log4javascript startup

+						replacement = "" + loggingEvent.timeStamp.getDifference(applicationStartDate);

+						break;

+					case "%": // Literal % sign

+						replacement = "%";

+						break;

+					default:

+						replacement = matchedString;

+						break;

+				}

+				// Format the replacement according to any padding or

+				// truncation specified

+				var l;

+

+				// First, truncation

+				if (truncation) {

+					l = parseInt(truncation.substr(1), 10);

+					var strLen = replacement.length;

+					if (l < strLen) {

+						replacement = replacement.substring(strLen - l, strLen);

+					}

+				}

+				// Next, padding

+				if (padding) {

+					if (padding.charAt(0) == "-") {

+						l = parseInt(padding.substr(1), 10);

+						// Right pad with spaces

+						while (replacement.length < l) {

+							replacement += " ";

+						}

+					} else {

+						l = parseInt(padding, 10);

+						// Left pad with spaces

+						while (replacement.length < l) {

+							replacement = " " + replacement;

+						}

+					}

+				}

+				formattedString += replacement;

+			}

+			searchString = searchString.substr(result.index + result[0].length);

+		}

+		return formattedString;

+	};

+

+	PatternLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	PatternLayout.prototype.toString = function() {

+	    return "PatternLayout";

+	};

+

+	log4javascript.PatternLayout = PatternLayout;

+	/* ---------------------------------------------------------------------- */

+	// AjaxAppender related

+

+	var xmlHttpFactories = [

+		function() { return new XMLHttpRequest(); },

+		function() { return new ActiveXObject("Msxml2.XMLHTTP"); },

+		function() { return new ActiveXObject("Microsoft.XMLHTTP"); }

+	];

+

+	var getXmlHttp = function(errorHandler) {

+		// This is only run the first time; the value of getXmlHttp gets

+		// replaced with the factory that succeeds on the first run

+		var xmlHttp = null, factory;

+		for (var i = 0, len = xmlHttpFactories.length; i < len; i++) {

+			factory = xmlHttpFactories[i];

+			try {

+				xmlHttp = factory();

+				getXmlHttp = factory;

+				return xmlHttp;

+			} catch (e) {

+			}

+		}

+		// If we're here, all factories have failed, so throw an error

+		if (errorHandler) {

+			errorHandler();

+		} else {

+			handleError("getXmlHttp: unable to obtain XMLHttpRequest object");

+		}

+	};

+

+	function isHttpRequestSuccessful(xmlHttp) {

+		return isUndefined(xmlHttp.status) || xmlHttp.status === 0 ||

+			(xmlHttp.status >= 200 && xmlHttp.status < 300) ||

+			xmlHttp.status == 1223 /* Fix for IE */;

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// AjaxAppender

+

+	function AjaxAppender(url) {

+		var appender = this;

+		var isSupported = true;

+		if (!url) {

+			handleError("AjaxAppender: URL must be specified in constructor");

+			isSupported = false;

+		}

+

+		var timed = this.defaults.timed;

+		var waitForResponse = this.defaults.waitForResponse;

+		var batchSize = this.defaults.batchSize;

+		var timerInterval = this.defaults.timerInterval;

+		var requestSuccessCallback = this.defaults.requestSuccessCallback;

+		var failCallback = this.defaults.failCallback;

+		var postVarName = this.defaults.postVarName;

+		var sendAllOnUnload = this.defaults.sendAllOnUnload;

+		var contentType = this.defaults.contentType;

+		var sessionId = null;

+

+		var queuedLoggingEvents = [];

+		var queuedRequests = [];

+		var headers = [];

+		var sending = false;

+		var initialized = false;

+

+		// Configuration methods. The function scope is used to prevent

+		// direct alteration to the appender configuration properties.

+		function checkCanConfigure(configOptionName) {

+			if (initialized) {

+				handleError("AjaxAppender: configuration option '" +

+					configOptionName +

+					"' may not be set after the appender has been initialized");

+				return false;

+			}

+			return true;

+		}

+

+		this.getSessionId = function() { return sessionId; };

+		this.setSessionId = function(sessionIdParam) {

+			sessionId = extractStringFromParam(sessionIdParam, null);

+			this.layout.setCustomField("sessionid", sessionId);

+		};

+

+		this.setLayout = function(layoutParam) {

+			if (checkCanConfigure("layout")) {

+				this.layout = layoutParam;

+				// Set the session id as a custom field on the layout, if not already present

+				if (sessionId !== null) {

+					this.setSessionId(sessionId);

+				}

+			}

+		};

+

+		this.isTimed = function() { return timed; };

+		this.setTimed = function(timedParam) {

+			if (checkCanConfigure("timed")) {

+				timed = bool(timedParam);

+			}

+		};

+

+		this.getTimerInterval = function() { return timerInterval; };

+		this.setTimerInterval = function(timerIntervalParam) {

+			if (checkCanConfigure("timerInterval")) {

+				timerInterval = extractIntFromParam(timerIntervalParam, timerInterval);

+			}

+		};

+

+		this.isWaitForResponse = function() { return waitForResponse; };

+		this.setWaitForResponse = function(waitForResponseParam) {

+			if (checkCanConfigure("waitForResponse")) {

+				waitForResponse = bool(waitForResponseParam);

+			}

+		};

+

+		this.getBatchSize = function() { return batchSize; };

+		this.setBatchSize = function(batchSizeParam) {

+			if (checkCanConfigure("batchSize")) {

+				batchSize = extractIntFromParam(batchSizeParam, batchSize);

+			}

+		};

+

+		this.isSendAllOnUnload = function() { return sendAllOnUnload; };

+		this.setSendAllOnUnload = function(sendAllOnUnloadParam) {

+			if (checkCanConfigure("sendAllOnUnload")) {

+				sendAllOnUnload = extractBooleanFromParam(sendAllOnUnloadParam, sendAllOnUnload);

+			}

+		};

+

+		this.setRequestSuccessCallback = function(requestSuccessCallbackParam) {

+			requestSuccessCallback = extractFunctionFromParam(requestSuccessCallbackParam, requestSuccessCallback);

+		};

+

+		this.setFailCallback = function(failCallbackParam) {

+			failCallback = extractFunctionFromParam(failCallbackParam, failCallback);

+		};

+

+		this.getPostVarName = function() { return postVarName; };

+		this.setPostVarName = function(postVarNameParam) {

+			if (checkCanConfigure("postVarName")) {

+				postVarName = extractStringFromParam(postVarNameParam, postVarName);

+			}

+		};

+

+		this.getHeaders = function() { return headers; };

+		this.addHeader = function(name, value) {

+			if (name.toLowerCase() == "content-type") {

+				contentType = value;

+			} else {

+				headers.push( { name: name, value: value } );

+			}

+		};

+

+		// Internal functions

+		function sendAll() {

+			if (isSupported && enabled) {

+				sending = true;

+				var currentRequestBatch;

+				if (waitForResponse) {

+					// Send the first request then use this function as the callback once

+					// the response comes back

+					if (queuedRequests.length > 0) {

+						currentRequestBatch = queuedRequests.shift();

+						sendRequest(preparePostData(currentRequestBatch), sendAll);

+					} else {

+						sending = false;

+						if (timed) {

+							scheduleSending();

+						}

+					}

+				} else {

+					// Rattle off all the requests without waiting to see the response

+					while ((currentRequestBatch = queuedRequests.shift())) {

+						sendRequest(preparePostData(currentRequestBatch));

+					}

+					sending = false;

+					if (timed) {

+						scheduleSending();

+					}

+				}

+			}

+		}

+

+		this.sendAll = sendAll;

+

+		// Called when the window unloads. At this point we're past caring about

+		// waiting for responses or timers or incomplete batches - everything

+		// must go, now

+		function sendAllRemaining() {

+			var sendingAnything = false;

+			if (isSupported && enabled) {

+				// Create requests for everything left over, batched as normal

+				var actualBatchSize = appender.getLayout().allowBatching() ? batchSize : 1;

+				var currentLoggingEvent;

+				var batchedLoggingEvents = [];

+				while ((currentLoggingEvent = queuedLoggingEvents.shift())) {

+					batchedLoggingEvents.push(currentLoggingEvent);

+					if (queuedLoggingEvents.length >= actualBatchSize) {

+						// Queue this batch of log entries

+						queuedRequests.push(batchedLoggingEvents);

+						batchedLoggingEvents = [];

+					}

+				}

+				// If there's a partially completed batch, add it

+				if (batchedLoggingEvents.length > 0) {

+					queuedRequests.push(batchedLoggingEvents);

+				}

+				sendingAnything = (queuedRequests.length > 0);

+				waitForResponse = false;

+				timed = false;

+				sendAll();

+			}

+			return sendingAnything;

+		}

+

+		this.sendAllRemaining = sendAllRemaining;

+

+		function preparePostData(batchedLoggingEvents) {

+			// Format the logging events

+			var formattedMessages = [];

+			var currentLoggingEvent;

+			var postData = "";

+			while ((currentLoggingEvent = batchedLoggingEvents.shift())) {

+				var currentFormattedMessage = appender.getLayout().format(currentLoggingEvent);

+				if (appender.getLayout().ignoresThrowable()) {

+					currentFormattedMessage += currentLoggingEvent.getThrowableStrRep();

+				}

+				formattedMessages.push(currentFormattedMessage);

+			}

+			// Create the post data string

+			if (batchedLoggingEvents.length == 1) {

+				postData = formattedMessages.join("");

+			} else {

+				postData = appender.getLayout().batchHeader +

+					formattedMessages.join(appender.getLayout().batchSeparator) +

+					appender.getLayout().batchFooter;

+			}

+			if (contentType == appender.defaults.contentType) {

+				postData = appender.getLayout().returnsPostData ? postData :

+					urlEncode(postVarName) + "=" + urlEncode(postData);

+				// Add the layout name to the post data

+				if (postData.length > 0) {

+					postData += "&";

+				}

+				postData += "layout=" + urlEncode(appender.getLayout().toString());

+			}

+			return postData;

+		}

+

+		function scheduleSending() {

+			window.setTimeout(sendAll, timerInterval);

+		}

+

+		function xmlHttpErrorHandler() {

+			var msg = "AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";

+			handleError(msg);

+			isSupported = false;

+			if (failCallback) {

+				failCallback(msg);

+			}

+		}

+

+		function sendRequest(postData, successCallback) {

+			try {

+				var xmlHttp = getXmlHttp(xmlHttpErrorHandler);

+				if (isSupported) {

+					if (xmlHttp.overrideMimeType) {

+						xmlHttp.overrideMimeType(appender.getLayout().getContentType());

+					}

+					xmlHttp.onreadystatechange = function() {

+						if (xmlHttp.readyState == 4) {

+							if (isHttpRequestSuccessful(xmlHttp)) {

+								if (requestSuccessCallback) {

+									requestSuccessCallback(xmlHttp);

+								}

+								if (successCallback) {

+									successCallback(xmlHttp);

+								}

+							} else {

+								var msg = "AjaxAppender.append: XMLHttpRequest request to URL " +

+									url + " returned status code " + xmlHttp.status;

+								handleError(msg);

+								if (failCallback) {

+									failCallback(msg);

+								}

+							}

+							xmlHttp.onreadystatechange = emptyFunction;

+							xmlHttp = null;

+						}

+					};

+					xmlHttp.open("POST", url, true);

+					try {

+						for (var i = 0, header; header = headers[i++]; ) {

+							xmlHttp.setRequestHeader(header.name, header.value);

+						}

+						xmlHttp.setRequestHeader("Content-Type", contentType);

+					} catch (headerEx) {

+						var msg = "AjaxAppender.append: your browser's XMLHttpRequest implementation" +

+							" does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";

+						handleError(msg);

+						isSupported = false;

+						if (failCallback) {

+							failCallback(msg);

+						}

+						return;

+					}

+					xmlHttp.send(postData);

+				}

+			} catch (ex) {

+				var errMsg = "AjaxAppender.append: error sending log message to " + url;

+				handleError(errMsg, ex);

+				isSupported = false;

+				if (failCallback) {

+					failCallback(errMsg + ". Details: " + getExceptionStringRep(ex));

+				}

+			}

+		}

+

+		this.append = function(loggingEvent) {

+			if (isSupported) {

+				if (!initialized) {

+					init();

+				}

+				queuedLoggingEvents.push(loggingEvent);

+				var actualBatchSize = this.getLayout().allowBatching() ? batchSize : 1;

+

+				if (queuedLoggingEvents.length >= actualBatchSize) {

+					var currentLoggingEvent;

+					var batchedLoggingEvents = [];

+					while ((currentLoggingEvent = queuedLoggingEvents.shift())) {

+						batchedLoggingEvents.push(currentLoggingEvent);

+					}

+					// Queue this batch of log entries

+					queuedRequests.push(batchedLoggingEvents);

+

+					// If using a timer, the queue of requests will be processed by the

+					// timer function, so nothing needs to be done here.

+					if (!timed && (!waitForResponse || (waitForResponse && !sending))) {

+						sendAll();

+					}

+				}

+			}

+		};

+

+		function init() {

+			initialized = true;

+			// Add unload event to send outstanding messages

+			if (sendAllOnUnload) {

+				var oldBeforeUnload = window.onbeforeunload;

+				window.onbeforeunload = function() {

+					if (oldBeforeUnload) {

+						oldBeforeUnload();

+					}

+					if (sendAllRemaining()) {

+						return "Sending log messages";

+					}

+				};

+			}

+			// Start timer

+			if (timed) {

+				scheduleSending();

+			}

+		}

+	}

+

+	AjaxAppender.prototype = new Appender();

+

+	AjaxAppender.prototype.defaults = {

+		waitForResponse: false,

+		timed: false,

+		timerInterval: 1000,

+		batchSize: 1,

+		sendAllOnUnload: false,

+		requestSuccessCallback: null,

+		failCallback: null,

+		postVarName: "data",

+		contentType: "application/x-www-form-urlencoded"

+	};

+

+	AjaxAppender.prototype.layout = new HttpPostDataLayout();

+

+	AjaxAppender.prototype.toString = function() {

+		return "AjaxAppender";

+	};

+

+	log4javascript.AjaxAppender = AjaxAppender;

+

+	/* ---------------------------------------------------------------------- */

+	// Main load

+

+   log4javascript.setDocumentReady = function() {

+       pageLoaded = true;

+       log4javascript.dispatchEvent("load", {});

+   };

+

+    if (window.addEventListener) {

+        window.addEventListener("load", log4javascript.setDocumentReady, false);

+    } else if (window.attachEvent) {

+        window.attachEvent("onload", log4javascript.setDocumentReady);

+    } else {

+        var oldOnload = window.onload;

+        if (typeof window.onload != "function") {

+            window.onload = log4javascript.setDocumentReady;

+        } else {

+            window.onload = function(evt) {

+                if (oldOnload) {

+                    oldOnload(evt);

+                }

+                log4javascript.setDocumentReady();

+            };

+        }

+    }

+

+    // Ensure that the log4javascript object is available in the window. This

+    // is necessary for log4javascript to be available in IE if loaded using

+    // Dojo's module system

+    window.log4javascript = log4javascript;

+

+    return log4javascript;

+})();
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_uncompressed.js
new file mode 100644
index 0000000..a644e3b
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_uncompressed.js
@@ -0,0 +1,5879 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+/**

+ * log4javascript

+ *

+ * log4javascript is a logging framework for JavaScript based on log4j

+ * for Java. This file contains all core log4javascript code and is the only

+ * file required to use log4javascript, unless you require support for

+ * document.domain, in which case you will also need console.html, which must be

+ * stored in the same directory as the main log4javascript.js file.

+ *

+ * Author: Tim Down <tim@log4javascript.org>

+ * Version: 1.4.6

+ * Edition: log4javascript

+ * Build date: 19 March 2013

+ * Website: http://log4javascript.org

+ */

+

+/* -------------------------------------------------------------------------- */

+// Array-related stuff

+

+// Next three methods are solely for IE5, which is missing them

+if (!Array.prototype.push) {

+	Array.prototype.push = function() {

+		for (var i = 0, len = arguments.length; i < len; i++){

+			this[this.length] = arguments[i];

+		}

+		return this.length;

+	};

+}

+

+if (!Array.prototype.shift) {

+	Array.prototype.shift = function() {

+		if (this.length > 0) {

+			var firstItem = this[0];

+			for (var i = 0, len = this.length - 1; i < len; i++) {

+				this[i] = this[i + 1];

+			}

+			this.length = this.length - 1;

+			return firstItem;

+		}

+	};

+}

+

+if (!Array.prototype.splice) {

+	Array.prototype.splice = function(startIndex, deleteCount) {

+		var itemsAfterDeleted = this.slice(startIndex + deleteCount);

+		var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);

+		this.length = startIndex;

+		// Copy the arguments into a proper Array object

+		var argumentsArray = [];

+		for (var i = 0, len = arguments.length; i < len; i++) {

+			argumentsArray[i] = arguments[i];

+		}

+		var itemsToAppend = (argumentsArray.length > 2) ?

+			itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;

+		for (i = 0, len = itemsToAppend.length; i < len; i++) {

+			this.push(itemsToAppend[i]);

+		}

+		return itemsDeleted;

+	};

+}

+

+/* -------------------------------------------------------------------------- */

+

+var log4javascript = (function() {

+

+	function isUndefined(obj) {

+		return typeof obj == "undefined";

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// Custom event support

+

+	function EventSupport() {}

+

+	EventSupport.prototype = {

+		eventTypes: [],

+		eventListeners: {},

+		setEventTypes: function(eventTypesParam) {

+			if (eventTypesParam instanceof Array) {

+				this.eventTypes = eventTypesParam;

+				this.eventListeners = {};

+				for (var i = 0, len = this.eventTypes.length; i < len; i++) {

+					this.eventListeners[this.eventTypes[i]] = [];

+				}

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: setEventTypes: eventTypes parameter must be an Array");

+			}

+		},

+

+		addEventListener: function(eventType, listener) {

+			if (typeof listener == "function") {

+				if (!array_contains(this.eventTypes, eventType)) {

+					handleError("log4javascript.EventSupport [" + this + "]: addEventListener: no event called '" + eventType + "'");

+				}

+				this.eventListeners[eventType].push(listener);

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: addEventListener: listener must be a function");

+			}

+		},

+

+		removeEventListener: function(eventType, listener) {

+			if (typeof listener == "function") {

+				if (!array_contains(this.eventTypes, eventType)) {

+					handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: no event called '" + eventType + "'");

+				}

+				array_remove(this.eventListeners[eventType], listener);

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: listener must be a function");

+			}

+		},

+

+		dispatchEvent: function(eventType, eventArgs) {

+			if (array_contains(this.eventTypes, eventType)) {

+				var listeners = this.eventListeners[eventType];

+				for (var i = 0, len = listeners.length; i < len; i++) {

+					listeners[i](this, eventType, eventArgs);

+				}

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: dispatchEvent: no event called '" + eventType + "'");

+			}

+		}

+	};

+

+	/* -------------------------------------------------------------------------- */

+

+	var applicationStartDate = new Date();

+	var uniqueId = "log4javascript_" + applicationStartDate.getTime() + "_" +

+		Math.floor(Math.random() * 100000000);

+	var emptyFunction = function() {};

+	var newLine = "\r\n";

+	var pageLoaded = false;

+

+	// Create main log4javascript object; this will be assigned public properties

+	function Log4JavaScript() {}

+	Log4JavaScript.prototype = new EventSupport();

+

+	log4javascript = new Log4JavaScript();

+	log4javascript.version = "1.4.6";

+	log4javascript.edition = "log4javascript";

+

+	/* -------------------------------------------------------------------------- */

+	// Utility functions

+

+	function toStr(obj) {

+		if (obj && obj.toString) {

+			return obj.toString();

+		} else {

+			return String(obj);

+		}

+	}

+

+	function getExceptionMessage(ex) {

+		if (ex.message) {

+			return ex.message;

+		} else if (ex.description) {

+			return ex.description;

+		} else {

+			return toStr(ex);

+		}

+	}

+

+	// Gets the portion of the URL after the last slash

+	function getUrlFileName(url) {

+		var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\"));

+		return url.substr(lastSlashIndex + 1);

+	}

+

+	// Returns a nicely formatted representation of an error

+	function getExceptionStringRep(ex) {

+		if (ex) {

+			var exStr = "Exception: " + getExceptionMessage(ex);

+			try {

+				if (ex.lineNumber) {

+					exStr += " on line number " + ex.lineNumber;

+				}

+				if (ex.fileName) {

+					exStr += " in file " + getUrlFileName(ex.fileName);

+				}

+			} catch (localEx) {

+				logLog.warn("Unable to obtain file and line information for error");

+			}

+			if (showStackTraces && ex.stack) {

+				exStr += newLine + "Stack trace:" + newLine + ex.stack;

+			}

+			return exStr;

+		}

+		return null;

+	}

+

+	function bool(obj) {

+		return Boolean(obj);

+	}

+

+	function trim(str) {

+		return str.replace(/^\s+/, "").replace(/\s+$/, "");

+	}

+

+	function splitIntoLines(text) {

+		// Ensure all line breaks are \n only

+		var text2 = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");

+		return text2.split("\n");

+	}

+

+	var urlEncode = (typeof window.encodeURIComponent != "undefined") ?

+		function(str) {

+			return encodeURIComponent(str);

+		}: 

+		function(str) {

+			return escape(str).replace(/\+/g, "%2B").replace(/"/g, "%22").replace(/'/g, "%27").replace(/\//g, "%2F").replace(/=/g, "%3D");

+		};

+

+	var urlDecode = (typeof window.decodeURIComponent != "undefined") ?

+		function(str) {

+			return decodeURIComponent(str);

+		}: 

+		function(str) {

+			return unescape(str).replace(/%2B/g, "+").replace(/%22/g, "\"").replace(/%27/g, "'").replace(/%2F/g, "/").replace(/%3D/g, "=");

+		};

+

+	function array_remove(arr, val) {

+		var index = -1;

+		for (var i = 0, len = arr.length; i < len; i++) {

+			if (arr[i] === val) {

+				index = i;

+				break;

+			}

+		}

+		if (index >= 0) {

+			arr.splice(index, 1);

+			return true;

+		} else {

+			return false;

+		}

+	}

+

+	function array_contains(arr, val) {

+		for(var i = 0, len = arr.length; i < len; i++) {

+			if (arr[i] == val) {

+				return true;

+			}

+		}

+		return false;

+	}

+

+	function extractBooleanFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			return bool(param);

+		}

+	}

+

+	function extractStringFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			return String(param);

+		}

+	}

+

+	function extractIntFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			try {

+				var value = parseInt(param, 10);

+				return isNaN(value) ? defaultValue : value;

+			} catch (ex) {

+				logLog.warn("Invalid int param " + param, ex);

+				return defaultValue;

+			}

+		}

+	}

+

+	function extractFunctionFromParam(param, defaultValue) {

+		if (typeof param == "function") {

+			return param;

+		} else {

+			return defaultValue;

+		}

+	}

+

+	function isError(err) {

+		return (err instanceof Error);

+	}

+

+	if (!Function.prototype.apply){

+		Function.prototype.apply = function(obj, args) {

+			var methodName = "__apply__";

+			if (typeof obj[methodName] != "undefined") {

+				methodName += String(Math.random()).substr(2);

+			}

+			obj[methodName] = this;

+

+			var argsStrings = [];

+			for (var i = 0, len = args.length; i < len; i++) {

+				argsStrings[i] = "args[" + i + "]";

+			}

+			var script = "obj." + methodName + "(" + argsStrings.join(",") + ")";

+			var returnValue = eval(script);

+			delete obj[methodName];

+			return returnValue;

+		};

+	}

+

+	if (!Function.prototype.call){

+		Function.prototype.call = function(obj) {

+			var args = [];

+			for (var i = 1, len = arguments.length; i < len; i++) {

+				args[i - 1] = arguments[i];

+			}

+			return this.apply(obj, args);

+		};

+	}

+

+	function getListenersPropertyName(eventName) {

+		return "__log4javascript_listeners__" + eventName;

+	}

+

+	function addEvent(node, eventName, listener, useCapture, win) {

+		win = win ? win : window;

+		if (node.addEventListener) {

+			node.addEventListener(eventName, listener, useCapture);

+		} else if (node.attachEvent) {

+			node.attachEvent("on" + eventName, listener);

+		} else {

+			var propertyName = getListenersPropertyName(eventName);

+			if (!node[propertyName]) {

+				node[propertyName] = [];

+				// Set event handler

+				node["on" + eventName] = function(evt) {

+					evt = getEvent(evt, win);

+					var listenersPropertyName = getListenersPropertyName(eventName);

+

+					// Clone the array of listeners to leave the original untouched

+					var listeners = this[listenersPropertyName].concat([]);

+					var currentListener;

+

+					// Call each listener in turn

+					while ((currentListener = listeners.shift())) {

+						currentListener.call(this, evt);

+					}

+				};

+			}

+			node[propertyName].push(listener);

+		}

+	}

+

+	function removeEvent(node, eventName, listener, useCapture) {

+		if (node.removeEventListener) {

+			node.removeEventListener(eventName, listener, useCapture);

+		} else if (node.detachEvent) {

+			node.detachEvent("on" + eventName, listener);

+		} else {

+			var propertyName = getListenersPropertyName(eventName);

+			if (node[propertyName]) {

+				array_remove(node[propertyName], listener);

+			}

+		}

+	}

+

+	function getEvent(evt, win) {

+		win = win ? win : window;

+		return evt ? evt : win.event;

+	}

+

+	function stopEventPropagation(evt) {

+		if (evt.stopPropagation) {

+			evt.stopPropagation();

+		} else if (typeof evt.cancelBubble != "undefined") {

+			evt.cancelBubble = true;

+		}

+		evt.returnValue = false;

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// Simple logging for log4javascript itself

+

+	var logLog = {

+		quietMode: false,

+

+		debugMessages: [],

+

+		setQuietMode: function(quietMode) {

+			this.quietMode = bool(quietMode);

+		},

+

+		numberOfErrors: 0,

+

+		alertAllErrors: false,

+

+		setAlertAllErrors: function(alertAllErrors) {

+			this.alertAllErrors = alertAllErrors;

+		},

+

+		debug: function(message) {

+			this.debugMessages.push(message);

+		},

+

+		displayDebug: function() {

+			alert(this.debugMessages.join(newLine));

+		},

+

+		warn: function(message, exception) {

+		},

+

+		error: function(message, exception) {

+			if (++this.numberOfErrors == 1 || this.alertAllErrors) {

+				if (!this.quietMode) {

+					var alertMessage = "log4javascript error: " + message;

+					if (exception) {

+						alertMessage += newLine + newLine + "Original error: " + getExceptionStringRep(exception);

+					}

+					alert(alertMessage);

+				}

+			}

+		}

+	};

+	log4javascript.logLog = logLog;

+

+	log4javascript.setEventTypes(["load", "error"]);

+

+	function handleError(message, exception) {

+		logLog.error(message, exception);

+		log4javascript.dispatchEvent("error", { "message": message, "exception": exception });

+	}

+

+	log4javascript.handleError = handleError;

+

+	/* ---------------------------------------------------------------------- */

+

+	var enabled = !((typeof log4javascript_disabled != "undefined") &&

+					log4javascript_disabled);

+

+	log4javascript.setEnabled = function(enable) {

+		enabled = bool(enable);

+	};

+

+	log4javascript.isEnabled = function() {

+		return enabled;

+	};

+

+	var useTimeStampsInMilliseconds = true;

+

+	log4javascript.setTimeStampsInMilliseconds = function(timeStampsInMilliseconds) {

+		useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);

+	};

+

+	log4javascript.isTimeStampsInMilliseconds = function() {

+		return useTimeStampsInMilliseconds;

+	};

+	

+

+	// This evaluates the given expression in the current scope, thus allowing

+	// scripts to access private variables. Particularly useful for testing

+	log4javascript.evalInScope = function(expr) {

+		return eval(expr);

+	};

+

+	var showStackTraces = false;

+

+	log4javascript.setShowStackTraces = function(show) {

+		showStackTraces = bool(show);

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Levels

+

+	var Level = function(level, name) {

+		this.level = level;

+		this.name = name;

+	};

+

+	Level.prototype = {

+		toString: function() {

+			return this.name;

+		},

+		equals: function(level) {

+			return this.level == level.level;

+		},

+		isGreaterOrEqual: function(level) {

+			return this.level >= level.level;

+		}

+	};

+

+	Level.ALL = new Level(Number.MIN_VALUE, "ALL");

+	Level.TRACE = new Level(10000, "TRACE");

+	Level.DEBUG = new Level(20000, "DEBUG");

+	Level.INFO = new Level(30000, "INFO");

+	Level.WARN = new Level(40000, "WARN");

+	Level.ERROR = new Level(50000, "ERROR");

+	Level.FATAL = new Level(60000, "FATAL");

+	Level.OFF = new Level(Number.MAX_VALUE, "OFF");

+

+	log4javascript.Level = Level;

+

+	/* ---------------------------------------------------------------------- */

+	// Timers

+

+	function Timer(name, level) {

+		this.name = name;

+		this.level = isUndefined(level) ? Level.INFO : level;

+		this.start = new Date();

+	}

+

+	Timer.prototype.getElapsedTime = function() {

+		return new Date().getTime() - this.start.getTime();

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Loggers

+

+	var anonymousLoggerName = "[anonymous]";

+	var defaultLoggerName = "[default]";

+	var nullLoggerName = "[null]";

+	var rootLoggerName = "root";

+

+	function Logger(name) {

+		this.name = name;

+		this.parent = null;

+		this.children = [];

+

+		var appenders = [];

+		var loggerLevel = null;

+		var isRoot = (this.name === rootLoggerName);

+		var isNull = (this.name === nullLoggerName);

+

+		var appenderCache = null;

+		var appenderCacheInvalidated = false;

+		

+		this.addChild = function(childLogger) {

+			this.children.push(childLogger);

+			childLogger.parent = this;

+			childLogger.invalidateAppenderCache();

+		};

+

+		// Additivity

+		var additive = true;

+		this.getAdditivity = function() {

+			return additive;

+		};

+

+		this.setAdditivity = function(additivity) {

+			var valueChanged = (additive != additivity);

+			additive = additivity;

+			if (valueChanged) {

+				this.invalidateAppenderCache();

+			}

+		};

+

+		// Create methods that use the appenders variable in this scope

+		this.addAppender = function(appender) {

+			if (isNull) {

+				handleError("Logger.addAppender: you may not add an appender to the null logger");

+			} else {

+				if (appender instanceof log4javascript.Appender) {

+					if (!array_contains(appenders, appender)) {

+						appenders.push(appender);

+						appender.setAddedToLogger(this);

+						this.invalidateAppenderCache();

+					}

+				} else {

+					handleError("Logger.addAppender: appender supplied ('" +

+						toStr(appender) + "') is not a subclass of Appender");

+				}

+			}

+		};

+

+		this.removeAppender = function(appender) {

+			array_remove(appenders, appender);

+			appender.setRemovedFromLogger(this);

+			this.invalidateAppenderCache();

+		};

+

+		this.removeAllAppenders = function() {

+			var appenderCount = appenders.length;

+			if (appenderCount > 0) {

+				for (var i = 0; i < appenderCount; i++) {

+					appenders[i].setRemovedFromLogger(this);

+				}

+				appenders.length = 0;

+				this.invalidateAppenderCache();

+			}

+		};

+

+		this.getEffectiveAppenders = function() {

+			if (appenderCache === null || appenderCacheInvalidated) {

+				// Build appender cache

+				var parentEffectiveAppenders = (isRoot || !this.getAdditivity()) ?

+					[] : this.parent.getEffectiveAppenders();

+				appenderCache = parentEffectiveAppenders.concat(appenders);

+				appenderCacheInvalidated = false;

+			}

+			return appenderCache;

+		};

+		

+		this.invalidateAppenderCache = function() {

+			appenderCacheInvalidated = true;

+			for (var i = 0, len = this.children.length; i < len; i++) {

+				this.children[i].invalidateAppenderCache();

+			}

+		};

+

+		this.log = function(level, params) {

+			if (enabled && level.isGreaterOrEqual(this.getEffectiveLevel())) {

+				// Check whether last param is an exception

+				var exception;

+				var finalParamIndex = params.length - 1;

+				var lastParam = params[finalParamIndex];

+				if (params.length > 1 && isError(lastParam)) {

+					exception = lastParam;

+					finalParamIndex--;

+				}

+

+				// Construct genuine array for the params

+				var messages = [];

+				for (var i = 0; i <= finalParamIndex; i++) {

+					messages[i] = params[i];

+				}

+

+				var loggingEvent = new LoggingEvent(

+					this, new Date(), level, messages, exception);

+

+				this.callAppenders(loggingEvent);

+			}

+		};

+

+		this.callAppenders = function(loggingEvent) {

+			var effectiveAppenders = this.getEffectiveAppenders();

+			for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+				effectiveAppenders[i].doAppend(loggingEvent);

+			}

+		};

+

+		this.setLevel = function(level) {

+			// Having a level of null on the root logger would be very bad.

+			if (isRoot && level === null) {

+				handleError("Logger.setLevel: you cannot set the level of the root logger to null");

+			} else if (level instanceof Level) {

+				loggerLevel = level;

+			} else {

+				handleError("Logger.setLevel: level supplied to logger " +

+					this.name + " is not an instance of log4javascript.Level");

+			}

+		};

+

+		this.getLevel = function() {

+			return loggerLevel;

+		};

+

+		this.getEffectiveLevel = function() {

+			for (var logger = this; logger !== null; logger = logger.parent) {

+				var level = logger.getLevel();

+				if (level !== null) {

+					return level;

+				}

+			}

+		};

+

+		this.group = function(name, initiallyExpanded) {

+			if (enabled) {

+				var effectiveAppenders = this.getEffectiveAppenders();

+				for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+					effectiveAppenders[i].group(name, initiallyExpanded);

+				}

+			}

+		};

+

+		this.groupEnd = function() {

+			if (enabled) {

+				var effectiveAppenders = this.getEffectiveAppenders();

+				for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+					effectiveAppenders[i].groupEnd();

+				}

+			}

+		};

+

+		var timers = {};

+

+		this.time = function(name, level) {

+			if (enabled) {

+				if (isUndefined(name)) {

+					handleError("Logger.time: a name for the timer must be supplied");

+				} else if (level && !(level instanceof Level)) {

+					handleError("Logger.time: level supplied to timer " +

+						name + " is not an instance of log4javascript.Level");

+				} else {

+					timers[name] = new Timer(name, level);

+				}

+			}

+		};

+

+		this.timeEnd = function(name) {

+			if (enabled) {

+				if (isUndefined(name)) {

+					handleError("Logger.timeEnd: a name for the timer must be supplied");

+				} else if (timers[name]) {

+					var timer = timers[name];

+					var milliseconds = timer.getElapsedTime();

+					this.log(timer.level, ["Timer " + toStr(name) + " completed in " + milliseconds + "ms"]);

+					delete timers[name];

+				} else {

+					logLog.warn("Logger.timeEnd: no timer found with name " + name);

+				}

+			}

+		};

+

+		this.assert = function(expr) {

+			if (enabled && !expr) {

+				var args = [];

+				for (var i = 1, len = arguments.length; i < len; i++) {

+					args.push(arguments[i]);

+				}

+				args = (args.length > 0) ? args : ["Assertion Failure"];

+				args.push(newLine);

+				args.push(expr);

+				this.log(Level.ERROR, args);

+			}

+		};

+

+		this.toString = function() {

+			return "Logger[" + this.name + "]";

+		};

+	}

+

+	Logger.prototype = {

+		trace: function() {

+			this.log(Level.TRACE, arguments);

+		},

+

+		debug: function() {

+			this.log(Level.DEBUG, arguments);

+		},

+

+		info: function() {

+			this.log(Level.INFO, arguments);

+		},

+

+		warn: function() {

+			this.log(Level.WARN, arguments);

+		},

+

+		error: function() {

+			this.log(Level.ERROR, arguments);

+		},

+

+		fatal: function() {

+			this.log(Level.FATAL, arguments);

+		},

+

+		isEnabledFor: function(level) {

+			return level.isGreaterOrEqual(this.getEffectiveLevel());

+		},

+

+		isTraceEnabled: function() {

+			return this.isEnabledFor(Level.TRACE);

+		},

+

+		isDebugEnabled: function() {

+			return this.isEnabledFor(Level.DEBUG);

+		},

+

+		isInfoEnabled: function() {

+			return this.isEnabledFor(Level.INFO);

+		},

+

+		isWarnEnabled: function() {

+			return this.isEnabledFor(Level.WARN);

+		},

+

+		isErrorEnabled: function() {

+			return this.isEnabledFor(Level.ERROR);

+		},

+

+		isFatalEnabled: function() {

+			return this.isEnabledFor(Level.FATAL);

+		}

+	};

+

+	Logger.prototype.trace.isEntryPoint = true;

+	Logger.prototype.debug.isEntryPoint = true;

+	Logger.prototype.info.isEntryPoint = true;

+	Logger.prototype.warn.isEntryPoint = true;

+	Logger.prototype.error.isEntryPoint = true;

+	Logger.prototype.fatal.isEntryPoint = true;

+

+	/* ---------------------------------------------------------------------- */

+	// Logger access methods

+

+	// Hashtable of loggers keyed by logger name

+	var loggers = {};

+	var loggerNames = [];

+

+	var ROOT_LOGGER_DEFAULT_LEVEL = Level.DEBUG;

+	var rootLogger = new Logger(rootLoggerName);

+	rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);

+

+	log4javascript.getRootLogger = function() {

+		return rootLogger;

+	};

+

+	log4javascript.getLogger = function(loggerName) {

+		// Use default logger if loggerName is not specified or invalid

+		if (!(typeof loggerName == "string")) {

+			loggerName = anonymousLoggerName;

+			logLog.warn("log4javascript.getLogger: non-string logger name "	+

+				toStr(loggerName) + " supplied, returning anonymous logger");

+		}

+

+		// Do not allow retrieval of the root logger by name

+		if (loggerName == rootLoggerName) {

+			handleError("log4javascript.getLogger: root logger may not be obtained by name");

+		}

+

+		// Create the logger for this name if it doesn't already exist

+		if (!loggers[loggerName]) {

+			var logger = new Logger(loggerName);

+			loggers[loggerName] = logger;

+			loggerNames.push(loggerName);

+

+			// Set up parent logger, if it doesn't exist

+			var lastDotIndex = loggerName.lastIndexOf(".");

+			var parentLogger;

+			if (lastDotIndex > -1) {

+				var parentLoggerName = loggerName.substring(0, lastDotIndex);

+				parentLogger = log4javascript.getLogger(parentLoggerName); // Recursively sets up grandparents etc.

+			} else {

+				parentLogger = rootLogger;

+			}

+			parentLogger.addChild(logger);

+		}

+		return loggers[loggerName];

+	};

+

+	var defaultLogger = null;

+	log4javascript.getDefaultLogger = function() {

+		if (!defaultLogger) {

+			defaultLogger = log4javascript.getLogger(defaultLoggerName);

+			var a = new log4javascript.PopUpAppender();

+			defaultLogger.addAppender(a);

+		}

+		return defaultLogger;

+	};

+

+	var nullLogger = null;

+	log4javascript.getNullLogger = function() {

+		if (!nullLogger) {

+			nullLogger = new Logger(nullLoggerName);

+			nullLogger.setLevel(Level.OFF);

+		}

+		return nullLogger;

+	};

+

+	// Destroys all loggers

+	log4javascript.resetConfiguration = function() {

+		rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);

+		loggers = {};

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Logging events

+

+	var LoggingEvent = function(logger, timeStamp, level, messages,

+			exception) {

+		this.logger = logger;

+		this.timeStamp = timeStamp;

+		this.timeStampInMilliseconds = timeStamp.getTime();

+		this.timeStampInSeconds = Math.floor(this.timeStampInMilliseconds / 1000);

+		this.milliseconds = this.timeStamp.getMilliseconds();

+		this.level = level;

+		this.messages = messages;

+		this.exception = exception;

+	};

+

+	LoggingEvent.prototype = {

+		getThrowableStrRep: function() {

+			return this.exception ?

+				getExceptionStringRep(this.exception) : "";

+		},

+		getCombinedMessages: function() {

+			return (this.messages.length == 1) ? this.messages[0] :

+				   this.messages.join(newLine);

+		},

+		toString: function() {

+			return "LoggingEvent[" + this.level + "]";

+		}

+	};

+

+	log4javascript.LoggingEvent = LoggingEvent;

+

+	/* ---------------------------------------------------------------------- */

+	// Layout prototype

+

+	var Layout = function() {

+	};

+

+	Layout.prototype = {

+		defaults: {

+			loggerKey: "logger",

+			timeStampKey: "timestamp",

+			millisecondsKey: "milliseconds",

+			levelKey: "level",

+			messageKey: "message",

+			exceptionKey: "exception",

+			urlKey: "url"

+		},

+		loggerKey: "logger",

+		timeStampKey: "timestamp",

+		millisecondsKey: "milliseconds",

+		levelKey: "level",

+		messageKey: "message",

+		exceptionKey: "exception",

+		urlKey: "url",

+		batchHeader: "",

+		batchFooter: "",

+		batchSeparator: "",

+		returnsPostData: false,

+		overrideTimeStampsSetting: false,

+		useTimeStampsInMilliseconds: null,

+

+		format: function() {

+			handleError("Layout.format: layout supplied has no format() method");

+		},

+

+		ignoresThrowable: function() {

+			handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");

+		},

+

+		getContentType: function() {

+			return "text/plain";

+		},

+

+		allowBatching: function() {

+			return true;

+		},

+

+		setTimeStampsInMilliseconds: function(timeStampsInMilliseconds) {

+			this.overrideTimeStampsSetting = true;

+			this.useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);

+		},

+

+		isTimeStampsInMilliseconds: function() {

+			return this.overrideTimeStampsSetting ?

+				this.useTimeStampsInMilliseconds : useTimeStampsInMilliseconds;

+		},

+

+		getTimeStampValue: function(loggingEvent) {

+			return this.isTimeStampsInMilliseconds() ?

+				loggingEvent.timeStampInMilliseconds : loggingEvent.timeStampInSeconds;

+		},

+

+		getDataValues: function(loggingEvent, combineMessages) {

+			var dataValues = [

+				[this.loggerKey, loggingEvent.logger.name],

+				[this.timeStampKey, this.getTimeStampValue(loggingEvent)],

+				[this.levelKey, loggingEvent.level.name],

+				[this.urlKey, window.location.href],

+				[this.messageKey, combineMessages ? loggingEvent.getCombinedMessages() : loggingEvent.messages]

+			];

+			if (!this.isTimeStampsInMilliseconds()) {

+				dataValues.push([this.millisecondsKey, loggingEvent.milliseconds]);

+			}

+			if (loggingEvent.exception) {

+				dataValues.push([this.exceptionKey, getExceptionStringRep(loggingEvent.exception)]);

+			}

+			if (this.hasCustomFields()) {

+				for (var i = 0, len = this.customFields.length; i < len; i++) {

+					var val = this.customFields[i].value;

+

+					// Check if the value is a function. If so, execute it, passing it the

+					// current layout and the logging event

+					if (typeof val === "function") {

+						val = val(this, loggingEvent);

+					}

+					dataValues.push([this.customFields[i].name, val]);

+				}

+			}

+			return dataValues;

+		},

+

+		setKeys: function(loggerKey, timeStampKey, levelKey, messageKey,

+				exceptionKey, urlKey, millisecondsKey) {

+			this.loggerKey = extractStringFromParam(loggerKey, this.defaults.loggerKey);

+			this.timeStampKey = extractStringFromParam(timeStampKey, this.defaults.timeStampKey);

+			this.levelKey = extractStringFromParam(levelKey, this.defaults.levelKey);

+			this.messageKey = extractStringFromParam(messageKey, this.defaults.messageKey);

+			this.exceptionKey = extractStringFromParam(exceptionKey, this.defaults.exceptionKey);

+			this.urlKey = extractStringFromParam(urlKey, this.defaults.urlKey);

+			this.millisecondsKey = extractStringFromParam(millisecondsKey, this.defaults.millisecondsKey);

+		},

+

+		setCustomField: function(name, value) {

+			var fieldUpdated = false;

+			for (var i = 0, len = this.customFields.length; i < len; i++) {

+				if (this.customFields[i].name === name) {

+					this.customFields[i].value = value;

+					fieldUpdated = true;

+				}

+			}

+			if (!fieldUpdated) {

+				this.customFields.push({"name": name, "value": value});

+			}

+		},

+

+		hasCustomFields: function() {

+			return (this.customFields.length > 0);

+		},

+

+		toString: function() {

+			handleError("Layout.toString: all layouts must override this method");

+		}

+	};

+

+	log4javascript.Layout = Layout;

+

+	/* ---------------------------------------------------------------------- */

+	// Appender prototype

+

+	var Appender = function() {};

+

+	Appender.prototype = new EventSupport();

+

+	Appender.prototype.layout = new PatternLayout();

+	Appender.prototype.threshold = Level.ALL;

+	Appender.prototype.loggers = [];

+

+	// Performs threshold checks before delegating actual logging to the

+	// subclass's specific append method.

+	Appender.prototype.doAppend = function(loggingEvent) {

+		if (enabled && loggingEvent.level.level >= this.threshold.level) {

+			this.append(loggingEvent);

+		}

+	};

+

+	Appender.prototype.append = function(loggingEvent) {};

+

+	Appender.prototype.setLayout = function(layout) {

+		if (layout instanceof Layout) {

+			this.layout = layout;

+		} else {

+			handleError("Appender.setLayout: layout supplied to " +

+				this.toString() + " is not a subclass of Layout");

+		}

+	};

+

+	Appender.prototype.getLayout = function() {

+		return this.layout;

+	};

+

+	Appender.prototype.setThreshold = function(threshold) {

+		if (threshold instanceof Level) {

+			this.threshold = threshold;

+		} else {

+			handleError("Appender.setThreshold: threshold supplied to " +

+				this.toString() + " is not a subclass of Level");

+		}

+	};

+

+	Appender.prototype.getThreshold = function() {

+		return this.threshold;

+	};

+

+	Appender.prototype.setAddedToLogger = function(logger) {

+		this.loggers.push(logger);

+	};

+

+	Appender.prototype.setRemovedFromLogger = function(logger) {

+		array_remove(this.loggers, logger);

+	};

+

+	Appender.prototype.group = emptyFunction;

+	Appender.prototype.groupEnd = emptyFunction;

+

+	Appender.prototype.toString = function() {

+		handleError("Appender.toString: all appenders must override this method");

+	};

+

+	log4javascript.Appender = Appender;

+

+	/* ---------------------------------------------------------------------- */

+	// SimpleLayout 

+

+	function SimpleLayout() {

+		this.customFields = [];

+	}

+

+	SimpleLayout.prototype = new Layout();

+

+	SimpleLayout.prototype.format = function(loggingEvent) {

+		return loggingEvent.level.name + " - " + loggingEvent.getCombinedMessages();

+	};

+

+	SimpleLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	SimpleLayout.prototype.toString = function() {

+	    return "SimpleLayout";

+	};

+

+	log4javascript.SimpleLayout = SimpleLayout;

+	/* ----------------------------------------------------------------------- */

+	// NullLayout 

+

+	function NullLayout() {

+		this.customFields = [];

+	}

+

+	NullLayout.prototype = new Layout();

+

+	NullLayout.prototype.format = function(loggingEvent) {

+		return loggingEvent.messages;

+	};

+

+	NullLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	NullLayout.prototype.toString = function() {

+	    return "NullLayout";

+	};

+

+	log4javascript.NullLayout = NullLayout;

+/* ---------------------------------------------------------------------- */

+	// XmlLayout

+

+	function XmlLayout(combineMessages) {

+		this.combineMessages = extractBooleanFromParam(combineMessages, true);

+		this.customFields = [];

+	}

+

+	XmlLayout.prototype = new Layout();

+

+	XmlLayout.prototype.isCombinedMessages = function() {

+		return this.combineMessages;

+	};

+

+	XmlLayout.prototype.getContentType = function() {

+		return "text/xml";

+	};

+

+	XmlLayout.prototype.escapeCdata = function(str) {

+		return str.replace(/\]\]>/, "]]>]]&gt;<![CDATA[");

+	};

+

+	XmlLayout.prototype.format = function(loggingEvent) {

+		var layout = this;

+		var i, len;

+		function formatMessage(message) {

+			message = (typeof message === "string") ? message : toStr(message);

+			return "<log4javascript:message><![CDATA[" +

+				layout.escapeCdata(message) + "]]></log4javascript:message>";

+		}

+

+		var str = "<log4javascript:event logger=\"" + loggingEvent.logger.name +

+			"\" timestamp=\"" + this.getTimeStampValue(loggingEvent) + "\"";

+		if (!this.isTimeStampsInMilliseconds()) {

+			str += " milliseconds=\"" + loggingEvent.milliseconds + "\"";

+		}

+		str += " level=\"" + loggingEvent.level.name + "\">" + newLine;

+		if (this.combineMessages) {

+			str += formatMessage(loggingEvent.getCombinedMessages());

+		} else {

+			str += "<log4javascript:messages>" + newLine;

+			for (i = 0, len = loggingEvent.messages.length; i < len; i++) {

+				str += formatMessage(loggingEvent.messages[i]) + newLine;

+			}

+			str += "</log4javascript:messages>" + newLine;

+		}

+		if (this.hasCustomFields()) {

+			for (i = 0, len = this.customFields.length; i < len; i++) {

+				str += "<log4javascript:customfield name=\"" +

+					this.customFields[i].name + "\"><![CDATA[" +

+					this.customFields[i].value.toString() +

+					"]]></log4javascript:customfield>" + newLine;

+			}

+		}

+		if (loggingEvent.exception) {

+			str += "<log4javascript:exception><![CDATA[" +

+				getExceptionStringRep(loggingEvent.exception) +

+				"]]></log4javascript:exception>" + newLine;

+		}

+		str += "</log4javascript:event>" + newLine + newLine;

+		return str;

+	};

+

+	XmlLayout.prototype.ignoresThrowable = function() {

+	    return false;

+	};

+

+	XmlLayout.prototype.toString = function() {

+	    return "XmlLayout";

+	};

+

+	log4javascript.XmlLayout = XmlLayout;

+	/* ---------------------------------------------------------------------- */

+	// JsonLayout related

+

+	function escapeNewLines(str) {

+		return str.replace(/\r\n|\r|\n/g, "\\r\\n");

+	}

+

+	function JsonLayout(readable, combineMessages) {

+		this.readable = extractBooleanFromParam(readable, false);

+		this.combineMessages = extractBooleanFromParam(combineMessages, true);

+		this.batchHeader = this.readable ? "[" + newLine : "[";

+		this.batchFooter = this.readable ? "]" + newLine : "]";

+		this.batchSeparator = this.readable ? "," + newLine : ",";

+		this.setKeys();

+		this.colon = this.readable ? ": " : ":";

+		this.tab = this.readable ? "\t" : "";

+		this.lineBreak = this.readable ? newLine : "";

+		this.customFields = [];

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// JsonLayout

+

+	JsonLayout.prototype = new Layout();

+

+	JsonLayout.prototype.isReadable = function() {

+		return this.readable;

+	};

+

+	JsonLayout.prototype.isCombinedMessages = function() {

+		return this.combineMessages;

+	};

+

+    JsonLayout.prototype.format = function(loggingEvent) {

+        var layout = this;

+        var dataValues = this.getDataValues(loggingEvent, this.combineMessages);

+        var str = "{" + this.lineBreak;

+        var i, len;

+

+        function formatValue(val, prefix, expand) {

+            // Check the type of the data value to decide whether quotation marks

+            // or expansion are required

+            var formattedValue;

+            var valType = typeof val;

+            if (val instanceof Date) {

+                formattedValue = String(val.getTime());

+            } else if (expand && (val instanceof Array)) {

+                formattedValue = "[" + layout.lineBreak;

+                for (var i = 0, len = val.length; i < len; i++) {

+                    var childPrefix = prefix + layout.tab;

+                    formattedValue += childPrefix + formatValue(val[i], childPrefix, false);

+                    if (i < val.length - 1) {

+                        formattedValue += ",";

+                    }

+                    formattedValue += layout.lineBreak;

+                }

+                formattedValue += prefix + "]";

+            } else if (valType !== "number" && valType !== "boolean") {

+                formattedValue = "\"" + escapeNewLines(toStr(val).replace(/\"/g, "\\\"")) + "\"";

+            } else {

+                formattedValue = val;

+            }

+            return formattedValue;

+        }

+

+        for (i = 0, len = dataValues.length - 1; i <= len; i++) {

+            str += this.tab + "\"" + dataValues[i][0] + "\"" + this.colon + formatValue(dataValues[i][1], this.tab, true);

+            if (i < len) {

+                str += ",";

+            }

+            str += this.lineBreak;

+        }

+

+        str += "}" + this.lineBreak;

+        return str;

+    };

+

+	JsonLayout.prototype.ignoresThrowable = function() {

+	    return false;

+	};

+

+	JsonLayout.prototype.toString = function() {

+	    return "JsonLayout";

+	};

+

+	JsonLayout.prototype.getContentType = function() {

+		return "application/json";

+	};

+

+	log4javascript.JsonLayout = JsonLayout;

+	/* ---------------------------------------------------------------------- */

+	// HttpPostDataLayout

+

+	function HttpPostDataLayout() {

+		this.setKeys();

+		this.customFields = [];

+		this.returnsPostData = true;

+	}

+

+	HttpPostDataLayout.prototype = new Layout();

+

+	// Disable batching

+	HttpPostDataLayout.prototype.allowBatching = function() {

+		return false;

+	};

+

+	HttpPostDataLayout.prototype.format = function(loggingEvent) {

+		var dataValues = this.getDataValues(loggingEvent);

+		var queryBits = [];

+		for (var i = 0, len = dataValues.length; i < len; i++) {

+			var val = (dataValues[i][1] instanceof Date) ?

+				String(dataValues[i][1].getTime()) : dataValues[i][1];

+			queryBits.push(urlEncode(dataValues[i][0]) + "=" + urlEncode(val));

+		}

+		return queryBits.join("&");

+	};

+

+	HttpPostDataLayout.prototype.ignoresThrowable = function(loggingEvent) {

+	    return false;

+	};

+

+	HttpPostDataLayout.prototype.toString = function() {

+	    return "HttpPostDataLayout";

+	};

+

+	log4javascript.HttpPostDataLayout = HttpPostDataLayout;

+	/* ---------------------------------------------------------------------- */

+	// formatObjectExpansion

+

+	function formatObjectExpansion(obj, depth, indentation) {

+		var objectsExpanded = [];

+

+		function doFormat(obj, depth, indentation) {

+			var i, j, len, childDepth, childIndentation, childLines, expansion,

+				childExpansion;

+

+			if (!indentation) {

+				indentation = "";

+			}

+

+			function formatString(text) {

+				var lines = splitIntoLines(text);

+				for (var j = 1, jLen = lines.length; j < jLen; j++) {

+					lines[j] = indentation + lines[j];

+				}

+				return lines.join(newLine);

+			}

+

+			if (obj === null) {

+				return "null";

+			} else if (typeof obj == "undefined") {

+				return "undefined";

+			} else if (typeof obj == "string") {

+				return formatString(obj);

+			} else if (typeof obj == "object" && array_contains(objectsExpanded, obj)) {

+				try {

+					expansion = toStr(obj);

+				} catch (ex) {

+					expansion = "Error formatting property. Details: " + getExceptionStringRep(ex);

+				}

+				return expansion + " [already expanded]";

+			} else if ((obj instanceof Array) && depth > 0) {

+				objectsExpanded.push(obj);

+				expansion = "[" + newLine;

+				childDepth = depth - 1;

+				childIndentation = indentation + "  ";

+				childLines = [];

+				for (i = 0, len = obj.length; i < len; i++) {

+					try {

+						childExpansion = doFormat(obj[i], childDepth, childIndentation);

+						childLines.push(childIndentation + childExpansion);

+					} catch (ex) {

+						childLines.push(childIndentation + "Error formatting array member. Details: " +

+							getExceptionStringRep(ex) + "");

+					}

+				}

+				expansion += childLines.join("," + newLine) + newLine + indentation + "]";

+				return expansion;

+            } else if (Object.prototype.toString.call(obj) == "[object Date]") {

+                return obj.toString();

+			} else if (typeof obj == "object" && depth > 0) {

+				objectsExpanded.push(obj);

+				expansion = "{" + newLine;

+				childDepth = depth - 1;

+				childIndentation = indentation + "  ";

+				childLines = [];

+				for (i in obj) {

+					try {

+						childExpansion = doFormat(obj[i], childDepth, childIndentation);

+						childLines.push(childIndentation + i + ": " + childExpansion);

+					} catch (ex) {

+						childLines.push(childIndentation + i + ": Error formatting property. Details: " +

+							getExceptionStringRep(ex));

+					}

+				}

+				expansion += childLines.join("," + newLine) + newLine + indentation + "}";

+				return expansion;

+			} else {

+				return formatString(toStr(obj));

+			}

+		}

+		return doFormat(obj, depth, indentation);

+	}

+	/* ---------------------------------------------------------------------- */

+	// Date-related stuff

+

+	var SimpleDateFormat;

+

+	(function() {

+		var regex = /('[^']*')|(G+|y+|M+|w+|W+|D+|d+|F+|E+|a+|H+|k+|K+|h+|m+|s+|S+|Z+)|([a-zA-Z]+)|([^a-zA-Z']+)/;

+		var monthNames = ["January", "February", "March", "April", "May", "June",

+			"July", "August", "September", "October", "November", "December"];

+		var dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

+		var TEXT2 = 0, TEXT3 = 1, NUMBER = 2, YEAR = 3, MONTH = 4, TIMEZONE = 5;

+		var types = {

+			G : TEXT2,

+			y : YEAR,

+			M : MONTH,

+			w : NUMBER,

+			W : NUMBER,

+			D : NUMBER,

+			d : NUMBER,

+			F : NUMBER,

+			E : TEXT3,

+			a : TEXT2,

+			H : NUMBER,

+			k : NUMBER,

+			K : NUMBER,

+			h : NUMBER,

+			m : NUMBER,

+			s : NUMBER,

+			S : NUMBER,

+			Z : TIMEZONE

+		};

+		var ONE_DAY = 24 * 60 * 60 * 1000;

+		var ONE_WEEK = 7 * ONE_DAY;

+		var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK = 1;

+

+		var newDateAtMidnight = function(year, month, day) {

+			var d = new Date(year, month, day, 0, 0, 0);

+			d.setMilliseconds(0);

+			return d;

+		};

+

+		Date.prototype.getDifference = function(date) {

+			return this.getTime() - date.getTime();

+		};

+

+		Date.prototype.isBefore = function(d) {

+			return this.getTime() < d.getTime();

+		};

+

+		Date.prototype.getUTCTime = function() {

+			return Date.UTC(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours(), this.getMinutes(),

+					this.getSeconds(), this.getMilliseconds());

+		};

+

+		Date.prototype.getTimeSince = function(d) {

+			return this.getUTCTime() - d.getUTCTime();

+		};

+

+		Date.prototype.getPreviousSunday = function() {

+			// Using midday avoids any possibility of DST messing things up

+			var midday = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 12, 0, 0);

+			var previousSunday = new Date(midday.getTime() - this.getDay() * ONE_DAY);

+			return newDateAtMidnight(previousSunday.getFullYear(), previousSunday.getMonth(),

+					previousSunday.getDate());

+		};

+

+		Date.prototype.getWeekInYear = function(minimalDaysInFirstWeek) {

+			if (isUndefined(this.minimalDaysInFirstWeek)) {

+				minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;

+			}

+			var previousSunday = this.getPreviousSunday();

+			var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);

+			var numberOfSundays = previousSunday.isBefore(startOfYear) ?

+				0 : 1 + Math.floor(previousSunday.getTimeSince(startOfYear) / ONE_WEEK);

+			var numberOfDaysInFirstWeek =  7 - startOfYear.getDay();

+			var weekInYear = numberOfSundays;

+			if (numberOfDaysInFirstWeek < minimalDaysInFirstWeek) {

+				weekInYear--;

+			}

+			return weekInYear;

+		};

+

+		Date.prototype.getWeekInMonth = function(minimalDaysInFirstWeek) {

+			if (isUndefined(this.minimalDaysInFirstWeek)) {

+				minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;

+			}

+			var previousSunday = this.getPreviousSunday();

+			var startOfMonth = newDateAtMidnight(this.getFullYear(), this.getMonth(), 1);

+			var numberOfSundays = previousSunday.isBefore(startOfMonth) ?

+				0 : 1 + Math.floor(previousSunday.getTimeSince(startOfMonth) / ONE_WEEK);

+			var numberOfDaysInFirstWeek =  7 - startOfMonth.getDay();

+			var weekInMonth = numberOfSundays;

+			if (numberOfDaysInFirstWeek >= minimalDaysInFirstWeek) {

+				weekInMonth++;

+			}

+			return weekInMonth;

+		};

+

+		Date.prototype.getDayInYear = function() {

+			var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);

+			return 1 + Math.floor(this.getTimeSince(startOfYear) / ONE_DAY);

+		};

+

+		/* ------------------------------------------------------------------ */

+

+		SimpleDateFormat = function(formatString) {

+			this.formatString = formatString;

+		};

+

+		/**

+		 * Sets the minimum number of days in a week in order for that week to

+		 * be considered as belonging to a particular month or year

+		 */

+		SimpleDateFormat.prototype.setMinimalDaysInFirstWeek = function(days) {

+			this.minimalDaysInFirstWeek = days;

+		};

+

+		SimpleDateFormat.prototype.getMinimalDaysInFirstWeek = function() {

+			return isUndefined(this.minimalDaysInFirstWeek)	?

+				DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK : this.minimalDaysInFirstWeek;

+		};

+

+		var padWithZeroes = function(str, len) {

+			while (str.length < len) {

+				str = "0" + str;

+			}

+			return str;

+		};

+

+		var formatText = function(data, numberOfLetters, minLength) {

+			return (numberOfLetters >= 4) ? data : data.substr(0, Math.max(minLength, numberOfLetters));

+		};

+

+		var formatNumber = function(data, numberOfLetters) {

+			var dataString = "" + data;

+			// Pad with 0s as necessary

+			return padWithZeroes(dataString, numberOfLetters);

+		};

+

+		SimpleDateFormat.prototype.format = function(date) {

+			var formattedString = "";

+			var result;

+			var searchString = this.formatString;

+			while ((result = regex.exec(searchString))) {

+				var quotedString = result[1];

+				var patternLetters = result[2];

+				var otherLetters = result[3];

+				var otherCharacters = result[4];

+

+				// If the pattern matched is quoted string, output the text between the quotes

+				if (quotedString) {

+					if (quotedString == "''") {

+						formattedString += "'";

+					} else {

+						formattedString += quotedString.substring(1, quotedString.length - 1);

+					}

+				} else if (otherLetters) {

+					// Swallow non-pattern letters by doing nothing here

+				} else if (otherCharacters) {

+					// Simply output other characters

+					formattedString += otherCharacters;

+				} else if (patternLetters) {

+					// Replace pattern letters

+					var patternLetter = patternLetters.charAt(0);

+					var numberOfLetters = patternLetters.length;

+					var rawData = "";

+					switch(patternLetter) {

+						case "G":

+							rawData = "AD";

+							break;

+						case "y":

+							rawData = date.getFullYear();

+							break;

+						case "M":

+							rawData = date.getMonth();

+							break;

+						case "w":

+							rawData = date.getWeekInYear(this.getMinimalDaysInFirstWeek());

+							break;

+						case "W":

+							rawData = date.getWeekInMonth(this.getMinimalDaysInFirstWeek());

+							break;

+						case "D":

+							rawData = date.getDayInYear();

+							break;

+						case "d":

+							rawData = date.getDate();

+							break;

+						case "F":

+							rawData = 1 + Math.floor((date.getDate() - 1) / 7);

+							break;

+						case "E":

+							rawData = dayNames[date.getDay()];

+							break;

+						case "a":

+							rawData = (date.getHours() >= 12) ? "PM" : "AM";

+							break;

+						case "H":

+							rawData = date.getHours();

+							break;

+						case "k":

+							rawData = date.getHours() || 24;

+							break;

+						case "K":

+							rawData = date.getHours() % 12;

+							break;

+						case "h":

+							rawData = (date.getHours() % 12) || 12;

+							break;

+						case "m":

+							rawData = date.getMinutes();

+							break;

+						case "s":

+							rawData = date.getSeconds();

+							break;

+						case "S":

+							rawData = date.getMilliseconds();

+							break;

+						case "Z":

+							rawData = date.getTimezoneOffset(); // This returns the number of minutes since GMT was this time.

+							break;

+					}

+					// Format the raw data depending on the type

+					switch(types[patternLetter]) {

+						case TEXT2:

+							formattedString += formatText(rawData, numberOfLetters, 2);

+							break;

+						case TEXT3:

+							formattedString += formatText(rawData, numberOfLetters, 3);

+							break;

+						case NUMBER:

+							formattedString += formatNumber(rawData, numberOfLetters);

+							break;

+						case YEAR:

+							if (numberOfLetters <= 3) {

+								// Output a 2-digit year

+								var dataString = "" + rawData;

+								formattedString += dataString.substr(2, 2);

+							} else {

+								formattedString += formatNumber(rawData, numberOfLetters);

+							}

+							break;

+						case MONTH:

+							if (numberOfLetters >= 3) {

+								formattedString += formatText(monthNames[rawData], numberOfLetters, numberOfLetters);

+							} else {

+								// NB. Months returned by getMonth are zero-based

+								formattedString += formatNumber(rawData + 1, numberOfLetters);

+							}

+							break;

+						case TIMEZONE:

+							var isPositive = (rawData > 0);

+							// The following line looks like a mistake but isn't

+							// because of the way getTimezoneOffset measures.

+							var prefix = isPositive ? "-" : "+";

+							var absData = Math.abs(rawData);

+

+							// Hours

+							var hours = "" + Math.floor(absData / 60);

+							hours = padWithZeroes(hours, 2);

+							// Minutes

+							var minutes = "" + (absData % 60);

+							minutes = padWithZeroes(minutes, 2);

+

+							formattedString += prefix + hours + minutes;

+							break;

+					}

+				}

+				searchString = searchString.substr(result.index + result[0].length);

+			}

+			return formattedString;

+		};

+	})();

+

+	log4javascript.SimpleDateFormat = SimpleDateFormat;

+

+	/* ---------------------------------------------------------------------- */

+	// PatternLayout

+

+	function PatternLayout(pattern) {

+		if (pattern) {

+			this.pattern = pattern;

+		} else {

+			this.pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;

+		}

+		this.customFields = [];

+	}

+

+	PatternLayout.TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n";

+	PatternLayout.DEFAULT_CONVERSION_PATTERN = "%m%n";

+	PatternLayout.ISO8601_DATEFORMAT = "yyyy-MM-dd HH:mm:ss,SSS";

+	PatternLayout.DATETIME_DATEFORMAT = "dd MMM yyyy HH:mm:ss,SSS";

+	PatternLayout.ABSOLUTETIME_DATEFORMAT = "HH:mm:ss,SSS";

+

+	PatternLayout.prototype = new Layout();

+

+	PatternLayout.prototype.format = function(loggingEvent) {

+		var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;

+		var formattedString = "";

+		var result;

+		var searchString = this.pattern;

+

+		// Cannot use regex global flag since it doesn't work with exec in IE5

+		while ((result = regex.exec(searchString))) {

+			var matchedString = result[0];

+			var padding = result[1];

+			var truncation = result[2];

+			var conversionCharacter = result[3];

+			var specifier = result[5];

+			var text = result[6];

+

+			// Check if the pattern matched was just normal text

+			if (text) {

+				formattedString += "" + text;

+			} else {

+				// Create a raw replacement string based on the conversion

+				// character and specifier

+				var replacement = "";

+				switch(conversionCharacter) {

+					case "a": // Array of messages

+					case "m": // Message

+						var depth = 0;

+						if (specifier) {

+							depth = parseInt(specifier, 10);

+							if (isNaN(depth)) {

+								handleError("PatternLayout.format: invalid specifier '" +

+									specifier + "' for conversion character '" + conversionCharacter +

+									"' - should be a number");

+								depth = 0;

+							}

+						}

+						var messages = (conversionCharacter === "a") ? loggingEvent.messages[0] : loggingEvent.messages;

+						for (var i = 0, len = messages.length; i < len; i++) {

+							if (i > 0 && (replacement.charAt(replacement.length - 1) !== " ")) {

+								replacement += " ";

+							}

+							if (depth === 0) {

+								replacement += messages[i];

+							} else {

+								replacement += formatObjectExpansion(messages[i], depth);

+							}

+						}

+						break;

+					case "c": // Logger name

+						var loggerName = loggingEvent.logger.name;

+						if (specifier) {

+							var precision = parseInt(specifier, 10);

+							var loggerNameBits = loggingEvent.logger.name.split(".");

+							if (precision >= loggerNameBits.length) {

+								replacement = loggerName;

+							} else {

+								replacement = loggerNameBits.slice(loggerNameBits.length - precision).join(".");

+							}

+						} else {

+							replacement = loggerName;

+						}

+						break;

+					case "d": // Date

+						var dateFormat = PatternLayout.ISO8601_DATEFORMAT;

+						if (specifier) {

+							dateFormat = specifier;

+							// Pick up special cases

+							if (dateFormat == "ISO8601") {

+								dateFormat = PatternLayout.ISO8601_DATEFORMAT;

+							} else if (dateFormat == "ABSOLUTE") {

+								dateFormat = PatternLayout.ABSOLUTETIME_DATEFORMAT;

+							} else if (dateFormat == "DATE") {

+								dateFormat = PatternLayout.DATETIME_DATEFORMAT;

+							}

+						}

+						// Format the date

+						replacement = (new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);

+						break;

+					case "f": // Custom field

+						if (this.hasCustomFields()) {

+							var fieldIndex = 0;

+							if (specifier) {

+								fieldIndex = parseInt(specifier, 10);

+								if (isNaN(fieldIndex)) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - should be a number");

+								} else if (fieldIndex === 0) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - must be greater than zero");

+								} else if (fieldIndex > this.customFields.length) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - there aren't that many custom fields");

+								} else {

+									fieldIndex = fieldIndex - 1;

+								}

+							}

+                            var val = this.customFields[fieldIndex].value;

+                            if (typeof val == "function") {

+                                val = val(this, loggingEvent);

+                            }

+                            replacement = val;

+						}

+						break;

+					case "n": // New line

+						replacement = newLine;

+						break;

+					case "p": // Level

+						replacement = loggingEvent.level.name;

+						break;

+					case "r": // Milliseconds since log4javascript startup

+						replacement = "" + loggingEvent.timeStamp.getDifference(applicationStartDate);

+						break;

+					case "%": // Literal % sign

+						replacement = "%";

+						break;

+					default:

+						replacement = matchedString;

+						break;

+				}

+				// Format the replacement according to any padding or

+				// truncation specified

+				var l;

+

+				// First, truncation

+				if (truncation) {

+					l = parseInt(truncation.substr(1), 10);

+					var strLen = replacement.length;

+					if (l < strLen) {

+						replacement = replacement.substring(strLen - l, strLen);

+					}

+				}

+				// Next, padding

+				if (padding) {

+					if (padding.charAt(0) == "-") {

+						l = parseInt(padding.substr(1), 10);

+						// Right pad with spaces

+						while (replacement.length < l) {

+							replacement += " ";

+						}

+					} else {

+						l = parseInt(padding, 10);

+						// Left pad with spaces

+						while (replacement.length < l) {

+							replacement = " " + replacement;

+						}

+					}

+				}

+				formattedString += replacement;

+			}

+			searchString = searchString.substr(result.index + result[0].length);

+		}

+		return formattedString;

+	};

+

+	PatternLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	PatternLayout.prototype.toString = function() {

+	    return "PatternLayout";

+	};

+

+	log4javascript.PatternLayout = PatternLayout;

+	/* ---------------------------------------------------------------------- */

+	// AlertAppender

+

+	function AlertAppender() {}

+

+	AlertAppender.prototype = new Appender();

+

+	AlertAppender.prototype.layout = new SimpleLayout();

+

+	AlertAppender.prototype.append = function(loggingEvent) {

+		var formattedMessage = this.getLayout().format(loggingEvent);

+		if (this.getLayout().ignoresThrowable()) {

+			formattedMessage += loggingEvent.getThrowableStrRep();

+		}

+		alert(formattedMessage);

+	};

+

+	AlertAppender.prototype.toString = function() {

+		return "AlertAppender";

+	};

+

+	log4javascript.AlertAppender = AlertAppender;

+	/* ---------------------------------------------------------------------- */

+	// BrowserConsoleAppender (only works in Opera and Safari and Firefox with

+	// Firebug extension)

+

+	function BrowserConsoleAppender() {}

+

+	BrowserConsoleAppender.prototype = new log4javascript.Appender();

+	BrowserConsoleAppender.prototype.layout = new NullLayout();

+	BrowserConsoleAppender.prototype.threshold = Level.DEBUG;

+

+	BrowserConsoleAppender.prototype.append = function(loggingEvent) {

+		var appender = this;

+

+		var getFormattedMessage = function() {

+			var layout = appender.getLayout();

+			var formattedMessage = layout.format(loggingEvent);

+			if (layout.ignoresThrowable() && loggingEvent.exception) {

+				formattedMessage += loggingEvent.getThrowableStrRep();

+			}

+			return formattedMessage;

+		};

+

+		if ((typeof opera != "undefined") && opera.postError) { // Opera

+			opera.postError(getFormattedMessage());

+		} else if (window.console && window.console.log) { // Safari and Firebug

+			var formattedMesage = getFormattedMessage();

+			// Log to Firebug using its logging methods or revert to the console.log

+			// method in Safari

+			if (window.console.debug && Level.DEBUG.isGreaterOrEqual(loggingEvent.level)) {

+				window.console.debug(formattedMesage);

+			} else if (window.console.info && Level.INFO.equals(loggingEvent.level)) {

+				window.console.info(formattedMesage);

+			} else if (window.console.warn && Level.WARN.equals(loggingEvent.level)) {

+				window.console.warn(formattedMesage);

+			} else if (window.console.error && loggingEvent.level.isGreaterOrEqual(Level.ERROR)) {

+				window.console.error(formattedMesage);

+			} else {

+				window.console.log(formattedMesage);

+			}

+		}

+	};

+

+	BrowserConsoleAppender.prototype.group = function(name) {

+		if (window.console && window.console.group) {

+			window.console.group(name);

+		}

+	};

+

+	BrowserConsoleAppender.prototype.groupEnd = function() {

+		if (window.console && window.console.groupEnd) {

+			window.console.groupEnd();

+		}

+	};

+

+	BrowserConsoleAppender.prototype.toString = function() {

+		return "BrowserConsoleAppender";

+	};

+

+	log4javascript.BrowserConsoleAppender = BrowserConsoleAppender;

+	/* ---------------------------------------------------------------------- */

+	// AjaxAppender related

+

+	var xmlHttpFactories = [

+		function() { return new XMLHttpRequest(); },

+		function() { return new ActiveXObject("Msxml2.XMLHTTP"); },

+		function() { return new ActiveXObject("Microsoft.XMLHTTP"); }

+	];

+

+	var getXmlHttp = function(errorHandler) {

+		// This is only run the first time; the value of getXmlHttp gets

+		// replaced with the factory that succeeds on the first run

+		var xmlHttp = null, factory;

+		for (var i = 0, len = xmlHttpFactories.length; i < len; i++) {

+			factory = xmlHttpFactories[i];

+			try {

+				xmlHttp = factory();

+				getXmlHttp = factory;

+				return xmlHttp;

+			} catch (e) {

+			}

+		}

+		// If we're here, all factories have failed, so throw an error

+		if (errorHandler) {

+			errorHandler();

+		} else {

+			handleError("getXmlHttp: unable to obtain XMLHttpRequest object");

+		}

+	};

+

+	function isHttpRequestSuccessful(xmlHttp) {

+		return isUndefined(xmlHttp.status) || xmlHttp.status === 0 ||

+			(xmlHttp.status >= 200 && xmlHttp.status < 300) ||

+			xmlHttp.status == 1223 /* Fix for IE */;

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// AjaxAppender

+

+	function AjaxAppender(url) {

+		var appender = this;

+		var isSupported = true;

+		if (!url) {

+			handleError("AjaxAppender: URL must be specified in constructor");

+			isSupported = false;

+		}

+

+		var timed = this.defaults.timed;

+		var waitForResponse = this.defaults.waitForResponse;

+		var batchSize = this.defaults.batchSize;

+		var timerInterval = this.defaults.timerInterval;

+		var requestSuccessCallback = this.defaults.requestSuccessCallback;

+		var failCallback = this.defaults.failCallback;

+		var postVarName = this.defaults.postVarName;

+		var sendAllOnUnload = this.defaults.sendAllOnUnload;

+		var contentType = this.defaults.contentType;

+		var sessionId = null;

+

+		var queuedLoggingEvents = [];

+		var queuedRequests = [];

+		var headers = [];

+		var sending = false;

+		var initialized = false;

+

+		// Configuration methods. The function scope is used to prevent

+		// direct alteration to the appender configuration properties.

+		function checkCanConfigure(configOptionName) {

+			if (initialized) {

+				handleError("AjaxAppender: configuration option '" +

+					configOptionName +

+					"' may not be set after the appender has been initialized");

+				return false;

+			}

+			return true;

+		}

+

+		this.getSessionId = function() { return sessionId; };

+		this.setSessionId = function(sessionIdParam) {

+			sessionId = extractStringFromParam(sessionIdParam, null);

+			this.layout.setCustomField("sessionid", sessionId);

+		};

+

+		this.setLayout = function(layoutParam) {

+			if (checkCanConfigure("layout")) {

+				this.layout = layoutParam;

+				// Set the session id as a custom field on the layout, if not already present

+				if (sessionId !== null) {

+					this.setSessionId(sessionId);

+				}

+			}

+		};

+

+		this.isTimed = function() { return timed; };

+		this.setTimed = function(timedParam) {

+			if (checkCanConfigure("timed")) {

+				timed = bool(timedParam);

+			}

+		};

+

+		this.getTimerInterval = function() { return timerInterval; };

+		this.setTimerInterval = function(timerIntervalParam) {

+			if (checkCanConfigure("timerInterval")) {

+				timerInterval = extractIntFromParam(timerIntervalParam, timerInterval);

+			}

+		};

+

+		this.isWaitForResponse = function() { return waitForResponse; };

+		this.setWaitForResponse = function(waitForResponseParam) {

+			if (checkCanConfigure("waitForResponse")) {

+				waitForResponse = bool(waitForResponseParam);

+			}

+		};

+

+		this.getBatchSize = function() { return batchSize; };

+		this.setBatchSize = function(batchSizeParam) {

+			if (checkCanConfigure("batchSize")) {

+				batchSize = extractIntFromParam(batchSizeParam, batchSize);

+			}

+		};

+

+		this.isSendAllOnUnload = function() { return sendAllOnUnload; };

+		this.setSendAllOnUnload = function(sendAllOnUnloadParam) {

+			if (checkCanConfigure("sendAllOnUnload")) {

+				sendAllOnUnload = extractBooleanFromParam(sendAllOnUnloadParam, sendAllOnUnload);

+			}

+		};

+

+		this.setRequestSuccessCallback = function(requestSuccessCallbackParam) {

+			requestSuccessCallback = extractFunctionFromParam(requestSuccessCallbackParam, requestSuccessCallback);

+		};

+

+		this.setFailCallback = function(failCallbackParam) {

+			failCallback = extractFunctionFromParam(failCallbackParam, failCallback);

+		};

+

+		this.getPostVarName = function() { return postVarName; };

+		this.setPostVarName = function(postVarNameParam) {

+			if (checkCanConfigure("postVarName")) {

+				postVarName = extractStringFromParam(postVarNameParam, postVarName);

+			}

+		};

+

+		this.getHeaders = function() { return headers; };

+		this.addHeader = function(name, value) {

+			if (name.toLowerCase() == "content-type") {

+				contentType = value;

+			} else {

+				headers.push( { name: name, value: value } );

+			}

+		};

+

+		// Internal functions

+		function sendAll() {

+			if (isSupported && enabled) {

+				sending = true;

+				var currentRequestBatch;

+				if (waitForResponse) {

+					// Send the first request then use this function as the callback once

+					// the response comes back

+					if (queuedRequests.length > 0) {

+						currentRequestBatch = queuedRequests.shift();

+						sendRequest(preparePostData(currentRequestBatch), sendAll);

+					} else {

+						sending = false;

+						if (timed) {

+							scheduleSending();

+						}

+					}

+				} else {

+					// Rattle off all the requests without waiting to see the response

+					while ((currentRequestBatch = queuedRequests.shift())) {

+						sendRequest(preparePostData(currentRequestBatch));

+					}

+					sending = false;

+					if (timed) {

+						scheduleSending();

+					}

+				}

+			}

+		}

+

+		this.sendAll = sendAll;

+

+		// Called when the window unloads. At this point we're past caring about

+		// waiting for responses or timers or incomplete batches - everything

+		// must go, now

+		function sendAllRemaining() {

+			var sendingAnything = false;

+			if (isSupported && enabled) {

+				// Create requests for everything left over, batched as normal

+				var actualBatchSize = appender.getLayout().allowBatching() ? batchSize : 1;

+				var currentLoggingEvent;

+				var batchedLoggingEvents = [];

+				while ((currentLoggingEvent = queuedLoggingEvents.shift())) {

+					batchedLoggingEvents.push(currentLoggingEvent);

+					if (queuedLoggingEvents.length >= actualBatchSize) {

+						// Queue this batch of log entries

+						queuedRequests.push(batchedLoggingEvents);

+						batchedLoggingEvents = [];

+					}

+				}

+				// If there's a partially completed batch, add it

+				if (batchedLoggingEvents.length > 0) {

+					queuedRequests.push(batchedLoggingEvents);

+				}

+				sendingAnything = (queuedRequests.length > 0);

+				waitForResponse = false;

+				timed = false;

+				sendAll();

+			}

+			return sendingAnything;

+		}

+

+		this.sendAllRemaining = sendAllRemaining;

+

+		function preparePostData(batchedLoggingEvents) {

+			// Format the logging events

+			var formattedMessages = [];

+			var currentLoggingEvent;

+			var postData = "";

+			while ((currentLoggingEvent = batchedLoggingEvents.shift())) {

+				var currentFormattedMessage = appender.getLayout().format(currentLoggingEvent);

+				if (appender.getLayout().ignoresThrowable()) {

+					currentFormattedMessage += currentLoggingEvent.getThrowableStrRep();

+				}

+				formattedMessages.push(currentFormattedMessage);

+			}

+			// Create the post data string

+			if (batchedLoggingEvents.length == 1) {

+				postData = formattedMessages.join("");

+			} else {

+				postData = appender.getLayout().batchHeader +

+					formattedMessages.join(appender.getLayout().batchSeparator) +

+					appender.getLayout().batchFooter;

+			}

+			if (contentType == appender.defaults.contentType) {

+				postData = appender.getLayout().returnsPostData ? postData :

+					urlEncode(postVarName) + "=" + urlEncode(postData);

+				// Add the layout name to the post data

+				if (postData.length > 0) {

+					postData += "&";

+				}

+				postData += "layout=" + urlEncode(appender.getLayout().toString());

+			}

+			return postData;

+		}

+

+		function scheduleSending() {

+			window.setTimeout(sendAll, timerInterval);

+		}

+

+		function xmlHttpErrorHandler() {

+			var msg = "AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";

+			handleError(msg);

+			isSupported = false;

+			if (failCallback) {

+				failCallback(msg);

+			}

+		}

+

+		function sendRequest(postData, successCallback) {

+			try {

+				var xmlHttp = getXmlHttp(xmlHttpErrorHandler);

+				if (isSupported) {

+					if (xmlHttp.overrideMimeType) {

+						xmlHttp.overrideMimeType(appender.getLayout().getContentType());

+					}

+					xmlHttp.onreadystatechange = function() {

+						if (xmlHttp.readyState == 4) {

+							if (isHttpRequestSuccessful(xmlHttp)) {

+								if (requestSuccessCallback) {

+									requestSuccessCallback(xmlHttp);

+								}

+								if (successCallback) {

+									successCallback(xmlHttp);

+								}

+							} else {

+								var msg = "AjaxAppender.append: XMLHttpRequest request to URL " +

+									url + " returned status code " + xmlHttp.status;

+								handleError(msg);

+								if (failCallback) {

+									failCallback(msg);

+								}

+							}

+							xmlHttp.onreadystatechange = emptyFunction;

+							xmlHttp = null;

+						}

+					};

+					xmlHttp.open("POST", url, true);

+					try {

+						for (var i = 0, header; header = headers[i++]; ) {

+							xmlHttp.setRequestHeader(header.name, header.value);

+						}

+						xmlHttp.setRequestHeader("Content-Type", contentType);

+					} catch (headerEx) {

+						var msg = "AjaxAppender.append: your browser's XMLHttpRequest implementation" +

+							" does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";

+						handleError(msg);

+						isSupported = false;

+						if (failCallback) {

+							failCallback(msg);

+						}

+						return;

+					}

+					xmlHttp.send(postData);

+				}

+			} catch (ex) {

+				var errMsg = "AjaxAppender.append: error sending log message to " + url;

+				handleError(errMsg, ex);

+				isSupported = false;

+				if (failCallback) {

+					failCallback(errMsg + ". Details: " + getExceptionStringRep(ex));

+				}

+			}

+		}

+

+		this.append = function(loggingEvent) {

+			if (isSupported) {

+				if (!initialized) {

+					init();

+				}

+				queuedLoggingEvents.push(loggingEvent);

+				var actualBatchSize = this.getLayout().allowBatching() ? batchSize : 1;

+

+				if (queuedLoggingEvents.length >= actualBatchSize) {

+					var currentLoggingEvent;

+					var batchedLoggingEvents = [];

+					while ((currentLoggingEvent = queuedLoggingEvents.shift())) {

+						batchedLoggingEvents.push(currentLoggingEvent);

+					}

+					// Queue this batch of log entries

+					queuedRequests.push(batchedLoggingEvents);

+

+					// If using a timer, the queue of requests will be processed by the

+					// timer function, so nothing needs to be done here.

+					if (!timed && (!waitForResponse || (waitForResponse && !sending))) {

+						sendAll();

+					}

+				}

+			}

+		};

+

+		function init() {

+			initialized = true;

+			// Add unload event to send outstanding messages

+			if (sendAllOnUnload) {

+				var oldBeforeUnload = window.onbeforeunload;

+				window.onbeforeunload = function() {

+					if (oldBeforeUnload) {

+						oldBeforeUnload();

+					}

+					if (sendAllRemaining()) {

+						return "Sending log messages";

+					}

+				};

+			}

+			// Start timer

+			if (timed) {

+				scheduleSending();

+			}

+		}

+	}

+

+	AjaxAppender.prototype = new Appender();

+

+	AjaxAppender.prototype.defaults = {

+		waitForResponse: false,

+		timed: false,

+		timerInterval: 1000,

+		batchSize: 1,

+		sendAllOnUnload: false,

+		requestSuccessCallback: null,

+		failCallback: null,

+		postVarName: "data",

+		contentType: "application/x-www-form-urlencoded"

+	};

+

+	AjaxAppender.prototype.layout = new HttpPostDataLayout();

+

+	AjaxAppender.prototype.toString = function() {

+		return "AjaxAppender";

+	};

+

+	log4javascript.AjaxAppender = AjaxAppender;

+	/* ---------------------------------------------------------------------- */

+	// PopUpAppender and InPageAppender related

+

+	function setCookie(name, value, days, path) {

+	    var expires;

+	    path = path ? "; path=" + path : "";

+		if (days) {

+			var date = new Date();

+			date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));

+			expires = "; expires=" + date.toGMTString();

+		} else {

+		    expires = "";

+	    }

+		document.cookie = escape(name) + "=" + escape(value) + expires + path;

+	}

+

+	function getCookie(name) {

+		var nameEquals = escape(name) + "=";

+		var ca = document.cookie.split(";");

+		for (var i = 0, len = ca.length; i < len; i++) {

+			var c = ca[i];

+			while (c.charAt(0) === " ") {

+			    c = c.substring(1, c.length);

+			}

+			if (c.indexOf(nameEquals) === 0) {

+			    return unescape(c.substring(nameEquals.length, c.length));

+	        }

+		}

+		return null;

+	}

+

+	// Gets the base URL of the location of the log4javascript script.

+	// This is far from infallible.

+	function getBaseUrl() {

+		var scripts = document.getElementsByTagName("script");

+		for (var i = 0, len = scripts.length; i < len; ++i) {

+			if (scripts[i].src.indexOf("log4javascript") != -1) {

+				var lastSlash = scripts[i].src.lastIndexOf("/");

+				return (lastSlash == -1) ? "" : scripts[i].src.substr(0, lastSlash + 1);

+			}

+		}

+        return null;

+    }

+

+	function isLoaded(win) {

+		try {

+			return bool(win.loaded);

+		} catch (ex) {

+			return false;

+		}

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// ConsoleAppender (prototype for PopUpAppender and InPageAppender)

+

+	var ConsoleAppender;

+

+	// Create an anonymous function to protect base console methods

+	(function() {

+		var getConsoleHtmlLines = function() {

+			return [

+'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',

+'<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">',

+'	<head>',

+'		<title>log4javascript</title>',

+'		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',

+'		<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->',

+'		<meta http-equiv="X-UA-Compatible" content="IE=7" />',

+'		<script type="text/javascript">var isIe = false, isIePre7 = false;</script>',

+'		<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->',

+'		<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->',

+'		<script type="text/javascript">',

+'			//<![CDATA[',

+'			var loggingEnabled = true;',

+'			var logQueuedEventsTimer = null;',

+'			var logEntries = [];',

+'			var logEntriesAndSeparators = [];',

+'			var logItems = [];',

+'			var renderDelay = 100;',

+'			var unrenderedLogItemsExist = false;',

+'			var rootGroup, currentGroup = null;',

+'			var loaded = false;',

+'			var currentLogItem = null;',

+'			var logMainContainer;',

+'',

+'			function copyProperties(obj, props) {',

+'				for (var i in props) {',

+'					obj[i] = props[i];',

+'				}',

+'			}',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItem() {',

+'			}',

+'',

+'			LogItem.prototype = {',

+'				mainContainer: null,',

+'				wrappedContainer: null,',

+'				unwrappedContainer: null,',

+'				group: null,',

+'',

+'				appendToLog: function() {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].appendToLog();',

+'					}',

+'					this.group.update();',

+'				},',

+'',

+'				doRemove: function(doUpdate, removeFromGroup) {',

+'					if (this.rendered) {',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].remove();',

+'						}',

+'						this.unwrappedElementContainer = null;',

+'						this.wrappedElementContainer = null;',

+'						this.mainElementContainer = null;',

+'					}',

+'					if (this.group && removeFromGroup) {',

+'						this.group.removeChild(this, doUpdate);',

+'					}',

+'					if (this === currentLogItem) {',

+'						currentLogItem = null;',

+'					}',

+'				},',

+'',

+'				remove: function(doUpdate, removeFromGroup) {',

+'					this.doRemove(doUpdate, removeFromGroup);',

+'				},',

+'',

+'				render: function() {},',

+'',

+'				accept: function(visitor) {',

+'					visitor.visit(this);',

+'				},',

+'',

+'				getUnwrappedDomContainer: function() {',

+'					return this.group.unwrappedElementContainer.contentDiv;',

+'				},',

+'',

+'				getWrappedDomContainer: function() {',

+'					return this.group.wrappedElementContainer.contentDiv;',

+'				},',

+'',

+'				getMainDomContainer: function() {',

+'					return this.group.mainElementContainer.contentDiv;',

+'				}',

+'			};',

+'',

+'			LogItem.serializedItemKeys = {LOG_ENTRY: 0, GROUP_START: 1, GROUP_END: 2};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItemContainerElement() {',

+'			}',

+'',

+'			LogItemContainerElement.prototype = {',

+'				appendToLog: function() {',

+'					var insertBeforeFirst = (newestAtTop && this.containerDomNode.hasChildNodes());',

+'					if (insertBeforeFirst) {',

+'						this.containerDomNode.insertBefore(this.mainDiv, this.containerDomNode.firstChild);',

+'					} else {',

+'						this.containerDomNode.appendChild(this.mainDiv);',

+'					}',

+'				}',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function SeparatorElementContainer(containerDomNode) {',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.className = "separator";',

+'				this.mainDiv.innerHTML = "&nbsp;";',

+'			}',

+'',

+'			SeparatorElementContainer.prototype = new LogItemContainerElement();',

+'',

+'			SeparatorElementContainer.prototype.remove = function() {',

+'				this.mainDiv.parentNode.removeChild(this.mainDiv);',

+'				this.mainDiv = null;',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function Separator() {',

+'				this.rendered = false;',

+'			}',

+'',

+'			Separator.prototype = new LogItem();',

+'',

+'			copyProperties(Separator.prototype, {',

+'				render: function() {',

+'					var containerDomNode = this.group.contentDiv;',

+'					if (isIe) {',

+'						this.unwrappedElementContainer = new SeparatorElementContainer(this.getUnwrappedDomContainer());',

+'						this.wrappedElementContainer = new SeparatorElementContainer(this.getWrappedDomContainer());',

+'						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',

+'					} else {',

+'						this.mainElementContainer = new SeparatorElementContainer(this.getMainDomContainer());',

+'						this.elementContainers = [this.mainElementContainer];',

+'					}',

+'					this.content = this.formattedMessage;',

+'					this.rendered = true;',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function GroupElementContainer(group, containerDomNode, isRoot, isWrapped) {',

+'				this.group = group;',

+'				this.containerDomNode = containerDomNode;',

+'				this.isRoot = isRoot;',

+'				this.isWrapped = isWrapped;',

+'				this.expandable = false;',

+'',

+'				if (this.isRoot) {',

+'					if (isIe) {',

+'						this.contentDiv = logMainContainer.appendChild(document.createElement("div"));',

+'						this.contentDiv.id = this.isWrapped ? "log_wrapped" : "log_unwrapped";',

+'					} else {',

+'						this.contentDiv = logMainContainer;',

+'					}',

+'				} else {',

+'					var groupElementContainer = this;',

+'					',

+'					this.mainDiv = document.createElement("div");',

+'					this.mainDiv.className = "group";',

+'',

+'					this.headingDiv = this.mainDiv.appendChild(document.createElement("div"));',

+'					this.headingDiv.className = "groupheading";',

+'',

+'					this.expander = this.headingDiv.appendChild(document.createElement("span"));',

+'					this.expander.className = "expander unselectable greyedout";',

+'					this.expander.unselectable = true;',

+'					var expanderText = this.group.expanded ? "-" : "+";',

+'					this.expanderTextNode = this.expander.appendChild(document.createTextNode(expanderText));',

+'					',

+'					this.headingDiv.appendChild(document.createTextNode(" " + this.group.name));',

+'',

+'					this.contentDiv = this.mainDiv.appendChild(document.createElement("div"));',

+'					var contentCssClass = this.group.expanded ? "expanded" : "collapsed";',

+'					this.contentDiv.className = "groupcontent " + contentCssClass;',

+'',

+'					this.expander.onclick = function() {',

+'						if (groupElementContainer.group.expandable) {',

+'							groupElementContainer.group.toggleExpanded();',

+'						}',

+'					};',

+'				}',

+'			}',

+'',

+'			GroupElementContainer.prototype = new LogItemContainerElement();',

+'',

+'			copyProperties(GroupElementContainer.prototype, {',

+'				toggleExpanded: function() {',

+'					if (!this.isRoot) {',

+'						var oldCssClass, newCssClass, expanderText;',

+'						if (this.group.expanded) {',

+'							newCssClass = "expanded";',

+'							oldCssClass = "collapsed";',

+'							expanderText = "-";',

+'						} else {',

+'							newCssClass = "collapsed";',

+'							oldCssClass = "expanded";',

+'							expanderText = "+";',

+'						}',

+'						replaceClass(this.contentDiv, newCssClass, oldCssClass);',

+'						this.expanderTextNode.nodeValue = expanderText;',

+'					}',

+'				},',

+'',

+'				remove: function() {',

+'					if (!this.isRoot) {',

+'						this.headingDiv = null;',

+'						this.expander.onclick = null;',

+'						this.expander = null;',

+'						this.expanderTextNode = null;',

+'						this.contentDiv = null;',

+'						this.containerDomNode = null;',

+'						this.mainDiv.parentNode.removeChild(this.mainDiv);',

+'						this.mainDiv = null;',

+'					}',

+'				},',

+'',

+'				reverseChildren: function() {',

+'					// Invert the order of the log entries',

+'					var node = null;',

+'',

+'					// Remove all the log container nodes',

+'					var childDomNodes = [];',

+'					while ((node = this.contentDiv.firstChild)) {',

+'						this.contentDiv.removeChild(node);',

+'						childDomNodes.push(node);',

+'					}',

+'',

+'					// Put them all back in reverse order',

+'					while ((node = childDomNodes.pop())) {',

+'						this.contentDiv.appendChild(node);',

+'					}',

+'				},',

+'',

+'				update: function() {',

+'					if (!this.isRoot) {',

+'						if (this.group.expandable) {',

+'							removeClass(this.expander, "greyedout");',

+'						} else {',

+'							addClass(this.expander, "greyedout");',

+'						}',

+'					}',

+'				},',

+'',

+'				clear: function() {',

+'					if (this.isRoot) {',

+'						this.contentDiv.innerHTML = "";',

+'					}',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function Group(name, isRoot, initiallyExpanded) {',

+'				this.name = name;',

+'				this.group = null;',

+'				this.isRoot = isRoot;',

+'				this.initiallyExpanded = initiallyExpanded;',

+'				this.elementContainers = [];',

+'				this.children = [];',

+'				this.expanded = initiallyExpanded;',

+'				this.rendered = false;',

+'				this.expandable = false;',

+'			}',

+'',

+'			Group.prototype = new LogItem();',

+'',

+'			copyProperties(Group.prototype, {',

+'				addChild: function(logItem) {',

+'					this.children.push(logItem);',

+'					logItem.group = this;',

+'				},',

+'',

+'				render: function() {',

+'					if (isIe) {',

+'						var unwrappedDomContainer, wrappedDomContainer;',

+'						if (this.isRoot) {',

+'							unwrappedDomContainer = logMainContainer;',

+'							wrappedDomContainer = logMainContainer;',

+'						} else {',

+'							unwrappedDomContainer = this.getUnwrappedDomContainer();',

+'							wrappedDomContainer = this.getWrappedDomContainer();',

+'						}',

+'						this.unwrappedElementContainer = new GroupElementContainer(this, unwrappedDomContainer, this.isRoot, false);',

+'						this.wrappedElementContainer = new GroupElementContainer(this, wrappedDomContainer, this.isRoot, true);',

+'						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',

+'					} else {',

+'						var mainDomContainer = this.isRoot ? logMainContainer : this.getMainDomContainer();',

+'						this.mainElementContainer = new GroupElementContainer(this, mainDomContainer, this.isRoot, false);',

+'						this.elementContainers = [this.mainElementContainer];',

+'					}',

+'					this.rendered = true;',

+'				},',

+'',

+'				toggleExpanded: function() {',

+'					this.expanded = !this.expanded;',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].toggleExpanded();',

+'					}',

+'				},',

+'',

+'				expand: function() {',

+'					if (!this.expanded) {',

+'						this.toggleExpanded();',

+'					}',

+'				},',

+'',

+'				accept: function(visitor) {',

+'					visitor.visitGroup(this);',

+'				},',

+'',

+'				reverseChildren: function() {',

+'					if (this.rendered) {',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].reverseChildren();',

+'						}',

+'					}',

+'				},',

+'',

+'				update: function() {',

+'					var previouslyExpandable = this.expandable;',

+'					this.expandable = (this.children.length !== 0);',

+'					if (this.expandable !== previouslyExpandable) {',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].update();',

+'						}',

+'					}',

+'				},',

+'',

+'				flatten: function() {',

+'					var visitor = new GroupFlattener();',

+'					this.accept(visitor);',

+'					return visitor.logEntriesAndSeparators;',

+'				},',

+'',

+'				removeChild: function(child, doUpdate) {',

+'					array_remove(this.children, child);',

+'					child.group = null;',

+'					if (doUpdate) {',

+'						this.update();',

+'					}',

+'				},',

+'',

+'				remove: function(doUpdate, removeFromGroup) {',

+'					for (var i = 0, len = this.children.length; i < len; i++) {',

+'						this.children[i].remove(false, false);',

+'					}',

+'					this.children = [];',

+'					this.update();',

+'					if (this === currentGroup) {',

+'						currentGroup = this.group;',

+'					}',

+'					this.doRemove(doUpdate, removeFromGroup);',

+'				},',

+'',

+'				serialize: function(items) {',

+'					items.push([LogItem.serializedItemKeys.GROUP_START, this.name]);',

+'					for (var i = 0, len = this.children.length; i < len; i++) {',

+'						this.children[i].serialize(items);',

+'					}',

+'					if (this !== currentGroup) {',

+'						items.push([LogItem.serializedItemKeys.GROUP_END]);',

+'					}',

+'				},',

+'',

+'				clear: function() {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].clear();',

+'					}',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryElementContainer() {',

+'			}',

+'',

+'			LogEntryElementContainer.prototype = new LogItemContainerElement();',

+'',

+'			copyProperties(LogEntryElementContainer.prototype, {',

+'				remove: function() {',

+'					this.doRemove();',

+'				},',

+'',

+'				doRemove: function() {',

+'					this.mainDiv.parentNode.removeChild(this.mainDiv);',

+'					this.mainDiv = null;',

+'					this.contentElement = null;',

+'					this.containerDomNode = null;',

+'				},',

+'',

+'				setContent: function(content, wrappedContent) {',

+'					if (content === this.formattedMessage) {',

+'						this.contentElement.innerHTML = "";',

+'						this.contentElement.appendChild(document.createTextNode(this.formattedMessage));',

+'					} else {',

+'						this.contentElement.innerHTML = content;',

+'					}',

+'				},',

+'',

+'				setSearchMatch: function(isMatch) {',

+'					var oldCssClass = isMatch ? "searchnonmatch" : "searchmatch";',

+'					var newCssClass = isMatch ? "searchmatch" : "searchnonmatch";',

+'					replaceClass(this.mainDiv, newCssClass, oldCssClass);',

+'				},',

+'',

+'				clearSearch: function() {',

+'					removeClass(this.mainDiv, "searchmatch");',

+'					removeClass(this.mainDiv, "searchnonmatch");',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryWrappedElementContainer(logEntry, containerDomNode) {',

+'				this.logEntry = logEntry;',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));',

+'				this.mainDiv.className = "logentry wrapped " + this.logEntry.level;',

+'				this.contentElement = this.mainDiv;',

+'			}',

+'',

+'			LogEntryWrappedElementContainer.prototype = new LogEntryElementContainer();',

+'',

+'			LogEntryWrappedElementContainer.prototype.setContent = function(content, wrappedContent) {',

+'				if (content === this.formattedMessage) {',

+'					this.contentElement.innerHTML = "";',

+'					this.contentElement.appendChild(document.createTextNode(this.formattedMessage));',

+'				} else {',

+'					this.contentElement.innerHTML = wrappedContent;',

+'				}',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryUnwrappedElementContainer(logEntry, containerDomNode) {',

+'				this.logEntry = logEntry;',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.className = "logentry unwrapped " + this.logEntry.level;',

+'				this.pre = this.mainDiv.appendChild(document.createElement("pre"));',

+'				this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));',

+'				this.pre.className = "unwrapped";',

+'				this.contentElement = this.pre;',

+'			}',

+'',

+'			LogEntryUnwrappedElementContainer.prototype = new LogEntryElementContainer();',

+'',

+'			LogEntryUnwrappedElementContainer.prototype.remove = function() {',

+'				this.doRemove();',

+'				this.pre = null;',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryMainElementContainer(logEntry, containerDomNode) {',

+'				this.logEntry = logEntry;',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.className = "logentry nonielogentry " + this.logEntry.level;',

+'				this.contentElement = this.mainDiv.appendChild(document.createElement("span"));',

+'				this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));',

+'			}',

+'',

+'			LogEntryMainElementContainer.prototype = new LogEntryElementContainer();',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntry(level, formattedMessage) {',

+'				this.level = level;',

+'				this.formattedMessage = formattedMessage;',

+'				this.rendered = false;',

+'			}',

+'',

+'			LogEntry.prototype = new LogItem();',

+'',

+'			copyProperties(LogEntry.prototype, {',

+'				render: function() {',

+'					var logEntry = this;',

+'					var containerDomNode = this.group.contentDiv;',

+'',

+'					// Support for the CSS attribute white-space in IE for Windows is',

+'					// non-existent pre version 6 and slightly odd in 6, so instead',

+'					// use two different HTML elements',

+'					if (isIe) {',

+'						this.formattedMessage = this.formattedMessage.replace(/\\r\\n/g, "\\r"); // Workaround for IE\'s treatment of white space',

+'						this.unwrappedElementContainer = new LogEntryUnwrappedElementContainer(this, this.getUnwrappedDomContainer());',

+'						this.wrappedElementContainer = new LogEntryWrappedElementContainer(this, this.getWrappedDomContainer());',

+'						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',

+'					} else {',

+'						this.mainElementContainer = new LogEntryMainElementContainer(this, this.getMainDomContainer());',

+'						this.elementContainers = [this.mainElementContainer];',

+'					}',

+'					this.content = this.formattedMessage;',

+'					this.rendered = true;',

+'				},',

+'',

+'				setContent: function(content, wrappedContent) {',

+'					if (content != this.content) {',

+'						if (isIe && (content !== this.formattedMessage)) {',

+'							content = content.replace(/\\r\\n/g, "\\r"); // Workaround for IE\'s treatment of white space',

+'						}',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].setContent(content, wrappedContent);',

+'						}',

+'						this.content = content;',

+'					}',

+'				},',

+'',

+'				getSearchMatches: function() {',

+'					var matches = [];',

+'					var i, len;',

+'					if (isIe) {',

+'						var unwrappedEls = getElementsByClass(this.unwrappedElementContainer.mainDiv, "searchterm", "span");',

+'						var wrappedEls = getElementsByClass(this.wrappedElementContainer.mainDiv, "searchterm", "span");',

+'						for (i = 0, len = unwrappedEls.length; i < len; i++) {',

+'							matches[i] = new Match(this.level, null, unwrappedEls[i], wrappedEls[i]);',

+'						}',

+'					} else {',

+'						var els = getElementsByClass(this.mainElementContainer.mainDiv, "searchterm", "span");',

+'						for (i = 0, len = els.length; i < len; i++) {',

+'							matches[i] = new Match(this.level, els[i]);',

+'						}',

+'					}',

+'					return matches;',

+'				},',

+'',

+'				setSearchMatch: function(isMatch) {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].setSearchMatch(isMatch);',

+'					}',

+'				},',

+'',

+'				clearSearch: function() {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].clearSearch();',

+'					}',

+'				},',

+'',

+'				accept: function(visitor) {',

+'					visitor.visitLogEntry(this);',

+'				},',

+'',

+'				serialize: function(items) {',

+'					items.push([LogItem.serializedItemKeys.LOG_ENTRY, this.level, this.formattedMessage]);',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItemVisitor() {',

+'			}',

+'',

+'			LogItemVisitor.prototype = {',

+'				visit: function(logItem) {',

+'				},',

+'',

+'				visitParent: function(logItem) {',

+'					if (logItem.group) {',

+'						logItem.group.accept(this);',

+'					}',

+'				},',

+'',

+'				visitChildren: function(logItem) {',

+'					for (var i = 0, len = logItem.children.length; i < len; i++) {',

+'						logItem.children[i].accept(this);',

+'					}',

+'				},',

+'',

+'				visitLogEntry: function(logEntry) {',

+'					this.visit(logEntry);',

+'				},',

+'',

+'				visitSeparator: function(separator) {',

+'					this.visit(separator);',

+'				},',

+'',

+'				visitGroup: function(group) {',

+'					this.visit(group);',

+'				}',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function GroupFlattener() {',

+'				this.logEntriesAndSeparators = [];',

+'			}',

+'',

+'			GroupFlattener.prototype = new LogItemVisitor();',

+'',

+'			GroupFlattener.prototype.visitGroup = function(group) {',

+'				this.visitChildren(group);',

+'			};',

+'',

+'			GroupFlattener.prototype.visitLogEntry = function(logEntry) {',

+'				this.logEntriesAndSeparators.push(logEntry);',

+'			};',

+'',

+'			GroupFlattener.prototype.visitSeparator = function(separator) {',

+'				this.logEntriesAndSeparators.push(separator);',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			window.onload = function() {',

+'				// Sort out document.domain',

+'				if (location.search) {',

+'					var queryBits = unescape(location.search).substr(1).split("&"), nameValueBits;',

+'					for (var i = 0, len = queryBits.length; i < len; i++) {',

+'						nameValueBits = queryBits[i].split("=");',

+'						if (nameValueBits[0] == "log4javascript_domain") {',

+'							document.domain = nameValueBits[1];',

+'							break;',

+'						}',

+'					}',

+'				}',

+'',

+'				// Create DOM objects',

+'				logMainContainer = $("log");',

+'				if (isIePre7) {',

+'					addClass(logMainContainer, "oldIe");',

+'				}',

+'',

+'				rootGroup = new Group("root", true);',

+'				rootGroup.render();',

+'				currentGroup = rootGroup;',

+'				',

+'				setCommandInputWidth();',

+'				setLogContainerHeight();',

+'				toggleLoggingEnabled();',

+'				toggleSearchEnabled();',

+'				toggleSearchFilter();',

+'				toggleSearchHighlight();',

+'				applyFilters();',

+'				checkAllLevels();',

+'				toggleWrap();',

+'				toggleNewestAtTop();',

+'				toggleScrollToLatest();',

+'				renderQueuedLogItems();',

+'				loaded = true;',

+'				$("command").value = "";',

+'				$("command").autocomplete = "off";',

+'				$("command").onkeydown = function(evt) {',

+'					evt = getEvent(evt);',

+'					if (evt.keyCode == 10 || evt.keyCode == 13) { // Return/Enter',

+'						evalCommandLine();',

+'						stopPropagation(evt);',

+'					} else if (evt.keyCode == 27) { // Escape',

+'						this.value = "";',

+'						this.focus();',

+'					} else if (evt.keyCode == 38 && commandHistory.length > 0) { // Up',

+'						currentCommandIndex = Math.max(0, currentCommandIndex - 1);',

+'						this.value = commandHistory[currentCommandIndex];',

+'						moveCaretToEnd(this);',

+'					} else if (evt.keyCode == 40 && commandHistory.length > 0) { // Down',

+'						currentCommandIndex = Math.min(commandHistory.length - 1, currentCommandIndex + 1);',

+'						this.value = commandHistory[currentCommandIndex];',

+'						moveCaretToEnd(this);',

+'					}',

+'				};',

+'',

+'				// Prevent the keypress moving the caret in Firefox',

+'				$("command").onkeypress = function(evt) {',

+'					evt = getEvent(evt);',

+'					if (evt.keyCode == 38 && commandHistory.length > 0 && evt.preventDefault) { // Up',

+'						evt.preventDefault();',

+'					}',

+'				};',

+'',

+'				// Prevent the keyup event blurring the input in Opera',

+'				$("command").onkeyup = function(evt) {',

+'					evt = getEvent(evt);',

+'					if (evt.keyCode == 27 && evt.preventDefault) { // Up',

+'						evt.preventDefault();',

+'						this.focus();',

+'					}',

+'				};',

+'',

+'				// Add document keyboard shortcuts',

+'				document.onkeydown = function keyEventHandler(evt) {',

+'					evt = getEvent(evt);',

+'					switch (evt.keyCode) {',

+'						case 69: // Ctrl + shift + E: re-execute last command',

+'							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',

+'								evalLastCommand();',

+'								cancelKeyEvent(evt);',

+'								return false;',

+'							}',

+'							break;',

+'						case 75: // Ctrl + shift + K: focus search',

+'							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',

+'								focusSearch();',

+'								cancelKeyEvent(evt);',

+'								return false;',

+'							}',

+'							break;',

+'						case 40: // Ctrl + shift + down arrow: focus command line',

+'						case 76: // Ctrl + shift + L: focus command line',

+'							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',

+'								focusCommandLine();',

+'								cancelKeyEvent(evt);',

+'								return false;',

+'							}',

+'							break;',

+'					}',

+'				};',

+'',

+'				// Workaround to make sure log div starts at the correct size',

+'				setTimeout(setLogContainerHeight, 20);',

+'',

+'				setShowCommandLine(showCommandLine);',

+'				doSearch();',

+'			};',

+'',

+'			window.onunload = function() {',

+'				if (mainWindowExists()) {',

+'					appender.unload();',

+'				}',

+'				appender = null;',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function toggleLoggingEnabled() {',

+'				setLoggingEnabled($("enableLogging").checked);',

+'			}',

+'',

+'			function setLoggingEnabled(enable) {',

+'				loggingEnabled = enable;',

+'			}',

+'',

+'			var appender = null;',

+'',

+'			function setAppender(appenderParam) {',

+'				appender = appenderParam;',

+'			}',

+'',

+'			function setShowCloseButton(showCloseButton) {',

+'				$("closeButton").style.display = showCloseButton ? "inline" : "none";',

+'			}',

+'',

+'			function setShowHideButton(showHideButton) {',

+'				$("hideButton").style.display = showHideButton ? "inline" : "none";',

+'			}',

+'',

+'			var newestAtTop = false;',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItemContentReverser() {',

+'			}',

+'			',

+'			LogItemContentReverser.prototype = new LogItemVisitor();',

+'			',

+'			LogItemContentReverser.prototype.visitGroup = function(group) {',

+'				group.reverseChildren();',

+'				this.visitChildren(group);',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function setNewestAtTop(isNewestAtTop) {',

+'				var oldNewestAtTop = newestAtTop;',

+'				var i, iLen, j, jLen;',

+'				newestAtTop = Boolean(isNewestAtTop);',

+'				if (oldNewestAtTop != newestAtTop) {',

+'					var visitor = new LogItemContentReverser();',

+'					rootGroup.accept(visitor);',

+'',

+'					// Reassemble the matches array',

+'					if (currentSearch) {',

+'						var currentMatch = currentSearch.matches[currentMatchIndex];',

+'						var matchIndex = 0;',

+'						var matches = [];',

+'						var actOnLogEntry = function(logEntry) {',

+'							var logEntryMatches = logEntry.getSearchMatches();',

+'							for (j = 0, jLen = logEntryMatches.length; j < jLen; j++) {',

+'								matches[matchIndex] = logEntryMatches[j];',

+'								if (currentMatch && logEntryMatches[j].equals(currentMatch)) {',

+'									currentMatchIndex = matchIndex;',

+'								}',

+'								matchIndex++;',

+'							}',

+'						};',

+'						if (newestAtTop) {',

+'							for (i = logEntries.length - 1; i >= 0; i--) {',

+'								actOnLogEntry(logEntries[i]);',

+'							}',

+'						} else {',

+'							for (i = 0, iLen = logEntries.length; i < iLen; i++) {',

+'								actOnLogEntry(logEntries[i]);',

+'							}',

+'						}',

+'						currentSearch.matches = matches;',

+'						if (currentMatch) {',

+'							currentMatch.setCurrent();',

+'						}',

+'					} else if (scrollToLatest) {',

+'						doScrollToLatest();',

+'					}',

+'				}',

+'				$("newestAtTop").checked = isNewestAtTop;',

+'			}',

+'',

+'			function toggleNewestAtTop() {',

+'				var isNewestAtTop = $("newestAtTop").checked;',

+'				setNewestAtTop(isNewestAtTop);',

+'			}',

+'',

+'			var scrollToLatest = true;',

+'',

+'			function setScrollToLatest(isScrollToLatest) {',

+'				scrollToLatest = isScrollToLatest;',

+'				if (scrollToLatest) {',

+'					doScrollToLatest();',

+'				}',

+'				$("scrollToLatest").checked = isScrollToLatest;',

+'			}',

+'',

+'			function toggleScrollToLatest() {',

+'				var isScrollToLatest = $("scrollToLatest").checked;',

+'				setScrollToLatest(isScrollToLatest);',

+'			}',

+'',

+'			function doScrollToLatest() {',

+'				var l = logMainContainer;',

+'				if (typeof l.scrollTop != "undefined") {',

+'					if (newestAtTop) {',

+'						l.scrollTop = 0;',

+'					} else {',

+'						var latestLogEntry = l.lastChild;',

+'						if (latestLogEntry) {',

+'							l.scrollTop = l.scrollHeight;',

+'						}',

+'					}',

+'				}',

+'			}',

+'',

+'			var closeIfOpenerCloses = true;',

+'',

+'			function setCloseIfOpenerCloses(isCloseIfOpenerCloses) {',

+'				closeIfOpenerCloses = isCloseIfOpenerCloses;',

+'			}',

+'',

+'			var maxMessages = null;',

+'',

+'			function setMaxMessages(max) {',

+'				maxMessages = max;',

+'				pruneLogEntries();',

+'			}',

+'',

+'			var showCommandLine = false;',

+'',

+'			function setShowCommandLine(isShowCommandLine) {',

+'				showCommandLine = isShowCommandLine;',

+'				if (loaded) {',

+'					$("commandLine").style.display = showCommandLine ? "block" : "none";',

+'					setCommandInputWidth();',

+'					setLogContainerHeight();',

+'				}',

+'			}',

+'',

+'			function focusCommandLine() {',

+'				if (loaded) {',

+'					$("command").focus();',

+'				}',

+'			}',

+'',

+'			function focusSearch() {',

+'				if (loaded) {',

+'					$("searchBox").focus();',

+'				}',

+'			}',

+'',

+'			function getLogItems() {',

+'				var items = [];',

+'				for (var i = 0, len = logItems.length; i < len; i++) {',

+'					logItems[i].serialize(items);',

+'				}',

+'				return items;',

+'			}',

+'',

+'			function setLogItems(items) {',

+'				var loggingReallyEnabled = loggingEnabled;',

+'				// Temporarily turn logging on',

+'				loggingEnabled = true;',

+'				for (var i = 0, len = items.length; i < len; i++) {',

+'					switch (items[i][0]) {',

+'						case LogItem.serializedItemKeys.LOG_ENTRY:',

+'							log(items[i][1], items[i][2]);',

+'							break;',

+'						case LogItem.serializedItemKeys.GROUP_START:',

+'							group(items[i][1]);',

+'							break;',

+'						case LogItem.serializedItemKeys.GROUP_END:',

+'							groupEnd();',

+'							break;',

+'					}',

+'				}',

+'				loggingEnabled = loggingReallyEnabled;',

+'			}',

+'',

+'			function log(logLevel, formattedMessage) {',

+'				if (loggingEnabled) {',

+'					var logEntry = new LogEntry(logLevel, formattedMessage);',

+'					logEntries.push(logEntry);',

+'					logEntriesAndSeparators.push(logEntry);',

+'					logItems.push(logEntry);',

+'					currentGroup.addChild(logEntry);',

+'					if (loaded) {',

+'						if (logQueuedEventsTimer !== null) {',

+'							clearTimeout(logQueuedEventsTimer);',

+'						}',

+'						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);',

+'						unrenderedLogItemsExist = true;',

+'					}',

+'				}',

+'			}',

+'',

+'			function renderQueuedLogItems() {',

+'				logQueuedEventsTimer = null;',

+'				var pruned = pruneLogEntries();',

+'',

+'				// Render any unrendered log entries and apply the current search to them',

+'				var initiallyHasMatches = currentSearch ? currentSearch.hasMatches() : false;',

+'				for (var i = 0, len = logItems.length; i < len; i++) {',

+'					if (!logItems[i].rendered) {',

+'						logItems[i].render();',

+'						logItems[i].appendToLog();',

+'						if (currentSearch && (logItems[i] instanceof LogEntry)) {',

+'							currentSearch.applyTo(logItems[i]);',

+'						}',

+'					}',

+'				}',

+'				if (currentSearch) {',

+'					if (pruned) {',

+'						if (currentSearch.hasVisibleMatches()) {',

+'							if (currentMatchIndex === null) {',

+'								setCurrentMatchIndex(0);',

+'							}',

+'							displayMatches();',

+'						} else {',

+'							displayNoMatches();',

+'						}',

+'					} else if (!initiallyHasMatches && currentSearch.hasVisibleMatches()) {',

+'						setCurrentMatchIndex(0);',

+'						displayMatches();',

+'					}',

+'				}',

+'				if (scrollToLatest) {',

+'					doScrollToLatest();',

+'				}',

+'				unrenderedLogItemsExist = false;',

+'			}',

+'',

+'			function pruneLogEntries() {',

+'				if ((maxMessages !== null) && (logEntriesAndSeparators.length > maxMessages)) {',

+'					var numberToDelete = logEntriesAndSeparators.length - maxMessages;',

+'					var prunedLogEntries = logEntriesAndSeparators.slice(0, numberToDelete);',

+'					if (currentSearch) {',

+'						currentSearch.removeMatches(prunedLogEntries);',

+'					}',

+'					var group;',

+'					for (var i = 0; i < numberToDelete; i++) {',

+'						group = logEntriesAndSeparators[i].group;',

+'						array_remove(logItems, logEntriesAndSeparators[i]);',

+'						array_remove(logEntries, logEntriesAndSeparators[i]);',

+'						logEntriesAndSeparators[i].remove(true, true);',

+'						if (group.children.length === 0 && group !== currentGroup && group !== rootGroup) {',

+'							array_remove(logItems, group);',

+'							group.remove(true, true);',

+'						}',

+'					}',

+'					logEntriesAndSeparators = array_removeFromStart(logEntriesAndSeparators, numberToDelete);',

+'					return true;',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function group(name, startExpanded) {',

+'				if (loggingEnabled) {',

+'					initiallyExpanded = (typeof startExpanded === "undefined") ? true : Boolean(startExpanded);',

+'					var newGroup = new Group(name, false, initiallyExpanded);',

+'					currentGroup.addChild(newGroup);',

+'					currentGroup = newGroup;',

+'					logItems.push(newGroup);',

+'					if (loaded) {',

+'						if (logQueuedEventsTimer !== null) {',

+'							clearTimeout(logQueuedEventsTimer);',

+'						}',

+'						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);',

+'						unrenderedLogItemsExist = true;',

+'					}',

+'				}',

+'			}',

+'',

+'			function groupEnd() {',

+'				currentGroup = (currentGroup === rootGroup) ? rootGroup : currentGroup.group;',

+'			}',

+'',

+'			function mainPageReloaded() {',

+'				currentGroup = rootGroup;',

+'				var separator = new Separator();',

+'				logEntriesAndSeparators.push(separator);',

+'				logItems.push(separator);',

+'				currentGroup.addChild(separator);',

+'			}',

+'',

+'			function closeWindow() {',

+'				if (appender && mainWindowExists()) {',

+'					appender.close(true);',

+'				} else {',

+'					window.close();',

+'				}',

+'			}',

+'',

+'			function hide() {',

+'				if (appender && mainWindowExists()) {',

+'					appender.hide();',

+'				}',

+'			}',

+'',

+'			var mainWindow = window;',

+'			var windowId = "log4javascriptConsoleWindow_" + new Date().getTime() + "_" + ("" + Math.random()).substr(2);',

+'',

+'			function setMainWindow(win) {',

+'				mainWindow = win;',

+'				mainWindow[windowId] = window;',

+'				// If this is a pop-up, poll the opener to see if it\'s closed',

+'				if (opener && closeIfOpenerCloses) {',

+'					pollOpener();',

+'				}',

+'			}',

+'',

+'			function pollOpener() {',

+'				if (closeIfOpenerCloses) {',

+'					if (mainWindowExists()) {',

+'						setTimeout(pollOpener, 500);',

+'					} else {',

+'						closeWindow();',

+'					}',

+'				}',

+'			}',

+'',

+'			function mainWindowExists() {',

+'				try {',

+'					return (mainWindow && !mainWindow.closed &&',

+'						mainWindow[windowId] == window);',

+'				} catch (ex) {}',

+'				return false;',

+'			}',

+'',

+'			var logLevels = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"];',

+'',

+'			function getCheckBox(logLevel) {',

+'				return $("switch_" + logLevel);',

+'			}',

+'',

+'			function getIeWrappedLogContainer() {',

+'				return $("log_wrapped");',

+'			}',

+'',

+'			function getIeUnwrappedLogContainer() {',

+'				return $("log_unwrapped");',

+'			}',

+'',

+'			function applyFilters() {',

+'				for (var i = 0; i < logLevels.length; i++) {',

+'					if (getCheckBox(logLevels[i]).checked) {',

+'						addClass(logMainContainer, logLevels[i]);',

+'					} else {',

+'						removeClass(logMainContainer, logLevels[i]);',

+'					}',

+'				}',

+'				updateSearchFromFilters();',

+'			}',

+'',

+'			function toggleAllLevels() {',

+'				var turnOn = $("switch_ALL").checked;',

+'				for (var i = 0; i < logLevels.length; i++) {',

+'					getCheckBox(logLevels[i]).checked = turnOn;',

+'					if (turnOn) {',

+'						addClass(logMainContainer, logLevels[i]);',

+'					} else {',

+'						removeClass(logMainContainer, logLevels[i]);',

+'					}',

+'				}',

+'			}',

+'',

+'			function checkAllLevels() {',

+'				for (var i = 0; i < logLevels.length; i++) {',

+'					if (!getCheckBox(logLevels[i]).checked) {',

+'						getCheckBox("ALL").checked = false;',

+'						return;',

+'					}',

+'				}',

+'				getCheckBox("ALL").checked = true;',

+'			}',

+'',

+'			function clearLog() {',

+'				rootGroup.clear();',

+'				currentGroup = rootGroup;',

+'				logEntries = [];',

+'				logItems = [];',

+'				logEntriesAndSeparators = [];',

+' 				doSearch();',

+'			}',

+'',

+'			function toggleWrap() {',

+'				var enable = $("wrap").checked;',

+'				if (enable) {',

+'					addClass(logMainContainer, "wrap");',

+'				} else {',

+'					removeClass(logMainContainer, "wrap");',

+'				}',

+'				refreshCurrentMatch();',

+'			}',

+'',

+'			/* ------------------------------------------------------------------- */',

+'',

+'			// Search',

+'',

+'			var searchTimer = null;',

+'',

+'			function scheduleSearch() {',

+'				try {',

+'					clearTimeout(searchTimer);',

+'				} catch (ex) {',

+'					// Do nothing',

+'				}',

+'				searchTimer = setTimeout(doSearch, 500);',

+'			}',

+'',

+'			function Search(searchTerm, isRegex, searchRegex, isCaseSensitive) {',

+'				this.searchTerm = searchTerm;',

+'				this.isRegex = isRegex;',

+'				this.searchRegex = searchRegex;',

+'				this.isCaseSensitive = isCaseSensitive;',

+'				this.matches = [];',

+'			}',

+'',

+'			Search.prototype = {',

+'				hasMatches: function() {',

+'					return this.matches.length > 0;',

+'				},',

+'',

+'				hasVisibleMatches: function() {',

+'					if (this.hasMatches()) {',

+'						for (var i = 0; i < this.matches.length; i++) {',

+'							if (this.matches[i].isVisible()) {',

+'								return true;',

+'							}',

+'						}',

+'					}',

+'					return false;',

+'				},',

+'',

+'				match: function(logEntry) {',

+'					var entryText = String(logEntry.formattedMessage);',

+'					var matchesSearch = false;',

+'					if (this.isRegex) {',

+'						matchesSearch = this.searchRegex.test(entryText);',

+'					} else if (this.isCaseSensitive) {',

+'						matchesSearch = (entryText.indexOf(this.searchTerm) > -1);',

+'					} else {',

+'						matchesSearch = (entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1);',

+'					}',

+'					return matchesSearch;',

+'				},',

+'',

+'				getNextVisibleMatchIndex: function() {',

+'					for (var i = currentMatchIndex + 1; i < this.matches.length; i++) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					// Start again from the first match',

+'					for (i = 0; i <= currentMatchIndex; i++) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					return -1;',

+'				},',

+'',

+'				getPreviousVisibleMatchIndex: function() {',

+'					for (var i = currentMatchIndex - 1; i >= 0; i--) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					// Start again from the last match',

+'					for (var i = this.matches.length - 1; i >= currentMatchIndex; i--) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					return -1;',

+'				},',

+'',

+'				applyTo: function(logEntry) {',

+'					var doesMatch = this.match(logEntry);',

+'					if (doesMatch) {',

+'						logEntry.group.expand();',

+'						logEntry.setSearchMatch(true);',

+'						var logEntryContent;',

+'						var wrappedLogEntryContent;',

+'						var searchTermReplacementStartTag = "<span class=\\\"searchterm\\\">";',

+'						var searchTermReplacementEndTag = "<" + "/span>";',

+'						var preTagName = isIe ? "pre" : "span";',

+'						var preStartTag = "<" + preTagName + " class=\\\"pre\\\">";',

+'						var preEndTag = "<" + "/" + preTagName + ">";',

+'						var startIndex = 0;',

+'						var searchIndex, matchedText, textBeforeMatch;',

+'						if (this.isRegex) {',

+'							var flags = this.isCaseSensitive ? "g" : "gi";',

+'							var capturingRegex = new RegExp("(" + this.searchRegex.source + ")", flags);',

+'',

+'							// Replace the search term with temporary tokens for the start and end tags',

+'							var rnd = ("" + Math.random()).substr(2);',

+'							var startToken = "%%s" + rnd + "%%";',

+'							var endToken = "%%e" + rnd + "%%";',

+'							logEntryContent = logEntry.formattedMessage.replace(capturingRegex, startToken + "$1" + endToken);',

+'',

+'							// Escape the HTML to get rid of angle brackets',

+'							logEntryContent = escapeHtml(logEntryContent);',

+'',

+'							// Substitute the proper HTML back in for the search match',

+'							var result;',

+'							var searchString = logEntryContent;',

+'							logEntryContent = "";',

+'							wrappedLogEntryContent = "";',

+'							while ((searchIndex = searchString.indexOf(startToken, startIndex)) > -1) {',

+'								var endTokenIndex = searchString.indexOf(endToken, searchIndex);',

+'								matchedText = searchString.substring(searchIndex + startToken.length, endTokenIndex);',

+'								textBeforeMatch = searchString.substring(startIndex, searchIndex);',

+'								logEntryContent += preStartTag + textBeforeMatch + preEndTag;',

+'								logEntryContent += searchTermReplacementStartTag + preStartTag + matchedText +',

+'									preEndTag + searchTermReplacementEndTag;',

+'								if (isIe) {',

+'									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +',

+'										matchedText + searchTermReplacementEndTag;',

+'								}',

+'								startIndex = endTokenIndex + endToken.length;',

+'							}',

+'							logEntryContent += preStartTag + searchString.substr(startIndex) + preEndTag;',

+'							if (isIe) {',

+'								wrappedLogEntryContent += searchString.substr(startIndex);',

+'							}',

+'						} else {',

+'							logEntryContent = "";',

+'							wrappedLogEntryContent = "";',

+'							var searchTermReplacementLength = searchTermReplacementStartTag.length +',

+'								this.searchTerm.length + searchTermReplacementEndTag.length;',

+'							var searchTermLength = this.searchTerm.length;',

+'							var searchTermLowerCase = this.searchTerm.toLowerCase();',

+'							var logTextLowerCase = logEntry.formattedMessage.toLowerCase();',

+'							while ((searchIndex = logTextLowerCase.indexOf(searchTermLowerCase, startIndex)) > -1) {',

+'								matchedText = escapeHtml(logEntry.formattedMessage.substr(searchIndex, this.searchTerm.length));',

+'								textBeforeMatch = escapeHtml(logEntry.formattedMessage.substring(startIndex, searchIndex));',

+'								var searchTermReplacement = searchTermReplacementStartTag +',

+'									preStartTag + matchedText + preEndTag + searchTermReplacementEndTag;',

+'								logEntryContent += preStartTag + textBeforeMatch + preEndTag + searchTermReplacement;',

+'								if (isIe) {',

+'									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +',

+'										matchedText + searchTermReplacementEndTag;',

+'								}',

+'								startIndex = searchIndex + searchTermLength;',

+'							}',

+'							var textAfterLastMatch = escapeHtml(logEntry.formattedMessage.substr(startIndex));',

+'							logEntryContent += preStartTag + textAfterLastMatch + preEndTag;',

+'							if (isIe) {',

+'								wrappedLogEntryContent += textAfterLastMatch;',

+'							}',

+'						}',

+'						logEntry.setContent(logEntryContent, wrappedLogEntryContent);',

+'						var logEntryMatches = logEntry.getSearchMatches();',

+'						this.matches = this.matches.concat(logEntryMatches);',

+'					} else {',

+'						logEntry.setSearchMatch(false);',

+'						logEntry.setContent(logEntry.formattedMessage, logEntry.formattedMessage);',

+'					}',

+'					return doesMatch;',

+'				},',

+'',

+'				removeMatches: function(logEntries) {',

+'					var matchesToRemoveCount = 0;',

+'					var currentMatchRemoved = false;',

+'					var matchesToRemove = [];',

+'					var i, iLen, j, jLen;',

+'',

+'					// Establish the list of matches to be removed',

+'					for (i = 0, iLen = this.matches.length; i < iLen; i++) {',

+'						for (j = 0, jLen = logEntries.length; j < jLen; j++) {',

+'							if (this.matches[i].belongsTo(logEntries[j])) {',

+'								matchesToRemove.push(this.matches[i]);',

+'								if (i === currentMatchIndex) {',

+'									currentMatchRemoved = true;',

+'								}',

+'							}',

+'						}',

+'					}',

+'',

+'					// Set the new current match index if the current match has been deleted',

+'					// This will be the first match that appears after the first log entry being',

+'					// deleted, if one exists; otherwise, it\'s the first match overall',

+'					var newMatch = currentMatchRemoved ? null : this.matches[currentMatchIndex];',

+'					if (currentMatchRemoved) {',

+'						for (i = currentMatchIndex, iLen = this.matches.length; i < iLen; i++) {',

+'							if (this.matches[i].isVisible() && !array_contains(matchesToRemove, this.matches[i])) {',

+'								newMatch = this.matches[i];',

+'								break;',

+'							}',

+'						}',

+'					}',

+'',

+'					// Remove the matches',

+'					for (i = 0, iLen = matchesToRemove.length; i < iLen; i++) {',

+'						array_remove(this.matches, matchesToRemove[i]);',

+'						matchesToRemove[i].remove();',

+'					}',

+'',

+'					// Set the new match, if one exists',

+'					if (this.hasVisibleMatches()) {',

+'						if (newMatch === null) {',

+'							setCurrentMatchIndex(0);',

+'						} else {',

+'							// Get the index of the new match',

+'							var newMatchIndex = 0;',

+'							for (i = 0, iLen = this.matches.length; i < iLen; i++) {',

+'								if (newMatch === this.matches[i]) {',

+'									newMatchIndex = i;',

+'									break;',

+'								}',

+'							}',

+'							setCurrentMatchIndex(newMatchIndex);',

+'						}',

+'					} else {',

+'						currentMatchIndex = null;',

+'						displayNoMatches();',

+'					}',

+'				}',

+'			};',

+'',

+'			function getPageOffsetTop(el, container) {',

+'				var currentEl = el;',

+'				var y = 0;',

+'				while (currentEl && currentEl != container) {',

+'					y += currentEl.offsetTop;',

+'					currentEl = currentEl.offsetParent;',

+'				}',

+'				return y;',

+'			}',

+'',

+'			function scrollIntoView(el) {',

+'				var logContainer = logMainContainer;',

+'				// Check if the whole width of the element is visible and centre if not',

+'				if (!$("wrap").checked) {',

+'					var logContainerLeft = logContainer.scrollLeft;',

+'					var logContainerRight = logContainerLeft  + logContainer.offsetWidth;',

+'					var elLeft = el.offsetLeft;',

+'					var elRight = elLeft + el.offsetWidth;',

+'					if (elLeft < logContainerLeft || elRight > logContainerRight) {',

+'						logContainer.scrollLeft = elLeft - (logContainer.offsetWidth - el.offsetWidth) / 2;',

+'					}',

+'				}',

+'				// Check if the whole height of the element is visible and centre if not',

+'				var logContainerTop = logContainer.scrollTop;',

+'				var logContainerBottom = logContainerTop  + logContainer.offsetHeight;',

+'				var elTop = getPageOffsetTop(el) - getToolBarsHeight();',

+'				var elBottom = elTop + el.offsetHeight;',

+'				if (elTop < logContainerTop || elBottom > logContainerBottom) {',

+'					logContainer.scrollTop = elTop - (logContainer.offsetHeight - el.offsetHeight) / 2;',

+'				}',

+'			}',

+'',

+'			function Match(logEntryLevel, spanInMainDiv, spanInUnwrappedPre, spanInWrappedDiv) {',

+'				this.logEntryLevel = logEntryLevel;',

+'				this.spanInMainDiv = spanInMainDiv;',

+'				if (isIe) {',

+'					this.spanInUnwrappedPre = spanInUnwrappedPre;',

+'					this.spanInWrappedDiv = spanInWrappedDiv;',

+'				}',

+'				this.mainSpan = isIe ? spanInUnwrappedPre : spanInMainDiv;',

+'			}',

+'',

+'			Match.prototype = {',

+'				equals: function(match) {',

+'					return this.mainSpan === match.mainSpan;',

+'				},',

+'',

+'				setCurrent: function() {',

+'					if (isIe) {',

+'						addClass(this.spanInUnwrappedPre, "currentmatch");',

+'						addClass(this.spanInWrappedDiv, "currentmatch");',

+'						// Scroll the visible one into view',

+'						var elementToScroll = $("wrap").checked ? this.spanInWrappedDiv : this.spanInUnwrappedPre;',

+'						scrollIntoView(elementToScroll);',

+'					} else {',

+'						addClass(this.spanInMainDiv, "currentmatch");',

+'						scrollIntoView(this.spanInMainDiv);',

+'					}',

+'				},',

+'',

+'				belongsTo: function(logEntry) {',

+'					if (isIe) {',

+'						return isDescendant(this.spanInUnwrappedPre, logEntry.unwrappedPre);',

+'					} else {',

+'						return isDescendant(this.spanInMainDiv, logEntry.mainDiv);',

+'					}',

+'				},',

+'',

+'				setNotCurrent: function() {',

+'					if (isIe) {',

+'						removeClass(this.spanInUnwrappedPre, "currentmatch");',

+'						removeClass(this.spanInWrappedDiv, "currentmatch");',

+'					} else {',

+'						removeClass(this.spanInMainDiv, "currentmatch");',

+'					}',

+'				},',

+'',

+'				isOrphan: function() {',

+'					return isOrphan(this.mainSpan);',

+'				},',

+'',

+'				isVisible: function() {',

+'					return getCheckBox(this.logEntryLevel).checked;',

+'				},',

+'',

+'				remove: function() {',

+'					if (isIe) {',

+'						this.spanInUnwrappedPre = null;',

+'						this.spanInWrappedDiv = null;',

+'					} else {',

+'						this.spanInMainDiv = null;',

+'					}',

+'				}',

+'			};',

+'',

+'			var currentSearch = null;',

+'			var currentMatchIndex = null;',

+'',

+'			function doSearch() {',

+'				var searchBox = $("searchBox");',

+'				var searchTerm = searchBox.value;',

+'				var isRegex = $("searchRegex").checked;',

+'				var isCaseSensitive = $("searchCaseSensitive").checked;',

+'				var i;',

+'',

+'				if (searchTerm === "") {',

+'					$("searchReset").disabled = true;',

+'					$("searchNav").style.display = "none";',

+'					removeClass(document.body, "searching");',

+'					removeClass(searchBox, "hasmatches");',

+'					removeClass(searchBox, "nomatches");',

+'					for (i = 0; i < logEntries.length; i++) {',

+'						logEntries[i].clearSearch();',

+'						logEntries[i].setContent(logEntries[i].formattedMessage, logEntries[i].formattedMessage);',

+'					}',

+'					currentSearch = null;',

+'					setLogContainerHeight();',

+'				} else {',

+'					$("searchReset").disabled = false;',

+'					$("searchNav").style.display = "block";',

+'					var searchRegex;',

+'					var regexValid;',

+'					if (isRegex) {',

+'						try {',

+'							searchRegex = isCaseSensitive ? new RegExp(searchTerm, "g") : new RegExp(searchTerm, "gi");',

+'							regexValid = true;',

+'							replaceClass(searchBox, "validregex", "invalidregex");',

+'							searchBox.title = "Valid regex";',

+'						} catch (ex) {',

+'							regexValid = false;',

+'							replaceClass(searchBox, "invalidregex", "validregex");',

+'							searchBox.title = "Invalid regex: " + (ex.message ? ex.message : (ex.description ? ex.description : "unknown error"));',

+'							return;',

+'						}',

+'					} else {',

+'						searchBox.title = "";',

+'						removeClass(searchBox, "validregex");',

+'						removeClass(searchBox, "invalidregex");',

+'					}',

+'					addClass(document.body, "searching");',

+'					currentSearch = new Search(searchTerm, isRegex, searchRegex, isCaseSensitive);',

+'					for (i = 0; i < logEntries.length; i++) {',

+'						currentSearch.applyTo(logEntries[i]);',

+'					}',

+'					setLogContainerHeight();',

+'',

+'					// Highlight the first search match',

+'					if (currentSearch.hasVisibleMatches()) {',

+'						setCurrentMatchIndex(0);',

+'						displayMatches();',

+'					} else {',

+'						displayNoMatches();',

+'					}',

+'				}',

+'			}',

+'',

+'			function updateSearchFromFilters() {',

+'				if (currentSearch) {',

+'					if (currentSearch.hasMatches()) {',

+'						if (currentMatchIndex === null) {',

+'							currentMatchIndex = 0;',

+'						}',

+'						var currentMatch = currentSearch.matches[currentMatchIndex];',

+'						if (currentMatch.isVisible()) {',

+'							displayMatches();',

+'							setCurrentMatchIndex(currentMatchIndex);',

+'						} else {',

+'							currentMatch.setNotCurrent();',

+'							// Find the next visible match, if one exists',

+'							var nextVisibleMatchIndex = currentSearch.getNextVisibleMatchIndex();',

+'							if (nextVisibleMatchIndex > -1) {',

+'								setCurrentMatchIndex(nextVisibleMatchIndex);',

+'								displayMatches();',

+'							} else {',

+'								displayNoMatches();',

+'							}',

+'						}',

+'					} else {',

+'						displayNoMatches();',

+'					}',

+'				}',

+'			}',

+'',

+'			function refreshCurrentMatch() {',

+'				if (currentSearch && currentSearch.hasVisibleMatches()) {',

+'					setCurrentMatchIndex(currentMatchIndex);',

+'				}',

+'			}',

+'',

+'			function displayMatches() {',

+'				replaceClass($("searchBox"), "hasmatches", "nomatches");',

+'				$("searchBox").title = "" + currentSearch.matches.length + " matches found";',

+'				$("searchNav").style.display = "block";',

+'				setLogContainerHeight();',

+'			}',

+'',

+'			function displayNoMatches() {',

+'				replaceClass($("searchBox"), "nomatches", "hasmatches");',

+'				$("searchBox").title = "No matches found";',

+'				$("searchNav").style.display = "none";',

+'				setLogContainerHeight();',

+'			}',

+'',

+'			function toggleSearchEnabled(enable) {',

+'				enable = (typeof enable == "undefined") ? !$("searchDisable").checked : enable;',

+'				$("searchBox").disabled = !enable;',

+'				$("searchReset").disabled = !enable;',

+'				$("searchRegex").disabled = !enable;',

+'				$("searchNext").disabled = !enable;',

+'				$("searchPrevious").disabled = !enable;',

+'				$("searchCaseSensitive").disabled = !enable;',

+'				$("searchNav").style.display = (enable && ($("searchBox").value !== "") &&',

+'						currentSearch && currentSearch.hasVisibleMatches()) ?',

+'					"block" : "none";',

+'				if (enable) {',

+'					removeClass($("search"), "greyedout");',

+'					addClass(document.body, "searching");',

+'					if ($("searchHighlight").checked) {',

+'						addClass(logMainContainer, "searchhighlight");',

+'					} else {',

+'						removeClass(logMainContainer, "searchhighlight");',

+'					}',

+'					if ($("searchFilter").checked) {',

+'						addClass(logMainContainer, "searchfilter");',

+'					} else {',

+'						removeClass(logMainContainer, "searchfilter");',

+'					}',

+'					$("searchDisable").checked = !enable;',

+'				} else {',

+'					addClass($("search"), "greyedout");',

+'					removeClass(document.body, "searching");',

+'					removeClass(logMainContainer, "searchhighlight");',

+'					removeClass(logMainContainer, "searchfilter");',

+'				}',

+'				setLogContainerHeight();',

+'			}',

+'',

+'			function toggleSearchFilter() {',

+'				var enable = $("searchFilter").checked;',

+'				if (enable) {',

+'					addClass(logMainContainer, "searchfilter");',

+'				} else {',

+'					removeClass(logMainContainer, "searchfilter");',

+'				}',

+'				refreshCurrentMatch();',

+'			}',

+'',

+'			function toggleSearchHighlight() {',

+'				var enable = $("searchHighlight").checked;',

+'				if (enable) {',

+'					addClass(logMainContainer, "searchhighlight");',

+'				} else {',

+'					removeClass(logMainContainer, "searchhighlight");',

+'				}',

+'			}',

+'',

+'			function clearSearch() {',

+'				$("searchBox").value = "";',

+'				doSearch();',

+'			}',

+'',

+'			function searchNext() {',

+'				if (currentSearch !== null && currentMatchIndex !== null) {',

+'					currentSearch.matches[currentMatchIndex].setNotCurrent();',

+'					var nextMatchIndex = currentSearch.getNextVisibleMatchIndex();',

+'					if (nextMatchIndex > currentMatchIndex || confirm("Reached the end of the page. Start from the top?")) {',

+'						setCurrentMatchIndex(nextMatchIndex);',

+'					}',

+'				}',

+'			}',

+'',

+'			function searchPrevious() {',

+'				if (currentSearch !== null && currentMatchIndex !== null) {',

+'					currentSearch.matches[currentMatchIndex].setNotCurrent();',

+'					var previousMatchIndex = currentSearch.getPreviousVisibleMatchIndex();',

+'					if (previousMatchIndex < currentMatchIndex || confirm("Reached the start of the page. Continue from the bottom?")) {',

+'						setCurrentMatchIndex(previousMatchIndex);',

+'					}',

+'				}',

+'			}',

+'',

+'			function setCurrentMatchIndex(index) {',

+'				currentMatchIndex = index;',

+'				currentSearch.matches[currentMatchIndex].setCurrent();',

+'			}',

+'',

+'			/* ------------------------------------------------------------------------- */',

+'',

+'			// CSS Utilities',

+'',

+'			function addClass(el, cssClass) {',

+'				if (!hasClass(el, cssClass)) {',

+'					if (el.className) {',

+'						el.className += " " + cssClass;',

+'					} else {',

+'						el.className = cssClass;',

+'					}',

+'				}',

+'			}',

+'',

+'			function hasClass(el, cssClass) {',

+'				if (el.className) {',

+'					var classNames = el.className.split(" ");',

+'					return array_contains(classNames, cssClass);',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function removeClass(el, cssClass) {',

+'				if (hasClass(el, cssClass)) {',

+'					// Rebuild the className property',

+'					var existingClasses = el.className.split(" ");',

+'					var newClasses = [];',

+'					for (var i = 0, len = existingClasses.length; i < len; i++) {',

+'						if (existingClasses[i] != cssClass) {',

+'							newClasses[newClasses.length] = existingClasses[i];',

+'						}',

+'					}',

+'					el.className = newClasses.join(" ");',

+'				}',

+'			}',

+'',

+'			function replaceClass(el, newCssClass, oldCssClass) {',

+'				removeClass(el, oldCssClass);',

+'				addClass(el, newCssClass);',

+'			}',

+'',

+'			/* ------------------------------------------------------------------------- */',

+'',

+'			// Other utility functions',

+'',

+'			function getElementsByClass(el, cssClass, tagName) {',

+'				var elements = el.getElementsByTagName(tagName);',

+'				var matches = [];',

+'				for (var i = 0, len = elements.length; i < len; i++) {',

+'					if (hasClass(elements[i], cssClass)) {',

+'						matches.push(elements[i]);',

+'					}',

+'				}',

+'				return matches;',

+'			}',

+'',

+'			// Syntax borrowed from Prototype library',

+'			function $(id) {',

+'				return document.getElementById(id);',

+'			}',

+'',

+'			function isDescendant(node, ancestorNode) {',

+'				while (node != null) {',

+'					if (node === ancestorNode) {',

+'						return true;',

+'					}',

+'					node = node.parentNode;',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function isOrphan(node) {',

+'				var currentNode = node;',

+'				while (currentNode) {',

+'					if (currentNode == document.body) {',

+'						return false;',

+'					}',

+'					currentNode = currentNode.parentNode;',

+'				}',

+'				return true;',

+'			}',

+'',

+'			function escapeHtml(str) {',

+'				return str.replace(/&/g, "&amp;").replace(/[<]/g, "&lt;").replace(/>/g, "&gt;");',

+'			}',

+'',

+'			function getWindowWidth() {',

+'				if (window.innerWidth) {',

+'					return window.innerWidth;',

+'				} else if (document.documentElement && document.documentElement.clientWidth) {',

+'					return document.documentElement.clientWidth;',

+'				} else if (document.body) {',

+'					return document.body.clientWidth;',

+'				}',

+'				return 0;',

+'			}',

+'',

+'			function getWindowHeight() {',

+'				if (window.innerHeight) {',

+'					return window.innerHeight;',

+'				} else if (document.documentElement && document.documentElement.clientHeight) {',

+'					return document.documentElement.clientHeight;',

+'				} else if (document.body) {',

+'					return document.body.clientHeight;',

+'				}',

+'				return 0;',

+'			}',

+'',

+'			function getToolBarsHeight() {',

+'				return $("switches").offsetHeight;',

+'			}',

+'',

+'			function getChromeHeight() {',

+'				var height = getToolBarsHeight();',

+'				if (showCommandLine) {',

+'					height += $("commandLine").offsetHeight;',

+'				}',

+'				return height;',

+'			}',

+'',

+'			function setLogContainerHeight() {',

+'				if (logMainContainer) {',

+'					var windowHeight = getWindowHeight();',

+'					$("body").style.height = getWindowHeight() + "px";',

+'					logMainContainer.style.height = "" +',

+'						Math.max(0, windowHeight - getChromeHeight()) + "px";',

+'				}',

+'			}',

+'',

+'			function setCommandInputWidth() {',

+'				if (showCommandLine) {',

+'					$("command").style.width = "" + Math.max(0, $("commandLineContainer").offsetWidth -',

+'						($("evaluateButton").offsetWidth + 13)) + "px";',

+'				}',

+'			}',

+'',

+'			window.onresize = function() {',

+'				setCommandInputWidth();',

+'				setLogContainerHeight();',

+'			};',

+'',

+'			if (!Array.prototype.push) {',

+'				Array.prototype.push = function() {',

+'			        for (var i = 0, len = arguments.length; i < len; i++){',

+'			            this[this.length] = arguments[i];',

+'			        }',

+'			        return this.length;',

+'				};',

+'			}',

+'',

+'			if (!Array.prototype.pop) {',

+'				Array.prototype.pop = function() {',

+'					if (this.length > 0) {',

+'						var val = this[this.length - 1];',

+'						this.length = this.length - 1;',

+'						return val;',

+'					}',

+'				};',

+'			}',

+'',

+'			if (!Array.prototype.shift) {',

+'				Array.prototype.shift = function() {',

+'					if (this.length > 0) {',

+'						var firstItem = this[0];',

+'						for (var i = 0, len = this.length - 1; i < len; i++) {',

+'							this[i] = this[i + 1];',

+'						}',

+'						this.length = this.length - 1;',

+'						return firstItem;',

+'					}',

+'				};',

+'			}',

+'',

+'			if (!Array.prototype.splice) {',

+'				Array.prototype.splice = function(startIndex, deleteCount) {',

+'					var itemsAfterDeleted = this.slice(startIndex + deleteCount);',

+'					var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);',

+'					this.length = startIndex;',

+'					// Copy the arguments into a proper Array object',

+'					var argumentsArray = [];',

+'					for (var i = 0, len = arguments.length; i < len; i++) {',

+'						argumentsArray[i] = arguments[i];',

+'					}',

+'					var itemsToAppend = (argumentsArray.length > 2) ?',

+'						itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;',

+'					for (i = 0, len = itemsToAppend.length; i < len; i++) {',

+'						this.push(itemsToAppend[i]);',

+'					}',

+'					return itemsDeleted;',

+'				};',

+'			}',

+'',

+'			function array_remove(arr, val) {',

+'				var index = -1;',

+'				for (var i = 0, len = arr.length; i < len; i++) {',

+'					if (arr[i] === val) {',

+'						index = i;',

+'						break;',

+'					}',

+'				}',

+'				if (index >= 0) {',

+'					arr.splice(index, 1);',

+'					return index;',

+'				} else {',

+'					return false;',

+'				}',

+'			}',

+'',

+'			function array_removeFromStart(array, numberToRemove) {',

+'				if (Array.prototype.splice) {',

+'					array.splice(0, numberToRemove);',

+'				} else {',

+'					for (var i = numberToRemove, len = array.length; i < len; i++) {',

+'						array[i - numberToRemove] = array[i];',

+'					}',

+'					array.length = array.length - numberToRemove;',

+'				}',

+'				return array;',

+'			}',

+'',

+'			function array_contains(arr, val) {',

+'				for (var i = 0, len = arr.length; i < len; i++) {',

+'					if (arr[i] == val) {',

+'						return true;',

+'					}',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function getErrorMessage(ex) {',

+'				if (ex.message) {',

+'					return ex.message;',

+'				} else if (ex.description) {',

+'					return ex.description;',

+'				}',

+'				return "" + ex;',

+'			}',

+'',

+'			function moveCaretToEnd(input) {',

+'				if (input.setSelectionRange) {',

+'					input.focus();',

+'					var length = input.value.length;',

+'					input.setSelectionRange(length, length);',

+'				} else if (input.createTextRange) {',

+'					var range = input.createTextRange();',

+'					range.collapse(false);',

+'					range.select();',

+'				}',

+'				input.focus();',

+'			}',

+'',

+'			function stopPropagation(evt) {',

+'				if (evt.stopPropagation) {',

+'					evt.stopPropagation();',

+'				} else if (typeof evt.cancelBubble != "undefined") {',

+'					evt.cancelBubble = true;',

+'				}',

+'			}',

+'',

+'			function getEvent(evt) {',

+'				return evt ? evt : event;',

+'			}',

+'',

+'			function getTarget(evt) {',

+'				return evt.target ? evt.target : evt.srcElement;',

+'			}',

+'',

+'			function getRelatedTarget(evt) {',

+'				if (evt.relatedTarget) {',

+'					return evt.relatedTarget;',

+'				} else if (evt.srcElement) {',

+'					switch(evt.type) {',

+'						case "mouseover":',

+'							return evt.fromElement;',

+'						case "mouseout":',

+'							return evt.toElement;',

+'						default:',

+'							return evt.srcElement;',

+'					}',

+'				}',

+'			}',

+'',

+'			function cancelKeyEvent(evt) {',

+'				evt.returnValue = false;',

+'				stopPropagation(evt);',

+'			}',

+'',

+'			function evalCommandLine() {',

+'				var expr = $("command").value;',

+'				evalCommand(expr);',

+'				$("command").value = "";',

+'			}',

+'',

+'			function evalLastCommand() {',

+'				if (lastCommand != null) {',

+'					evalCommand(lastCommand);',

+'				}',

+'			}',

+'',

+'			var lastCommand = null;',

+'			var commandHistory = [];',

+'			var currentCommandIndex = 0;',

+'',

+'			function evalCommand(expr) {',

+'				if (appender) {',

+'					appender.evalCommandAndAppend(expr);',

+'				} else {',

+'					var prefix = ">>> " + expr + "\\r\\n";',

+'					try {',

+'						log("INFO", prefix + eval(expr));',

+'					} catch (ex) {',

+'						log("ERROR", prefix + "Error: " + getErrorMessage(ex));',

+'					}',

+'				}',

+'				// Update command history',

+'				if (expr != commandHistory[commandHistory.length - 1]) {',

+'					commandHistory.push(expr);',

+'					// Update the appender',

+'					if (appender) {',

+'						appender.storeCommandHistory(commandHistory);',

+'					}',

+'				}',

+'				currentCommandIndex = (expr == commandHistory[currentCommandIndex]) ? currentCommandIndex + 1 : commandHistory.length;',

+'				lastCommand = expr;',

+'			}',

+'			//]]>',

+'		</script>',

+'		<style type="text/css">',

+'			body {',

+'				background-color: white;',

+'				color: black;',

+'				padding: 0;',

+'				margin: 0;',

+'				font-family: tahoma, verdana, arial, helvetica, sans-serif;',

+'				overflow: hidden;',

+'			}',

+'',

+'			div#switchesContainer input {',

+'				margin-bottom: 0;',

+'			}',

+'',

+'			div.toolbar {',

+'				border-top: solid #ffffff 1px;',

+'				border-bottom: solid #aca899 1px;',

+'				background-color: #f1efe7;',

+'				padding: 3px 5px;',

+'				font-size: 68.75%;',

+'			}',

+'',

+'			div.toolbar, div#search input {',

+'				font-family: tahoma, verdana, arial, helvetica, sans-serif;',

+'			}',

+'',

+'			div.toolbar input.button {',

+'				padding: 0 5px;',

+'				font-size: 100%;',

+'			}',

+'',

+'			div.toolbar input.hidden {',

+'				display: none;',

+'			}',

+'',

+'			div#switches input#clearButton {',

+'				margin-left: 20px;',

+'			}',

+'',

+'			div#levels label {',

+'				font-weight: bold;',

+'			}',

+'',

+'			div#levels label, div#options label {',

+'				margin-right: 5px;',

+'			}',

+'',

+'			div#levels label#wrapLabel {',

+'				font-weight: normal;',

+'			}',

+'',

+'			div#search label {',

+'				margin-right: 10px;',

+'			}',

+'',

+'			div#search label.searchboxlabel {',

+'				margin-right: 0;',

+'			}',

+'',

+'			div#search input {',

+'				font-size: 100%;',

+'			}',

+'',

+'			div#search input.validregex {',

+'				color: green;',

+'			}',

+'',

+'			div#search input.invalidregex {',

+'				color: red;',

+'			}',

+'',

+'			div#search input.nomatches {',

+'				color: white;',

+'				background-color: #ff6666;',

+'			}',

+'',

+'			div#search input.nomatches {',

+'				color: white;',

+'				background-color: #ff6666;',

+'			}',

+'',

+'			div#searchNav {',

+'				display: none;',

+'			}',

+'',

+'			div#commandLine {',

+'				display: none;',

+'			}',

+'',

+'			div#commandLine input#command {',

+'				font-size: 100%;',

+'				font-family: Courier New, Courier;',

+'			}',

+'',

+'			div#commandLine input#evaluateButton {',

+'			}',

+'',

+'			*.greyedout {',

+'				color: gray !important;',

+'				border-color: gray !important;',

+'			}',

+'',

+'			*.greyedout *.alwaysenabled { color: black; }',

+'',

+'			*.unselectable {',

+'				-khtml-user-select: none;',

+'				-moz-user-select: none;',

+'				user-select: none;',

+'			}',

+'',

+'			div#log {',

+'				font-family: Courier New, Courier;',

+'				font-size: 75%;',

+'				width: 100%;',

+'				overflow: auto;',

+'				clear: both;',

+'				position: relative;',

+'			}',

+'',

+'			div.group {',

+'				border-color: #cccccc;',

+'				border-style: solid;',

+'				border-width: 1px 0 1px 1px;',

+'				overflow: visible;',

+'			}',

+'',

+'			div.oldIe div.group, div.oldIe div.group *, div.oldIe *.logentry {',

+'				height: 1%;',

+'			}',

+'',

+'			div.group div.groupheading span.expander {',

+'				border: solid black 1px;',

+'				font-family: Courier New, Courier;',

+'				font-size: 0.833em;',

+'				background-color: #eeeeee;',

+'				position: relative;',

+'				top: -1px;',

+'				color: black;',

+'				padding: 0 2px;',

+'				cursor: pointer;',

+'				cursor: hand;',

+'				height: 1%;',

+'			}',

+'',

+'			div.group div.groupcontent {',

+'				margin-left: 10px;',

+'				padding-bottom: 2px;',

+'				overflow: visible;',

+'			}',

+'',

+'			div.group div.expanded {',

+'				display: block;',

+'			}',

+'',

+'			div.group div.collapsed {',

+'				display: none;',

+'			}',

+'',

+'			*.logentry {',

+'				overflow: visible;',

+'				display: none;',

+'				white-space: pre;',

+'			}',

+'',

+'			span.pre {',

+'				white-space: pre;',

+'			}',

+'			',

+'			pre.unwrapped {',

+'				display: inline !important;',

+'			}',

+'',

+'			pre.unwrapped pre.pre, div.wrapped pre.pre {',

+'				display: inline;',

+'			}',

+'',

+'			div.wrapped pre.pre {',

+'				white-space: normal;',

+'			}',

+'',

+'			div.wrapped {',

+'				display: none;',

+'			}',

+'',

+'			body.searching *.logentry span.currentmatch {',

+'				color: white !important;',

+'				background-color: green !important;',

+'			}',

+'',

+'			body.searching div.searchhighlight *.logentry span.searchterm {',

+'				color: black;',

+'				background-color: yellow;',

+'			}',

+'',

+'			div.wrap *.logentry {',

+'				white-space: normal !important;',

+'				border-width: 0 0 1px 0;',

+'				border-color: #dddddd;',

+'				border-style: dotted;',

+'			}',

+'',

+'			div.wrap #log_wrapped, #log_unwrapped {',

+'				display: block;',

+'			}',

+'',

+'			div.wrap #log_unwrapped, #log_wrapped {',

+'				display: none;',

+'			}',

+'',

+'			div.wrap *.logentry span.pre {',

+'				overflow: visible;',

+'				white-space: normal;',

+'			}',

+'',

+'			div.wrap *.logentry pre.unwrapped {',

+'				display: none;',

+'			}',

+'',

+'			div.wrap *.logentry span.wrapped {',

+'				display: inline;',

+'			}',

+'',

+'			div.searchfilter *.searchnonmatch {',

+'				display: none !important;',

+'			}',

+'',

+'			div#log *.TRACE, label#label_TRACE {',

+'				color: #666666;',

+'			}',

+'',

+'			div#log *.DEBUG, label#label_DEBUG {',

+'				color: green;',

+'			}',

+'',

+'			div#log *.INFO, label#label_INFO {',

+'				color: #000099;',

+'			}',

+'',

+'			div#log *.WARN, label#label_WARN {',

+'				color: #999900;',

+'			}',

+'',

+'			div#log *.ERROR, label#label_ERROR {',

+'				color: red;',

+'			}',

+'',

+'			div#log *.FATAL, label#label_FATAL {',

+'				color: #660066;',

+'			}',

+'',

+'			div.TRACE#log *.TRACE,',

+'			div.DEBUG#log *.DEBUG,',

+'			div.INFO#log *.INFO,',

+'			div.WARN#log *.WARN,',

+'			div.ERROR#log *.ERROR,',

+'			div.FATAL#log *.FATAL {',

+'				display: block;',

+'			}',

+'',

+'			div#log div.separator {',

+'				background-color: #cccccc;',

+'				margin: 5px 0;',

+'				line-height: 1px;',

+'			}',

+'		</style>',

+'	</head>',

+'',

+'	<body id="body">',

+'		<div id="switchesContainer">',

+'			<div id="switches">',

+'				<div id="levels" class="toolbar">',

+'					Filters:',

+'					<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>',

+'					<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>',

+'					<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>',

+'					<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>',

+'					<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>',

+'					<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>',

+'					<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>',

+'				</div>',

+'				<div id="search" class="toolbar">',

+'					<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />',

+'					<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />',

+'					<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>',

+'					<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>',

+'					<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>',

+'					<div id="searchNav">',

+'						<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />',

+'						<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />',

+'						<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>',

+'						<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>',

+'					</div>',

+'				</div>',

+'				<div id="options" class="toolbar">',

+'					Options:',

+'					<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>',

+'					<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>',

+'					<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>',

+'					<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>',

+'					<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />',

+'					<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />',

+'					<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />',

+'				</div>',

+'			</div>',

+'		</div>',

+'		<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>',

+'		<div id="commandLine" class="toolbar">',

+'			<div id="commandLineContainer">',

+'				<input type="text" id="command" title="Enter a JavaScript command here and hit return or press \'Evaluate\'" />',

+'				<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />',

+'			</div>',

+'		</div>',

+'	</body>',

+'</html>',

+''

+];

+		};

+

+		var defaultCommandLineFunctions = [];

+

+		ConsoleAppender = function() {};

+

+		var consoleAppenderIdCounter = 1;

+		ConsoleAppender.prototype = new Appender();

+

+		ConsoleAppender.prototype.create = function(inPage, container,

+				lazyInit, initiallyMinimized, useDocumentWrite, width, height, focusConsoleWindow) {

+			var appender = this;

+

+			// Common properties

+			var initialized = false;

+			var consoleWindowCreated = false;

+			var consoleWindowLoaded = false;

+			var consoleClosed = false;

+

+			var queuedLoggingEvents = [];

+			var isSupported = true;

+			var consoleAppenderId = consoleAppenderIdCounter++;

+

+			// Local variables

+			initiallyMinimized = extractBooleanFromParam(initiallyMinimized, this.defaults.initiallyMinimized);

+			lazyInit = extractBooleanFromParam(lazyInit, this.defaults.lazyInit);

+			useDocumentWrite = extractBooleanFromParam(useDocumentWrite, this.defaults.useDocumentWrite);

+			var newestMessageAtTop = this.defaults.newestMessageAtTop;

+			var scrollToLatestMessage = this.defaults.scrollToLatestMessage;

+			width = width ? width : this.defaults.width;

+			height = height ? height : this.defaults.height;

+			var maxMessages = this.defaults.maxMessages;

+			var showCommandLine = this.defaults.showCommandLine;

+			var commandLineObjectExpansionDepth = this.defaults.commandLineObjectExpansionDepth;

+			var showHideButton = this.defaults.showHideButton;

+            var showCloseButton = this.defaults.showCloseButton;

+            var showLogEntryDeleteButtons = this.defaults.showLogEntryDeleteButtons;

+

+			this.setLayout(this.defaults.layout);

+

+			// Functions whose implementations vary between subclasses

+			var init, createWindow, safeToAppend, getConsoleWindow, open;

+

+			// Configuration methods. The function scope is used to prevent

+			// direct alteration to the appender configuration properties.

+			var appenderName = inPage ? "InPageAppender" : "PopUpAppender";

+			var checkCanConfigure = function(configOptionName) {

+				if (consoleWindowCreated) {

+					handleError(appenderName + ": configuration option '" + configOptionName + "' may not be set after the appender has been initialized");

+					return false;

+				}

+				return true;

+			};

+

+			var consoleWindowExists = function() {

+				return (consoleWindowLoaded && isSupported && !consoleClosed);

+			};

+

+			this.isNewestMessageAtTop = function() { return newestMessageAtTop; };

+			this.setNewestMessageAtTop = function(newestMessageAtTopParam) {

+				newestMessageAtTop = bool(newestMessageAtTopParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setNewestAtTop(newestMessageAtTop);

+				}

+			};

+

+			this.isScrollToLatestMessage = function() { return scrollToLatestMessage; };

+			this.setScrollToLatestMessage = function(scrollToLatestMessageParam) {

+				scrollToLatestMessage = bool(scrollToLatestMessageParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setScrollToLatest(scrollToLatestMessage);

+				}

+			};

+

+			this.getWidth = function() { return width; };

+			this.setWidth = function(widthParam) {

+				if (checkCanConfigure("width")) {

+					width = extractStringFromParam(widthParam, width);

+				}

+			};

+

+			this.getHeight = function() { return height; };

+			this.setHeight = function(heightParam) {

+				if (checkCanConfigure("height")) {

+					height = extractStringFromParam(heightParam, height);

+				}

+			};

+

+			this.getMaxMessages = function() { return maxMessages; };

+			this.setMaxMessages = function(maxMessagesParam) {

+				maxMessages = extractIntFromParam(maxMessagesParam, maxMessages);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setMaxMessages(maxMessages);

+				}

+			};

+

+			this.isShowCommandLine = function() { return showCommandLine; };

+			this.setShowCommandLine = function(showCommandLineParam) {

+				showCommandLine = bool(showCommandLineParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setShowCommandLine(showCommandLine);

+				}

+			};

+

+			this.isShowHideButton = function() { return showHideButton; };

+			this.setShowHideButton = function(showHideButtonParam) {

+				showHideButton = bool(showHideButtonParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setShowHideButton(showHideButton);

+				}

+			};

+

+			this.isShowCloseButton = function() { return showCloseButton; };

+			this.setShowCloseButton = function(showCloseButtonParam) {

+				showCloseButton = bool(showCloseButtonParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setShowCloseButton(showCloseButton);

+				}

+			};

+

+			this.getCommandLineObjectExpansionDepth = function() { return commandLineObjectExpansionDepth; };

+			this.setCommandLineObjectExpansionDepth = function(commandLineObjectExpansionDepthParam) {

+				commandLineObjectExpansionDepth = extractIntFromParam(commandLineObjectExpansionDepthParam, commandLineObjectExpansionDepth);

+			};

+

+			var minimized = initiallyMinimized;

+			this.isInitiallyMinimized = function() { return initiallyMinimized; };

+			this.setInitiallyMinimized = function(initiallyMinimizedParam) {

+				if (checkCanConfigure("initiallyMinimized")) {

+					initiallyMinimized = bool(initiallyMinimizedParam);

+					minimized = initiallyMinimized;

+				}

+			};

+

+			this.isUseDocumentWrite = function() { return useDocumentWrite; };

+			this.setUseDocumentWrite = function(useDocumentWriteParam) {

+				if (checkCanConfigure("useDocumentWrite")) {

+					useDocumentWrite = bool(useDocumentWriteParam);

+				}

+			};

+

+			// Common methods

+			function QueuedLoggingEvent(loggingEvent, formattedMessage) {

+				this.loggingEvent = loggingEvent;

+				this.levelName = loggingEvent.level.name;

+				this.formattedMessage = formattedMessage;

+			}

+

+			QueuedLoggingEvent.prototype.append = function() {

+				getConsoleWindow().log(this.levelName, this.formattedMessage);

+			};

+

+			function QueuedGroup(name, initiallyExpanded) {

+				this.name = name;

+				this.initiallyExpanded = initiallyExpanded;

+			}

+

+			QueuedGroup.prototype.append = function() {

+				getConsoleWindow().group(this.name, this.initiallyExpanded);

+			};

+

+			function QueuedGroupEnd() {}

+

+			QueuedGroupEnd.prototype.append = function() {

+				getConsoleWindow().groupEnd();

+			};

+

+			var checkAndAppend = function() {

+				// Next line forces a check of whether the window has been closed

+				safeToAppend();

+				if (!initialized) {

+					init();

+				} else if (consoleClosed && reopenWhenClosed) {

+					createWindow();

+				}

+				if (safeToAppend()) {

+					appendQueuedLoggingEvents();

+				}

+			};

+

+			this.append = function(loggingEvent) {

+				if (isSupported) {

+					// Format the message

+					var formattedMessage = appender.getLayout().format(loggingEvent);

+					if (this.getLayout().ignoresThrowable()) {

+						formattedMessage += loggingEvent.getThrowableStrRep();

+					}

+					queuedLoggingEvents.push(new QueuedLoggingEvent(loggingEvent, formattedMessage));

+					checkAndAppend();

+				}

+			};

+

+            this.group = function(name, initiallyExpanded) {

+				if (isSupported) {

+					queuedLoggingEvents.push(new QueuedGroup(name, initiallyExpanded));

+					checkAndAppend();

+				}

+			};

+

+            this.groupEnd = function() {

+				if (isSupported) {

+					queuedLoggingEvents.push(new QueuedGroupEnd());

+					checkAndAppend();

+				}

+			};

+

+			var appendQueuedLoggingEvents = function() {

+				var currentLoggingEvent;

+				while (queuedLoggingEvents.length > 0) {

+					queuedLoggingEvents.shift().append();

+				}

+				if (focusConsoleWindow) {

+					getConsoleWindow().focus();

+				}

+			};

+

+			this.setAddedToLogger = function(logger) {

+				this.loggers.push(logger);

+				if (enabled && !lazyInit) {

+					init();

+				}

+			};

+

+			this.clear = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().clearLog();

+				}

+				queuedLoggingEvents.length = 0;

+			};

+

+			this.focus = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().focus();

+				}

+			};

+

+			this.focusCommandLine = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().focusCommandLine();

+				}

+			};

+

+			this.focusSearch = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().focusSearch();

+				}

+			};

+

+			var commandWindow = window;

+

+			this.getCommandWindow = function() { return commandWindow; };

+			this.setCommandWindow = function(commandWindowParam) {

+				commandWindow = commandWindowParam;

+			};

+

+			this.executeLastCommand = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().evalLastCommand();

+				}

+			};

+

+			var commandLayout = new PatternLayout("%m");

+			this.getCommandLayout = function() { return commandLayout; };

+			this.setCommandLayout = function(commandLayoutParam) {

+				commandLayout = commandLayoutParam;

+			};

+

+			this.evalCommandAndAppend = function(expr) {

+				var commandReturnValue = { appendResult: true, isError: false };

+				var commandOutput = "";

+				// Evaluate the command

+				try {

+					var result, i;

+					// The next three lines constitute a workaround for IE. Bizarrely, iframes seem to have no

+					// eval method on the window object initially, but once execScript has been called on

+					// it once then the eval method magically appears. See http://www.thismuchiknow.co.uk/?p=25

+					if (!commandWindow.eval && commandWindow.execScript) {

+						commandWindow.execScript("null");

+					}

+

+					var commandLineFunctionsHash = {};

+					for (i = 0, len = commandLineFunctions.length; i < len; i++) {

+						commandLineFunctionsHash[commandLineFunctions[i][0]] = commandLineFunctions[i][1];

+					}

+

+					// Keep an array of variables that are being changed in the command window so that they

+					// can be restored to their original values afterwards

+					var objectsToRestore = [];

+					var addObjectToRestore = function(name) {

+						objectsToRestore.push([name, commandWindow[name]]);

+					};

+

+					addObjectToRestore("appender");

+					commandWindow.appender = appender;

+

+					addObjectToRestore("commandReturnValue");

+					commandWindow.commandReturnValue = commandReturnValue;

+

+					addObjectToRestore("commandLineFunctionsHash");

+					commandWindow.commandLineFunctionsHash = commandLineFunctionsHash;

+

+					var addFunctionToWindow = function(name) {

+						addObjectToRestore(name);

+						commandWindow[name] = function() {

+							return this.commandLineFunctionsHash[name](appender, arguments, commandReturnValue);

+						};

+					};

+

+					for (i = 0, len = commandLineFunctions.length; i < len; i++) {

+						addFunctionToWindow(commandLineFunctions[i][0]);

+					}

+

+					// Another bizarre workaround to get IE to eval in the global scope

+					if (commandWindow === window && commandWindow.execScript) {

+						addObjectToRestore("evalExpr");

+						addObjectToRestore("result");

+						window.evalExpr = expr;

+						commandWindow.execScript("window.result=eval(window.evalExpr);");

+						result = window.result;

+ 					} else {

+ 						result = commandWindow.eval(expr);

+ 					}

+					commandOutput = isUndefined(result) ? result : formatObjectExpansion(result, commandLineObjectExpansionDepth);

+

+					// Restore variables in the command window to their original state

+					for (i = 0, len = objectsToRestore.length; i < len; i++) {

+						commandWindow[objectsToRestore[i][0]] = objectsToRestore[i][1];

+					}

+				} catch (ex) {

+					commandOutput = "Error evaluating command: " + getExceptionStringRep(ex);

+					commandReturnValue.isError = true;

+				}

+				// Append command output

+				if (commandReturnValue.appendResult) {

+					var message = ">>> " + expr;

+					if (!isUndefined(commandOutput)) {

+						message += newLine + commandOutput;

+					}

+					var level = commandReturnValue.isError ? Level.ERROR : Level.INFO;

+					var loggingEvent = new LoggingEvent(null, new Date(), level, [message], null);

+					var mainLayout = this.getLayout();

+					this.setLayout(commandLayout);

+					this.append(loggingEvent);

+					this.setLayout(mainLayout);

+				}

+			};

+

+			var commandLineFunctions = defaultCommandLineFunctions.concat([]);

+

+			this.addCommandLineFunction = function(functionName, commandLineFunction) {

+				commandLineFunctions.push([functionName, commandLineFunction]);

+			};

+

+			var commandHistoryCookieName = "log4javascriptCommandHistory";

+			this.storeCommandHistory = function(commandHistory) {

+				setCookie(commandHistoryCookieName, commandHistory.join(","));

+			};

+

+			var writeHtml = function(doc) {

+				var lines = getConsoleHtmlLines();

+				doc.open();

+				for (var i = 0, len = lines.length; i < len; i++) {

+					doc.writeln(lines[i]);

+				}

+				doc.close();

+			};

+

+			// Set up event listeners

+			this.setEventTypes(["load", "unload"]);

+

+			var consoleWindowLoadHandler = function() {

+				var win = getConsoleWindow();

+				win.setAppender(appender);

+				win.setNewestAtTop(newestMessageAtTop);

+				win.setScrollToLatest(scrollToLatestMessage);

+				win.setMaxMessages(maxMessages);

+				win.setShowCommandLine(showCommandLine);

+				win.setShowHideButton(showHideButton);

+				win.setShowCloseButton(showCloseButton);

+				win.setMainWindow(window);

+

+				// Restore command history stored in cookie

+				var storedValue = getCookie(commandHistoryCookieName);

+				if (storedValue) {

+					win.commandHistory = storedValue.split(",");

+					win.currentCommandIndex = win.commandHistory.length;

+				}

+

+				appender.dispatchEvent("load", { "win" : win });

+			};

+

+			this.unload = function() {

+				logLog.debug("unload " + this + ", caller: " + this.unload.caller);

+				if (!consoleClosed) {

+					logLog.debug("really doing unload " + this);

+					consoleClosed = true;

+					consoleWindowLoaded = false;

+					consoleWindowCreated = false;

+					appender.dispatchEvent("unload", {});

+				}

+			};

+

+			var pollConsoleWindow = function(windowTest, interval, successCallback, errorMessage) {

+				function doPoll() {

+					try {

+						// Test if the console has been closed while polling

+						if (consoleClosed) {

+							clearInterval(poll);

+						}

+						if (windowTest(getConsoleWindow())) {

+							clearInterval(poll);

+							successCallback();

+						}

+					} catch (ex) {

+						clearInterval(poll);

+						isSupported = false;

+						handleError(errorMessage, ex);

+					}

+				}

+

+				// Poll the pop-up since the onload event is not reliable

+				var poll = setInterval(doPoll, interval);

+			};

+

+			var getConsoleUrl = function() {

+				var documentDomainSet = (document.domain != location.hostname);

+				return useDocumentWrite ? "" : getBaseUrl() + "console_uncompressed.html" +

+											   (documentDomainSet ? "?log4javascript_domain=" + escape(document.domain) : "");

+			};

+

+			// Define methods and properties that vary between subclasses

+			if (inPage) {

+				// InPageAppender

+

+				var containerElement = null;

+

+				// Configuration methods. The function scope is used to prevent

+				// direct alteration to the appender configuration properties.

+				var cssProperties = [];

+				this.addCssProperty = function(name, value) {

+					if (checkCanConfigure("cssProperties")) {

+						cssProperties.push([name, value]);

+					}

+				};

+

+				// Define useful variables

+				var windowCreationStarted = false;

+				var iframeContainerDiv;

+				var iframeId = uniqueId + "_InPageAppender_" + consoleAppenderId;

+

+				this.hide = function() {

+					if (initialized && consoleWindowCreated) {

+						if (consoleWindowExists()) {

+							getConsoleWindow().$("command").blur();

+						}

+						iframeContainerDiv.style.display = "none";

+						minimized = true;

+					}

+				};

+

+				this.show = function() {

+					if (initialized) {

+						if (consoleWindowCreated) {

+							iframeContainerDiv.style.display = "block";

+							this.setShowCommandLine(showCommandLine); // Force IE to update

+							minimized = false;

+						} else if (!windowCreationStarted) {

+							createWindow(true);

+						}

+					}

+				};

+

+				this.isVisible = function() {

+					return !minimized && !consoleClosed;

+				};

+

+				this.close = function(fromButton) {

+					if (!consoleClosed && (!fromButton || confirm("This will permanently remove the console from the page. No more messages will be logged. Do you wish to continue?"))) {

+						iframeContainerDiv.parentNode.removeChild(iframeContainerDiv);

+						this.unload();

+					}

+				};

+

+				// Create open, init, getConsoleWindow and safeToAppend functions

+				open = function() {

+					var initErrorMessage = "InPageAppender.open: unable to create console iframe";

+

+					function finalInit() {

+						try {

+							if (!initiallyMinimized) {

+								appender.show();

+							}

+							consoleWindowLoadHandler();

+							consoleWindowLoaded = true;

+							appendQueuedLoggingEvents();

+						} catch (ex) {

+							isSupported = false;

+							handleError(initErrorMessage, ex);

+						}

+					}

+

+					function writeToDocument() {

+						try {

+							var windowTest = function(win) { return isLoaded(win); };

+							if (useDocumentWrite) {

+								writeHtml(getConsoleWindow().document);

+							}

+							if (windowTest(getConsoleWindow())) {

+								finalInit();

+							} else {

+								pollConsoleWindow(windowTest, 100, finalInit, initErrorMessage);

+							}

+						} catch (ex) {

+							isSupported = false;

+							handleError(initErrorMessage, ex);

+						}

+					}

+

+					minimized = false;

+					iframeContainerDiv = containerElement.appendChild(document.createElement("div"));

+

+					iframeContainerDiv.style.width = width;

+					iframeContainerDiv.style.height = height;

+					iframeContainerDiv.style.border = "solid gray 1px";

+

+					for (var i = 0, len = cssProperties.length; i < len; i++) {

+						iframeContainerDiv.style[cssProperties[i][0]] = cssProperties[i][1];

+					}

+

+					var iframeSrc = useDocumentWrite ? "" : " src='" + getConsoleUrl() + "'";

+

+					// Adding an iframe using the DOM would be preferable, but it doesn't work

+					// in IE5 on Windows, or in Konqueror prior to version 3.5 - in Konqueror

+					// it creates the iframe fine but I haven't been able to find a way to obtain

+					// the iframe's window object

+					iframeContainerDiv.innerHTML = "<iframe id='" + iframeId + "' name='" + iframeId +

+						"' width='100%' height='100%' frameborder='0'" + iframeSrc +

+						" scrolling='no'></iframe>";

+					consoleClosed = false;

+

+					// Write the console HTML to the iframe

+					var iframeDocumentExistsTest = function(win) {

+						try {

+							return bool(win) && bool(win.document);

+						} catch (ex) {

+							return false;

+						}

+					};

+					if (iframeDocumentExistsTest(getConsoleWindow())) {

+						writeToDocument();

+					} else {

+						pollConsoleWindow(iframeDocumentExistsTest, 100, writeToDocument, initErrorMessage);

+					}

+					consoleWindowCreated = true;

+				};

+

+				createWindow = function(show) {

+					if (show || !initiallyMinimized) {

+						var pageLoadHandler = function() {

+							if (!container) {

+								// Set up default container element

+								containerElement = document.createElement("div");

+								containerElement.style.position = "fixed";

+								containerElement.style.left = "0";

+								containerElement.style.right = "0";

+								containerElement.style.bottom = "0";

+								document.body.appendChild(containerElement);

+								appender.addCssProperty("borderWidth", "1px 0 0 0");

+								appender.addCssProperty("zIndex", 1000000); // Can't find anything authoritative that says how big z-index can be

+								open();

+							} else {

+								try {

+									var el = document.getElementById(container);

+									if (el.nodeType == 1) {

+										containerElement = el;

+									}

+									open();

+								} catch (ex) {

+									handleError("InPageAppender.init: invalid container element '" + container + "' supplied", ex);

+								}

+							}

+						};

+

+						// Test the type of the container supplied. First, check if it's an element

+						if (pageLoaded && container && container.appendChild) {

+							containerElement = container;

+							open();

+						} else if (pageLoaded) {

+							pageLoadHandler();

+						} else {

+							log4javascript.addEventListener("load", pageLoadHandler);

+						}

+						windowCreationStarted = true;

+					}

+				};

+

+				init = function() {

+					createWindow();

+					initialized = true;

+				};

+

+				getConsoleWindow = function() {

+					var iframe = window.frames[iframeId];

+					if (iframe) {

+						return iframe;

+					}

+				};

+

+				safeToAppend = function() {

+					if (isSupported && !consoleClosed) {

+						if (consoleWindowCreated && !consoleWindowLoaded && getConsoleWindow() && isLoaded(getConsoleWindow())) {

+							consoleWindowLoaded = true;

+						}

+						return consoleWindowLoaded;

+					}

+					return false;

+				};

+			} else {

+				// PopUpAppender

+

+				// Extract params

+				var useOldPopUp = appender.defaults.useOldPopUp;

+				var complainAboutPopUpBlocking = appender.defaults.complainAboutPopUpBlocking;

+				var reopenWhenClosed = this.defaults.reopenWhenClosed;

+

+				// Configuration methods. The function scope is used to prevent

+				// direct alteration to the appender configuration properties.

+				this.isUseOldPopUp = function() { return useOldPopUp; };

+				this.setUseOldPopUp = function(useOldPopUpParam) {

+					if (checkCanConfigure("useOldPopUp")) {

+						useOldPopUp = bool(useOldPopUpParam);

+					}

+				};

+

+				this.isComplainAboutPopUpBlocking = function() { return complainAboutPopUpBlocking; };

+				this.setComplainAboutPopUpBlocking = function(complainAboutPopUpBlockingParam) {

+					if (checkCanConfigure("complainAboutPopUpBlocking")) {

+						complainAboutPopUpBlocking = bool(complainAboutPopUpBlockingParam);

+					}

+				};

+

+				this.isFocusPopUp = function() { return focusConsoleWindow; };

+				this.setFocusPopUp = function(focusPopUpParam) {

+					// This property can be safely altered after logging has started

+					focusConsoleWindow = bool(focusPopUpParam);

+				};

+

+				this.isReopenWhenClosed = function() { return reopenWhenClosed; };

+				this.setReopenWhenClosed = function(reopenWhenClosedParam) {

+					// This property can be safely altered after logging has started

+					reopenWhenClosed = bool(reopenWhenClosedParam);

+				};

+

+				this.close = function() {

+					logLog.debug("close " + this);

+					try {

+						popUp.close();

+						this.unload();

+					} catch (ex) {

+						// Do nothing

+					}

+				};

+

+				this.hide = function() {

+					logLog.debug("hide " + this);

+					if (consoleWindowExists()) {

+						this.close();

+					}

+				};

+

+				this.show = function() {

+					logLog.debug("show " + this);

+					if (!consoleWindowCreated) {

+						open();

+					}

+				};

+

+				this.isVisible = function() {

+					return safeToAppend();

+				};

+

+				// Define useful variables

+				var popUp;

+

+				// Create open, init, getConsoleWindow and safeToAppend functions

+				open = function() {

+					var windowProperties = "width=" + width + ",height=" + height + ",status,resizable";

+					var frameInfo = "";

+					try {

+						var frameEl = window.frameElement;

+						if (frameEl) {

+							frameInfo = "_" + frameEl.tagName + "_" + (frameEl.name || frameEl.id || "");

+						}

+					} catch (e) {

+						frameInfo = "_inaccessibleParentFrame";

+					}

+					var windowName = "PopUp_" + location.host.replace(/[^a-z0-9]/gi, "_") + "_" + consoleAppenderId + frameInfo;

+					if (!useOldPopUp || !useDocumentWrite) {

+						// Ensure a previous window isn't used by using a unique name

+						windowName = windowName + "_" + uniqueId;

+					}

+

+					var checkPopUpClosed = function(win) {

+						if (consoleClosed) {

+							return true;

+						} else {

+							try {

+								return bool(win) && win.closed;

+							} catch(ex) {}

+						}

+						return false;

+					};

+

+					var popUpClosedCallback = function() {

+						if (!consoleClosed) {

+							appender.unload();

+						}

+					};

+

+					function finalInit() {

+						getConsoleWindow().setCloseIfOpenerCloses(!useOldPopUp || !useDocumentWrite);

+						consoleWindowLoadHandler();

+						consoleWindowLoaded = true;

+						appendQueuedLoggingEvents();

+						pollConsoleWindow(checkPopUpClosed, 500, popUpClosedCallback,

+								"PopUpAppender.checkPopUpClosed: error checking pop-up window");

+					}

+

+					try {

+						popUp = window.open(getConsoleUrl(), windowName, windowProperties);

+						consoleClosed = false;

+						consoleWindowCreated = true;

+						if (popUp && popUp.document) {

+							if (useDocumentWrite && useOldPopUp && isLoaded(popUp)) {

+								popUp.mainPageReloaded();

+								finalInit();

+							} else {

+								if (useDocumentWrite) {

+									writeHtml(popUp.document);

+								}

+								// Check if the pop-up window object is available

+								var popUpLoadedTest = function(win) { return bool(win) && isLoaded(win); };

+								if (isLoaded(popUp)) {

+									finalInit();

+								} else {

+									pollConsoleWindow(popUpLoadedTest, 100, finalInit,

+											"PopUpAppender.init: unable to create console window");

+								}

+							}

+						} else {

+							isSupported = false;

+							logLog.warn("PopUpAppender.init: pop-ups blocked, please unblock to use PopUpAppender");

+							if (complainAboutPopUpBlocking) {

+								handleError("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");

+							}

+						}

+					} catch (ex) {

+						handleError("PopUpAppender.init: error creating pop-up", ex);

+					}

+				};

+

+				createWindow = function() {

+					if (!initiallyMinimized) {

+						open();

+					}

+				};

+

+				init = function() {

+					createWindow();

+					initialized = true;

+				};

+

+				getConsoleWindow = function() {

+					return popUp;

+				};

+

+				safeToAppend = function() {

+					if (isSupported && !isUndefined(popUp) && !consoleClosed) {

+						if (popUp.closed ||

+								(consoleWindowLoaded && isUndefined(popUp.closed))) { // Extra check for Opera

+							appender.unload();

+							logLog.debug("PopUpAppender: pop-up closed");

+							return false;

+						}

+						if (!consoleWindowLoaded && isLoaded(popUp)) {

+							consoleWindowLoaded = true;

+						}

+					}

+					return isSupported && consoleWindowLoaded && !consoleClosed;

+				};

+			}

+

+			// Expose getConsoleWindow so that automated tests can check the DOM

+			this.getConsoleWindow = getConsoleWindow;

+		};

+

+		ConsoleAppender.addGlobalCommandLineFunction = function(functionName, commandLineFunction) {

+			defaultCommandLineFunctions.push([functionName, commandLineFunction]);

+		};

+

+		/* ------------------------------------------------------------------ */

+

+		function PopUpAppender(lazyInit, initiallyMinimized, useDocumentWrite,

+							   width, height) {

+			this.create(false, null, lazyInit, initiallyMinimized,

+					useDocumentWrite, width, height, this.defaults.focusPopUp);

+		}

+

+		PopUpAppender.prototype = new ConsoleAppender();

+

+		PopUpAppender.prototype.defaults = {

+			layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),

+			initiallyMinimized: false,

+			focusPopUp: false,

+			lazyInit: true,

+			useOldPopUp: true,

+			complainAboutPopUpBlocking: true,

+			newestMessageAtTop: false,

+			scrollToLatestMessage: true,

+			width: "600",

+			height: "400",

+			reopenWhenClosed: false,

+			maxMessages: null,

+			showCommandLine: true,

+			commandLineObjectExpansionDepth: 1,

+			showHideButton: false,

+			showCloseButton: true,

+            showLogEntryDeleteButtons: true,

+            useDocumentWrite: true

+		};

+

+		PopUpAppender.prototype.toString = function() {

+			return "PopUpAppender";

+		};

+

+		log4javascript.PopUpAppender = PopUpAppender;

+

+		/* ------------------------------------------------------------------ */

+

+		function InPageAppender(container, lazyInit, initiallyMinimized,

+								useDocumentWrite, width, height) {

+			this.create(true, container, lazyInit, initiallyMinimized,

+					useDocumentWrite, width, height, false);

+		}

+

+		InPageAppender.prototype = new ConsoleAppender();

+

+		InPageAppender.prototype.defaults = {

+			layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),

+			initiallyMinimized: false,

+			lazyInit: true,

+			newestMessageAtTop: false,

+			scrollToLatestMessage: true,

+			width: "100%",

+			height: "220px",

+			maxMessages: null,

+			showCommandLine: true,

+			commandLineObjectExpansionDepth: 1,

+			showHideButton: false,

+			showCloseButton: false,

+            showLogEntryDeleteButtons: true,

+            useDocumentWrite: true

+		};

+

+		InPageAppender.prototype.toString = function() {

+			return "InPageAppender";

+		};

+

+		log4javascript.InPageAppender = InPageAppender;

+

+		// Next line for backwards compatibility

+		log4javascript.InlineAppender = InPageAppender;

+	})();

+	/* ---------------------------------------------------------------------- */

+	// Console extension functions

+

+	function padWithSpaces(str, len) {

+		if (str.length < len) {

+			var spaces = [];

+			var numberOfSpaces = Math.max(0, len - str.length);

+			for (var i = 0; i < numberOfSpaces; i++) {

+				spaces[i] = " ";

+			}

+			str += spaces.join("");

+		}

+		return str;

+	}

+

+	(function() {

+		function dir(obj) {

+			var maxLen = 0;

+			// Obtain the length of the longest property name

+			for (var p in obj) {

+				maxLen = Math.max(toStr(p).length, maxLen);

+			}

+			// Create the nicely formatted property list

+			var propList = [];

+			for (p in obj) {

+				var propNameStr = "  " + padWithSpaces(toStr(p), maxLen + 2);

+				var propVal;

+				try {

+					propVal = splitIntoLines(toStr(obj[p])).join(padWithSpaces(newLine, maxLen + 6));

+				} catch (ex) {

+					propVal = "[Error obtaining property. Details: " + getExceptionMessage(ex) + "]";

+				}

+				propList.push(propNameStr + propVal);

+			}

+			return propList.join(newLine);

+		}

+

+		var nodeTypes = {

+			ELEMENT_NODE: 1,

+			ATTRIBUTE_NODE: 2,

+			TEXT_NODE: 3,

+			CDATA_SECTION_NODE: 4,

+			ENTITY_REFERENCE_NODE: 5,

+			ENTITY_NODE: 6,

+			PROCESSING_INSTRUCTION_NODE: 7,

+			COMMENT_NODE: 8,

+			DOCUMENT_NODE: 9,

+			DOCUMENT_TYPE_NODE: 10,

+			DOCUMENT_FRAGMENT_NODE: 11,

+			NOTATION_NODE: 12

+		};

+

+		var preFormattedElements = ["script", "pre"];

+

+		// This should be the definitive list, as specified by the XHTML 1.0 Transitional DTD

+		var emptyElements = ["br", "img", "hr", "param", "link", "area", "input", "col", "base", "meta"];

+		var indentationUnit = "  ";

+

+		// Create and return an XHTML string from the node specified

+		function getXhtml(rootNode, includeRootNode, indentation, startNewLine, preformatted) {

+			includeRootNode = (typeof includeRootNode == "undefined") ? true : !!includeRootNode;

+			if (typeof indentation != "string") {

+				indentation = "";

+			}

+			startNewLine = !!startNewLine;

+			preformatted = !!preformatted;

+			var xhtml;

+

+			function isWhitespace(node) {

+				return ((node.nodeType == nodeTypes.TEXT_NODE) && /^[ \t\r\n]*$/.test(node.nodeValue));

+			}

+

+			function fixAttributeValue(attrValue) {

+				return attrValue.toString().replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/"/g, "&quot;");

+			}

+

+			function getStyleAttributeValue(el) {

+				var stylePairs = el.style.cssText.split(";");

+				var styleValue = "";

+				var isFirst = true;

+				for (var j = 0, len = stylePairs.length; j < len; j++) {

+					var nameValueBits = stylePairs[j].split(":");

+					var props = [];

+					if (!/^\s*$/.test(nameValueBits[0])) {

+						props.push(trim(nameValueBits[0]).toLowerCase() + ":" + trim(nameValueBits[1]));

+					}

+					styleValue = props.join(";");

+				}

+				return styleValue;

+			}

+

+			function getNamespace(el) {

+				if (el.prefix) {

+					return el.prefix;

+				} else if (el.outerHTML) {

+					var regex = new RegExp("<([^:]+):" + el.tagName + "[^>]*>", "i");

+					if (regex.test(el.outerHTML)) {

+						return RegExp.$1.toLowerCase();

+					}

+				}

+                return "";

+			}

+

+			var lt = "<";

+			var gt = ">";

+

+			if (includeRootNode && rootNode.nodeType != nodeTypes.DOCUMENT_FRAGMENT_NODE) {

+				switch (rootNode.nodeType) {

+					case nodeTypes.ELEMENT_NODE:

+						var tagName = rootNode.tagName.toLowerCase();

+						xhtml = startNewLine ? newLine + indentation : "";

+						xhtml += lt;

+						// Allow for namespaces, where present

+						var prefix = getNamespace(rootNode);

+						var hasPrefix = !!prefix;

+						if (hasPrefix) {

+							xhtml += prefix + ":";

+						}

+						xhtml += tagName;

+						for (i = 0, len = rootNode.attributes.length; i < len; i++) {

+							var currentAttr = rootNode.attributes[i];

+							// Check the attribute is valid.

+							if (!	currentAttr.specified ||

+									currentAttr.nodeValue === null ||

+									currentAttr.nodeName.toLowerCase() === "style" ||

+									typeof currentAttr.nodeValue !== "string" ||

+									currentAttr.nodeName.indexOf("_moz") === 0) {

+								continue;

+							}

+							xhtml += " " + currentAttr.nodeName.toLowerCase() + "=\"";

+							xhtml += fixAttributeValue(currentAttr.nodeValue);

+							xhtml += "\"";

+						}

+						// Style needs to be done separately as it is not reported as an

+						// attribute in IE

+						if (rootNode.style.cssText) {

+							var styleValue = getStyleAttributeValue(rootNode);

+							if (styleValue !== "") {

+								xhtml += " style=\"" + getStyleAttributeValue(rootNode) + "\"";

+							}

+						}

+						if (array_contains(emptyElements, tagName) ||

+								(hasPrefix && !rootNode.hasChildNodes())) {

+							xhtml += "/" + gt;

+						} else {

+							xhtml += gt;

+							// Add output for childNodes collection (which doesn't include attribute nodes)

+							var childStartNewLine = !(rootNode.childNodes.length === 1 &&

+								rootNode.childNodes[0].nodeType === nodeTypes.TEXT_NODE);

+							var childPreformatted = array_contains(preFormattedElements, tagName);

+							for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {

+								xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit,

+									childStartNewLine, childPreformatted);

+							}

+							// Add the end tag

+							var endTag = lt + "/" + tagName + gt;

+							xhtml += childStartNewLine ? newLine + indentation + endTag : endTag;

+						}

+						return xhtml;

+					case nodeTypes.TEXT_NODE:

+						if (isWhitespace(rootNode)) {

+							xhtml = "";

+						} else {

+							if (preformatted) {

+								xhtml = rootNode.nodeValue;

+							} else {

+								// Trim whitespace from each line of the text node

+								var lines = splitIntoLines(trim(rootNode.nodeValue));

+								var trimmedLines = [];

+								for (var i = 0, len = lines.length; i < len; i++) {

+									trimmedLines[i] = trim(lines[i]);

+								}

+								xhtml = trimmedLines.join(newLine + indentation);

+							}

+							if (startNewLine) {

+								xhtml = newLine + indentation + xhtml;

+							}

+						}

+						return xhtml;

+					case nodeTypes.CDATA_SECTION_NODE:

+						return "<![CDA" + "TA[" + rootNode.nodeValue + "]" + "]>" + newLine;

+					case nodeTypes.DOCUMENT_NODE:

+						xhtml = "";

+						// Add output for childNodes collection (which doesn't include attribute nodes)

+						for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {

+							xhtml += getXhtml(rootNode.childNodes[i], true, indentation);

+						}

+						return xhtml;

+					default:

+						return "";

+				}

+			} else {

+				xhtml = "";

+				// Add output for childNodes collection (which doesn't include attribute nodes)

+				for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {

+					xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit);

+				}

+				return xhtml;

+			}

+		}

+

+		function createCommandLineFunctions() {

+			ConsoleAppender.addGlobalCommandLineFunction("$", function(appender, args, returnValue) {

+				return document.getElementById(args[0]);

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("dir", function(appender, args, returnValue) {

+				var lines = [];

+				for (var i = 0, len = args.length; i < len; i++) {

+					lines[i] = dir(args[i]);

+				}

+				return lines.join(newLine + newLine);

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("dirxml", function(appender, args, returnValue) {

+				var lines = [];

+				for (var i = 0, len = args.length; i < len; i++) {

+					var win = appender.getCommandWindow();

+					lines[i] = getXhtml(args[i]);

+				}

+				return lines.join(newLine + newLine);

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("cd", function(appender, args, returnValue) {

+				var win, message;

+				if (args.length === 0 || args[0] === "") {

+					win = window;

+					message = "Command line set to run in main window";

+				} else {

+					if (args[0].window == args[0]) {

+						win = args[0];

+						message = "Command line set to run in frame '" + args[0].name + "'";

+					} else {

+						win = window.frames[args[0]];

+						if (win) {

+							message = "Command line set to run in frame '" + args[0] + "'";

+						} else {

+							returnValue.isError = true;

+							message = "Frame '" + args[0] + "' does not exist";

+							win = appender.getCommandWindow();

+						}

+					}

+				}

+				appender.setCommandWindow(win);

+				return message;

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("clear", function(appender, args, returnValue) {

+				returnValue.appendResult = false;

+				appender.clear();

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("keys", function(appender, args, returnValue) {

+				var keys = [];

+				for (var k in args[0]) {

+					keys.push(k);

+				}

+				return keys;

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("values", function(appender, args, returnValue) {

+				var values = [];

+				for (var k in args[0]) {

+					try {

+						values.push(args[0][k]);

+					} catch (ex) {

+						logLog.warn("values(): Unable to obtain value for key " + k + ". Details: " + getExceptionMessage(ex));

+					}

+				}

+				return values;

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("expansionDepth", function(appender, args, returnValue) {

+				var expansionDepth = parseInt(args[0], 10);

+				if (isNaN(expansionDepth) || expansionDepth < 0) {

+					returnValue.isError = true;

+					return "" + args[0] + " is not a valid expansion depth";

+				} else {

+					appender.setCommandLineObjectExpansionDepth(expansionDepth);

+					return "Object expansion depth set to " + expansionDepth;

+				}

+			});

+		}

+

+		function init() {

+			// Add command line functions

+			createCommandLineFunctions();

+		}

+

+		/* ------------------------------------------------------------------ */

+

+		init();

+	})();

+

+	/* ---------------------------------------------------------------------- */

+	// Main load

+

+   log4javascript.setDocumentReady = function() {

+       pageLoaded = true;

+       log4javascript.dispatchEvent("load", {});

+   };

+

+    if (window.addEventListener) {

+        window.addEventListener("load", log4javascript.setDocumentReady, false);

+    } else if (window.attachEvent) {

+        window.attachEvent("onload", log4javascript.setDocumentReady);

+    } else {

+        var oldOnload = window.onload;

+        if (typeof window.onload != "function") {

+            window.onload = log4javascript.setDocumentReady;

+        } else {

+            window.onload = function(evt) {

+                if (oldOnload) {

+                    oldOnload(evt);

+                }

+                log4javascript.setDocumentReady();

+            };

+        }

+    }

+

+    // Ensure that the log4javascript object is available in the window. This

+    // is necessary for log4javascript to be available in IE if loaded using

+    // Dojo's module system

+    window.log4javascript = log4javascript;

+

+    return log4javascript;

+})();
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript.js b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript.js
new file mode 100644
index 0000000..eae582b
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript.js
@@ -0,0 +1,23 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+var log4javascript_stub=(function(){var log4javascript;function ff(){return function(){};}

+function copy(obj,props){for(var i in props){obj[i]=props[i];}}

+var f=ff();var Logger=ff();copy(Logger.prototype,{addChild:f,getEffectiveAppenders:f,invalidateAppenderCache:f,getAdditivity:f,setAdditivity:f,addAppender:f,removeAppender:f,removeAllAppenders:f,log:f,setLevel:f,getLevel:f,getEffectiveLevel:f,trace:f,debug:f,info:f,warn:f,error:f,fatal:f,isEnabledFor:f,isTraceEnabled:f,isDebugEnabled:f,isInfoEnabled:f,isWarnEnabled:f,isErrorEnabled:f,isFatalEnabled:f,callAppenders:f,group:f,groupEnd:f,time:f,timeEnd:f,assert:f,parent:new Logger()});var getLogger=function(){return new Logger();};function EventSupport(){}

+copy(EventSupport.prototype,{setEventTypes:f,addEventListener:f,removeEventListener:f,dispatchEvent:f,eventTypes:[],eventListeners:{}});function Log4JavaScript(){}

+Log4JavaScript.prototype=new EventSupport();log4javascript=new Log4JavaScript();log4javascript={isStub:true,version:"1.4.6",edition:"log4javascript",setDocumentReady:f,setEventTypes:f,addEventListener:f,removeEventListener:f,dispatchEvent:f,eventTypes:[],eventListeners:{},logLog:{setQuietMode:f,setAlertAllErrors:f,debug:f,displayDebug:f,warn:f,error:f},handleError:f,setEnabled:f,isEnabled:f,setTimeStampsInMilliseconds:f,isTimeStampsInMilliseconds:f,evalInScope:f,setShowStackTraces:f,getLogger:getLogger,getDefaultLogger:getLogger,getNullLogger:getLogger,getRootLogger:getLogger,resetConfiguration:f,Level:ff(),LoggingEvent:ff(),Layout:ff(),Appender:ff()};log4javascript.LoggingEvent.prototype={getThrowableStrRep:f,getCombinedMessages:f};log4javascript.Level.prototype={toString:f,equals:f,isGreaterOrEqual:f};var level=new log4javascript.Level();copy(log4javascript.Level,{ALL:level,TRACE:level,DEBUG:level,INFO:level,WARN:level,ERROR:level,FATAL:level,OFF:level});log4javascript.Layout.prototype={defaults:{},format:f,ignoresThrowable:f,getContentType:f,allowBatching:f,getDataValues:f,setKeys:f,setCustomField:f,hasCustomFields:f,setTimeStampsInMilliseconds:f,isTimeStampsInMilliseconds:f,getTimeStampValue:f,toString:f};log4javascript.SimpleDateFormat=ff();log4javascript.SimpleDateFormat.prototype={setMinimalDaysInFirstWeek:f,getMinimalDaysInFirstWeek:f,format:f};log4javascript.PatternLayout=ff();log4javascript.PatternLayout.prototype=new log4javascript.Layout();log4javascript.Appender=ff();log4javascript.Appender.prototype=new EventSupport();copy(log4javascript.Appender.prototype,{layout:new log4javascript.PatternLayout(),threshold:log4javascript.Level.ALL,loggers:[],doAppend:f,append:f,setLayout:f,getLayout:f,setThreshold:f,getThreshold:f,setAddedToLogger:f,setRemovedFromLogger:f,group:f,groupEnd:f,toString:f});log4javascript.SimpleLayout=ff();log4javascript.SimpleLayout.prototype=new log4javascript.Layout();log4javascript.NullLayout=ff();log4javascript.NullLayout.prototype=new log4javascript.Layout();log4javascript.XmlLayout=ff();log4javascript.XmlLayout.prototype=new log4javascript.Layout();copy(log4javascript.XmlLayout.prototype,{escapeCdata:f,isCombinedMessages:f});log4javascript.JsonLayout=ff();log4javascript.JsonLayout.prototype=new log4javascript.Layout();copy(log4javascript.JsonLayout.prototype,{isReadable:f,isCombinedMessages:f});log4javascript.HttpPostDataLayout=ff();log4javascript.HttpPostDataLayout.prototype=new log4javascript.Layout();log4javascript.PatternLayout=ff();log4javascript.PatternLayout.prototype=new log4javascript.Layout();log4javascript.AlertAppender=ff();log4javascript.AlertAppender.prototype=new log4javascript.Appender();log4javascript.BrowserConsoleAppender=ff();log4javascript.BrowserConsoleAppender.prototype=new log4javascript.Appender();log4javascript.AjaxAppender=ff();log4javascript.AjaxAppender.prototype=new log4javascript.Appender();copy(log4javascript.AjaxAppender.prototype,{getSessionId:f,setSessionId:f,isTimed:f,setTimed:f,getTimerInterval:f,setTimerInterval:f,isWaitForResponse:f,setWaitForResponse:f,getBatchSize:f,setBatchSize:f,isSendAllOnUnload:f,setSendAllOnUnload:f,setRequestSuccessCallback:f,setFailCallback:f,getPostVarName:f,setPostVarName:f,sendAll:f,sendAllRemaining:f,defaults:{requestSuccessCallback:null,failCallback:null}});function ConsoleAppender(){}

+ConsoleAppender.prototype=new log4javascript.Appender();copy(ConsoleAppender.prototype,{create:f,isNewestMessageAtTop:f,setNewestMessageAtTop:f,isScrollToLatestMessage:f,setScrollToLatestMessage:f,getWidth:f,setWidth:f,getHeight:f,setHeight:f,getMaxMessages:f,setMaxMessages:f,isShowCommandLine:f,setShowCommandLine:f,isShowHideButton:f,setShowHideButton:f,isShowCloseButton:f,setShowCloseButton:f,getCommandLineObjectExpansionDepth:f,setCommandLineObjectExpansionDepth:f,isInitiallyMinimized:f,setInitiallyMinimized:f,isUseDocumentWrite:f,setUseDocumentWrite:f,group:f,groupEnd:f,clear:f,focus:f,focusCommandLine:f,focusSearch:f,getCommandWindow:f,setCommandWindow:f,executeLastCommand:f,getCommandLayout:f,setCommandLayout:f,evalCommandAndAppend:f,addCommandLineFunction:f,storeCommandHistory:f,unload:f});ConsoleAppender.addGlobalCommandLineFunction=f;log4javascript.InPageAppender=ff();log4javascript.InPageAppender.prototype=new ConsoleAppender();copy(log4javascript.InPageAppender.prototype,{addCssProperty:f,hide:f,show:f,isVisible:f,close:f,defaults:{layout:new log4javascript.PatternLayout(),maxMessages:null}});log4javascript.InlineAppender=log4javascript.InPageAppender;log4javascript.PopUpAppender=ff();log4javascript.PopUpAppender.prototype=new ConsoleAppender();copy(log4javascript.PopUpAppender.prototype,{isUseOldPopUp:f,setUseOldPopUp:f,isComplainAboutPopUpBlocking:f,setComplainAboutPopUpBlocking:f,isFocusPopUp:f,setFocusPopUp:f,isReopenWhenClosed:f,setReopenWhenClosed:f,close:f,hide:f,show:f,defaults:{layout:new log4javascript.PatternLayout(),maxMessages:null}});return log4javascript;})();if(typeof window.log4javascript=="undefined"){var log4javascript=log4javascript_stub;}

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite.js b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite.js
new file mode 100644
index 0000000..7d2ea14
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite.js
@@ -0,0 +1,21 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+var log4javascript_stub=(function(){var log4javascript;function ff(){return function(){};}

+function copy(obj,props){for(var i in props){obj[i]=props[i];}}

+var f=ff();var Logger=ff();copy(Logger.prototype,{setLevel:f,getLevel:f,trace:f,debug:f,info:f,warn:f,error:f,fatal:f,isEnabledFor:f,isTraceEnabled:f,isDebugEnabled:f,isInfoEnabled:f,isWarnEnabled:f,isErrorEnabled:f,isFatalEnabled:f});var getLogger=function(){return new Logger();};function Log4JavaScript(){}

+log4javascript=new Log4JavaScript();log4javascript={isStub:true,version:"1.4.6",edition:"log4javascript_lite",setEnabled:f,isEnabled:f,setShowStackTraces:f,getDefaultLogger:getLogger,getLogger:getLogger,getNullLogger:getLogger,Level:ff(),LoggingEvent:ff(),Appender:ff()};log4javascript.LoggingEvent.prototype={getThrowableStrRep:f,getCombinedMessages:f};log4javascript.Level.prototype={toString:f,equals:f,isGreaterOrEqual:f};var level=new log4javascript.Level();copy(log4javascript.Level,{ALL:level,TRACE:level,DEBUG:level,INFO:level,WARN:level,ERROR:level,FATAL:level,OFF:level});log4javascript.Appender.prototype.append=f;return log4javascript;})();if(typeof window.log4javascript=="undefined"){var log4javascript=log4javascript_stub;}

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite_uncompressed.js
new file mode 100644
index 0000000..afb9ba7
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite_uncompressed.js
@@ -0,0 +1,102 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+var log4javascript_stub = (function() {

+	var log4javascript;

+

+	function ff() {

+		return function() {};

+	}

+	function copy(obj, props) {

+		for (var i in props) {

+			obj[i] = props[i];

+		}

+	}

+	var f = ff();

+

+	// Loggers

+	var Logger = ff();

+	copy(Logger.prototype, {

+		setLevel: f,

+		getLevel: f,

+		trace: f,

+		debug: f,

+		info: f,

+		warn: f,

+		error: f,

+		fatal: f,

+		isEnabledFor: f,

+		isTraceEnabled: f,

+		isDebugEnabled: f,

+		isInfoEnabled: f,

+		isWarnEnabled: f,

+		isErrorEnabled: f,

+		isFatalEnabled: f

+	});

+

+	var getLogger = function() {

+		return new Logger();

+	};

+

+	function Log4JavaScript() {}

+	log4javascript = new Log4JavaScript();

+

+	log4javascript = {

+		isStub: true,

+		version: "1.4.6",

+		edition: "log4javascript_lite",

+		setEnabled: f,

+		isEnabled: f,

+		setShowStackTraces: f,

+		getDefaultLogger: getLogger,

+		getLogger: getLogger,

+		getNullLogger: getLogger,

+		Level: ff(),

+		LoggingEvent: ff(),

+		Appender: ff()

+	};

+

+	// LoggingEvents

+	log4javascript.LoggingEvent.prototype = {

+		getThrowableStrRep: f,

+		getCombinedMessages: f

+	};

+

+	// Levels

+	log4javascript.Level.prototype = {

+		toString: f,

+		equals: f,

+		isGreaterOrEqual: f

+	};

+	var level = new log4javascript.Level();

+	copy(log4javascript.Level, {

+		ALL: level,

+		TRACE: level,

+		DEBUG: level,

+		INFO: level,

+		WARN: level,

+		ERROR: level,

+		FATAL: level,

+		OFF: level

+	});

+	

+	log4javascript.Appender.prototype.append = f;

+

+	return log4javascript;

+})();

+if (typeof window.log4javascript == "undefined") {

+	var log4javascript = log4javascript_stub;

+}

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production.js b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production.js
new file mode 100644
index 0000000..69a90a8
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production.js
@@ -0,0 +1,22 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+var log4javascript_stub=(function(){var log4javascript;function ff(){return function(){};}

+function copy(obj,props){for(var i in props){obj[i]=props[i];}}

+var f=ff();var Logger=ff();copy(Logger.prototype,{addChild:f,getEffectiveAppenders:f,invalidateAppenderCache:f,getAdditivity:f,setAdditivity:f,addAppender:f,removeAppender:f,removeAllAppenders:f,log:f,setLevel:f,getLevel:f,getEffectiveLevel:f,trace:f,debug:f,info:f,warn:f,error:f,fatal:f,isEnabledFor:f,isTraceEnabled:f,isDebugEnabled:f,isInfoEnabled:f,isWarnEnabled:f,isErrorEnabled:f,isFatalEnabled:f,callAppenders:f,group:f,groupEnd:f,time:f,timeEnd:f,assert:f,parent:new Logger()});var getLogger=function(){return new Logger();};function EventSupport(){}

+copy(EventSupport.prototype,{setEventTypes:f,addEventListener:f,removeEventListener:f,dispatchEvent:f,eventTypes:[],eventListeners:{}});function Log4JavaScript(){}

+Log4JavaScript.prototype=new EventSupport();log4javascript=new Log4JavaScript();log4javascript={isStub:true,version:"1.4.6",edition:"log4javascript_production",setDocumentReady:f,setEventTypes:f,addEventListener:f,removeEventListener:f,dispatchEvent:f,eventTypes:[],eventListeners:{},logLog:{setQuietMode:f,setAlertAllErrors:f,debug:f,displayDebug:f,warn:f,error:f},handleError:f,setEnabled:f,isEnabled:f,setTimeStampsInMilliseconds:f,isTimeStampsInMilliseconds:f,evalInScope:f,setShowStackTraces:f,getLogger:getLogger,getDefaultLogger:getLogger,getNullLogger:getLogger,getRootLogger:getLogger,resetConfiguration:f,Level:ff(),LoggingEvent:ff(),Layout:ff(),Appender:ff()};log4javascript.LoggingEvent.prototype={getThrowableStrRep:f,getCombinedMessages:f};log4javascript.Level.prototype={toString:f,equals:f,isGreaterOrEqual:f};var level=new log4javascript.Level();copy(log4javascript.Level,{ALL:level,TRACE:level,DEBUG:level,INFO:level,WARN:level,ERROR:level,FATAL:level,OFF:level});log4javascript.Layout.prototype={defaults:{},format:f,ignoresThrowable:f,getContentType:f,allowBatching:f,getDataValues:f,setKeys:f,setCustomField:f,hasCustomFields:f,setTimeStampsInMilliseconds:f,isTimeStampsInMilliseconds:f,getTimeStampValue:f,toString:f};log4javascript.SimpleDateFormat=ff();log4javascript.SimpleDateFormat.prototype={setMinimalDaysInFirstWeek:f,getMinimalDaysInFirstWeek:f,format:f};log4javascript.PatternLayout=ff();log4javascript.PatternLayout.prototype=new log4javascript.Layout();log4javascript.Appender=ff();log4javascript.Appender.prototype=new EventSupport();copy(log4javascript.Appender.prototype,{layout:new log4javascript.PatternLayout(),threshold:log4javascript.Level.ALL,loggers:[],doAppend:f,append:f,setLayout:f,getLayout:f,setThreshold:f,getThreshold:f,setAddedToLogger:f,setRemovedFromLogger:f,group:f,groupEnd:f,toString:f});log4javascript.SimpleLayout=ff();log4javascript.SimpleLayout.prototype=new log4javascript.Layout();log4javascript.NullLayout=ff();log4javascript.NullLayout.prototype=new log4javascript.Layout();log4javascript.XmlLayout=ff();log4javascript.XmlLayout.prototype=new log4javascript.Layout();copy(log4javascript.XmlLayout.prototype,{escapeCdata:f,isCombinedMessages:f});log4javascript.JsonLayout=ff();log4javascript.JsonLayout.prototype=new log4javascript.Layout();copy(log4javascript.JsonLayout.prototype,{isReadable:f,isCombinedMessages:f});log4javascript.HttpPostDataLayout=ff();log4javascript.HttpPostDataLayout.prototype=new log4javascript.Layout();log4javascript.PatternLayout=ff();log4javascript.PatternLayout.prototype=new log4javascript.Layout();log4javascript.AjaxAppender=ff();log4javascript.AjaxAppender.prototype=new log4javascript.Appender();copy(log4javascript.AjaxAppender.prototype,{getSessionId:f,setSessionId:f,isTimed:f,setTimed:f,getTimerInterval:f,setTimerInterval:f,isWaitForResponse:f,setWaitForResponse:f,getBatchSize:f,setBatchSize:f,isSendAllOnUnload:f,setSendAllOnUnload:f,setRequestSuccessCallback:f,setFailCallback:f,getPostVarName:f,setPostVarName:f,sendAll:f,sendAllRemaining:f,defaults:{requestSuccessCallback:null,failCallback:null}});return log4javascript;})();if(typeof window.log4javascript=="undefined"){var log4javascript=log4javascript_stub;}

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production_uncompressed.js
new file mode 100644
index 0000000..79eb7ca
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production_uncompressed.js
@@ -0,0 +1,253 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+var log4javascript_stub = (function() {

+	var log4javascript;

+

+	function ff() {

+		return function() {};

+	}

+	function copy(obj, props) {

+		for (var i in props) {

+			obj[i] = props[i];

+		}

+	}

+	var f = ff();

+

+	// Loggers

+	var Logger = ff();

+	copy(Logger.prototype, {

+		addChild: f,

+		getEffectiveAppenders: f,

+		invalidateAppenderCache: f,

+		getAdditivity: f,

+		setAdditivity: f,

+		addAppender: f,

+		removeAppender: f,

+		removeAllAppenders: f,

+		log: f,

+		setLevel: f,

+		getLevel: f,

+		getEffectiveLevel: f,

+		trace: f,

+		debug: f,

+		info: f,

+		warn: f,

+		error: f,

+		fatal: f,

+		isEnabledFor: f,

+		isTraceEnabled: f,

+		isDebugEnabled: f,

+		isInfoEnabled: f,

+		isWarnEnabled: f,

+		isErrorEnabled: f,

+		isFatalEnabled: f,

+		callAppenders: f,

+		group: f,

+		groupEnd: f,

+		time: f,

+		timeEnd: f,

+		assert: f,

+		parent: new Logger()

+	});

+

+	var getLogger = function() {

+		return new Logger();

+	};

+

+	function EventSupport() {}

+

+	copy(EventSupport.prototype, {

+		setEventTypes: f,

+		addEventListener: f,

+		removeEventListener: f,

+		dispatchEvent: f,

+		eventTypes: [],

+		eventListeners: {}

+	});

+

+	function Log4JavaScript() {}

+	Log4JavaScript.prototype = new EventSupport();

+	log4javascript = new Log4JavaScript();

+

+	log4javascript = {

+		isStub: true,

+		version: "1.4.6",

+		edition: "log4javascript_production",

+        setDocumentReady: f,

+		setEventTypes: f,

+		addEventListener: f,

+		removeEventListener: f,

+		dispatchEvent: f,

+		eventTypes: [],

+		eventListeners: {},

+		logLog: {

+			setQuietMode: f,

+			setAlertAllErrors: f,

+			debug: f,

+			displayDebug: f,

+			warn: f,

+			error: f

+		},

+		handleError: f,

+		setEnabled: f,

+		isEnabled: f,

+		setTimeStampsInMilliseconds: f,

+		isTimeStampsInMilliseconds: f,

+		evalInScope: f,

+		setShowStackTraces: f,

+		getLogger: getLogger,

+		getDefaultLogger: getLogger,

+		getNullLogger: getLogger,

+		getRootLogger: getLogger,

+		resetConfiguration: f,

+		Level: ff(),

+		LoggingEvent: ff(),

+		Layout: ff(),

+		Appender: ff()

+	};

+

+	// LoggingEvents

+	log4javascript.LoggingEvent.prototype = {

+		getThrowableStrRep: f,

+		getCombinedMessages: f

+	};

+

+	// Levels

+	log4javascript.Level.prototype = {

+		toString: f,

+		equals: f,

+		isGreaterOrEqual: f

+	};

+	var level = new log4javascript.Level();

+	copy(log4javascript.Level, {

+		ALL: level,

+		TRACE: level,

+		DEBUG: level,

+		INFO: level,

+		WARN: level,

+		ERROR: level,

+		FATAL: level,

+		OFF: level

+	});

+

+	// Layouts

+	log4javascript.Layout.prototype = {

+		defaults: {},

+		format: f,

+		ignoresThrowable: f,

+		getContentType: f,

+		allowBatching: f,

+		getDataValues: f,

+		setKeys: f,

+		setCustomField: f,

+		hasCustomFields: f,

+		setTimeStampsInMilliseconds: f,

+		isTimeStampsInMilliseconds: f,

+		getTimeStampValue: f,

+		toString: f

+	};

+

+	// PatternLayout related

+	log4javascript.SimpleDateFormat = ff();

+	log4javascript.SimpleDateFormat.prototype = {

+		setMinimalDaysInFirstWeek: f,

+		getMinimalDaysInFirstWeek: f,

+		format: f

+	};

+

+	// PatternLayout

+	log4javascript.PatternLayout = ff();

+	log4javascript.PatternLayout.prototype = new log4javascript.Layout();

+

+	// Appenders

+	log4javascript.Appender = ff();

+	log4javascript.Appender.prototype = new EventSupport();

+

+	copy(log4javascript.Appender.prototype, {

+		layout: new log4javascript.PatternLayout(),

+		threshold: log4javascript.Level.ALL,

+		loggers: [],

+		doAppend: f,

+		append: f,

+		setLayout: f,

+		getLayout: f,

+		setThreshold: f,

+		getThreshold: f,

+		setAddedToLogger: f,

+		setRemovedFromLogger: f,

+		group: f,

+		groupEnd: f,

+		toString: f

+	});

+	// SimpleLayout

+	log4javascript.SimpleLayout = ff();

+	log4javascript.SimpleLayout.prototype = new log4javascript.Layout();

+	// NullLayout

+	log4javascript.NullLayout = ff();

+	log4javascript.NullLayout.prototype = new log4javascript.Layout();

+	// ZmlLayout

+	log4javascript.XmlLayout = ff();

+	log4javascript.XmlLayout.prototype = new log4javascript.Layout();

+	copy(log4javascript.XmlLayout.prototype, {

+		escapeCdata: f,

+		isCombinedMessages: f

+	});

+	// JsonLayout

+	log4javascript.JsonLayout = ff();

+	log4javascript.JsonLayout.prototype = new log4javascript.Layout();

+	copy(log4javascript.JsonLayout.prototype, {

+		isReadable: f,

+		isCombinedMessages: f

+	});

+	// HttpPostDataLayout 

+	log4javascript.HttpPostDataLayout = ff();

+	log4javascript.HttpPostDataLayout.prototype = new log4javascript.Layout();

+	// PatternLayout

+	log4javascript.PatternLayout = ff();

+	log4javascript.PatternLayout.prototype = new log4javascript.Layout();

+	// AjaxAppender

+	log4javascript.AjaxAppender = ff();

+	log4javascript.AjaxAppender.prototype = new log4javascript.Appender();

+	copy(log4javascript.AjaxAppender.prototype, {

+		getSessionId: f,

+		setSessionId: f,

+		isTimed: f,

+		setTimed: f,

+		getTimerInterval: f,

+		setTimerInterval: f,

+		isWaitForResponse: f,

+		setWaitForResponse: f,

+		getBatchSize: f,

+		setBatchSize: f,

+		isSendAllOnUnload: f,

+		setSendAllOnUnload: f,

+		setRequestSuccessCallback: f,

+		setFailCallback: f,

+		getPostVarName: f,

+		setPostVarName: f,

+		sendAll: f,

+		sendAllRemaining: f,

+		defaults: {

+			requestSuccessCallback: null,

+			failCallback: null

+		}

+	});

+	return log4javascript;

+})();

+if (typeof window.log4javascript == "undefined") {

+	var log4javascript = log4javascript_stub;

+}

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_uncompressed.js
new file mode 100644
index 0000000..1976fbc
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_uncompressed.js
@@ -0,0 +1,341 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+var log4javascript_stub = (function() {

+	var log4javascript;

+

+	function ff() {

+		return function() {};

+	}

+	function copy(obj, props) {

+		for (var i in props) {

+			obj[i] = props[i];

+		}

+	}

+	var f = ff();

+

+	// Loggers

+	var Logger = ff();

+	copy(Logger.prototype, {

+		addChild: f,

+		getEffectiveAppenders: f,

+		invalidateAppenderCache: f,

+		getAdditivity: f,

+		setAdditivity: f,

+		addAppender: f,

+		removeAppender: f,

+		removeAllAppenders: f,

+		log: f,

+		setLevel: f,

+		getLevel: f,

+		getEffectiveLevel: f,

+		trace: f,

+		debug: f,

+		info: f,

+		warn: f,

+		error: f,

+		fatal: f,

+		isEnabledFor: f,

+		isTraceEnabled: f,

+		isDebugEnabled: f,

+		isInfoEnabled: f,

+		isWarnEnabled: f,

+		isErrorEnabled: f,

+		isFatalEnabled: f,

+		callAppenders: f,

+		group: f,

+		groupEnd: f,

+		time: f,

+		timeEnd: f,

+		assert: f,

+		parent: new Logger()

+	});

+

+	var getLogger = function() {

+		return new Logger();

+	};

+

+	function EventSupport() {}

+

+	copy(EventSupport.prototype, {

+		setEventTypes: f,

+		addEventListener: f,

+		removeEventListener: f,

+		dispatchEvent: f,

+		eventTypes: [],

+		eventListeners: {}

+	});

+

+	function Log4JavaScript() {}

+	Log4JavaScript.prototype = new EventSupport();

+	log4javascript = new Log4JavaScript();

+

+	log4javascript = {

+		isStub: true,

+		version: "1.4.6",

+		edition: "log4javascript",

+        setDocumentReady: f,

+		setEventTypes: f,

+		addEventListener: f,

+		removeEventListener: f,

+		dispatchEvent: f,

+		eventTypes: [],

+		eventListeners: {},

+		logLog: {

+			setQuietMode: f,

+			setAlertAllErrors: f,

+			debug: f,

+			displayDebug: f,

+			warn: f,

+			error: f

+		},

+		handleError: f,

+		setEnabled: f,

+		isEnabled: f,

+		setTimeStampsInMilliseconds: f,

+		isTimeStampsInMilliseconds: f,

+		evalInScope: f,

+		setShowStackTraces: f,

+		getLogger: getLogger,

+		getDefaultLogger: getLogger,

+		getNullLogger: getLogger,

+		getRootLogger: getLogger,

+		resetConfiguration: f,

+		Level: ff(),

+		LoggingEvent: ff(),

+		Layout: ff(),

+		Appender: ff()

+	};

+

+	// LoggingEvents

+	log4javascript.LoggingEvent.prototype = {

+		getThrowableStrRep: f,

+		getCombinedMessages: f

+	};

+

+	// Levels

+	log4javascript.Level.prototype = {

+		toString: f,

+		equals: f,

+		isGreaterOrEqual: f

+	};

+	var level = new log4javascript.Level();

+	copy(log4javascript.Level, {

+		ALL: level,

+		TRACE: level,

+		DEBUG: level,

+		INFO: level,

+		WARN: level,

+		ERROR: level,

+		FATAL: level,

+		OFF: level

+	});

+

+	// Layouts

+	log4javascript.Layout.prototype = {

+		defaults: {},

+		format: f,

+		ignoresThrowable: f,

+		getContentType: f,

+		allowBatching: f,

+		getDataValues: f,

+		setKeys: f,

+		setCustomField: f,

+		hasCustomFields: f,

+		setTimeStampsInMilliseconds: f,

+		isTimeStampsInMilliseconds: f,

+		getTimeStampValue: f,

+		toString: f

+	};

+

+	// PatternLayout related

+	log4javascript.SimpleDateFormat = ff();

+	log4javascript.SimpleDateFormat.prototype = {

+		setMinimalDaysInFirstWeek: f,

+		getMinimalDaysInFirstWeek: f,

+		format: f

+	};

+

+	// PatternLayout

+	log4javascript.PatternLayout = ff();

+	log4javascript.PatternLayout.prototype = new log4javascript.Layout();

+

+	// Appenders

+	log4javascript.Appender = ff();

+	log4javascript.Appender.prototype = new EventSupport();

+

+	copy(log4javascript.Appender.prototype, {

+		layout: new log4javascript.PatternLayout(),

+		threshold: log4javascript.Level.ALL,

+		loggers: [],

+		doAppend: f,

+		append: f,

+		setLayout: f,

+		getLayout: f,

+		setThreshold: f,

+		getThreshold: f,

+		setAddedToLogger: f,

+		setRemovedFromLogger: f,

+		group: f,

+		groupEnd: f,

+		toString: f

+	});

+	// SimpleLayout

+	log4javascript.SimpleLayout = ff();

+	log4javascript.SimpleLayout.prototype = new log4javascript.Layout();

+	// NullLayout

+	log4javascript.NullLayout = ff();

+	log4javascript.NullLayout.prototype = new log4javascript.Layout();

+	// ZmlLayout

+	log4javascript.XmlLayout = ff();

+	log4javascript.XmlLayout.prototype = new log4javascript.Layout();

+	copy(log4javascript.XmlLayout.prototype, {

+		escapeCdata: f,

+		isCombinedMessages: f

+	});

+	// JsonLayout

+	log4javascript.JsonLayout = ff();

+	log4javascript.JsonLayout.prototype = new log4javascript.Layout();

+	copy(log4javascript.JsonLayout.prototype, {

+		isReadable: f,

+		isCombinedMessages: f

+	});

+	// HttpPostDataLayout 

+	log4javascript.HttpPostDataLayout = ff();

+	log4javascript.HttpPostDataLayout.prototype = new log4javascript.Layout();

+	// PatternLayout

+	log4javascript.PatternLayout = ff();

+	log4javascript.PatternLayout.prototype = new log4javascript.Layout();

+	// AlertAppender

+	log4javascript.AlertAppender = ff();

+	log4javascript.AlertAppender.prototype = new log4javascript.Appender();

+	// BrowserConsoleAppender

+	log4javascript.BrowserConsoleAppender = ff();

+	log4javascript.BrowserConsoleAppender.prototype = new log4javascript.Appender();

+	// AjaxAppender

+	log4javascript.AjaxAppender = ff();

+	log4javascript.AjaxAppender.prototype = new log4javascript.Appender();

+	copy(log4javascript.AjaxAppender.prototype, {

+		getSessionId: f,

+		setSessionId: f,

+		isTimed: f,

+		setTimed: f,

+		getTimerInterval: f,

+		setTimerInterval: f,

+		isWaitForResponse: f,

+		setWaitForResponse: f,

+		getBatchSize: f,

+		setBatchSize: f,

+		isSendAllOnUnload: f,

+		setSendAllOnUnload: f,

+		setRequestSuccessCallback: f,

+		setFailCallback: f,

+		getPostVarName: f,

+		setPostVarName: f,

+		sendAll: f,

+		sendAllRemaining: f,

+		defaults: {

+			requestSuccessCallback: null,

+			failCallback: null

+		}

+	});

+	// ConsoleAppender

+	function ConsoleAppender() {}

+	ConsoleAppender.prototype = new log4javascript.Appender();

+	copy(ConsoleAppender.prototype, {

+		create: f,

+		isNewestMessageAtTop: f,

+		setNewestMessageAtTop: f,

+		isScrollToLatestMessage: f,

+		setScrollToLatestMessage: f,

+		getWidth: f,

+		setWidth: f,

+		getHeight: f,

+		setHeight: f,

+		getMaxMessages: f,

+		setMaxMessages: f,

+		isShowCommandLine: f,

+		setShowCommandLine: f,

+		isShowHideButton: f,

+		setShowHideButton: f,

+		isShowCloseButton: f,

+		setShowCloseButton: f,

+		getCommandLineObjectExpansionDepth: f,

+		setCommandLineObjectExpansionDepth: f,

+		isInitiallyMinimized: f,

+		setInitiallyMinimized: f,

+		isUseDocumentWrite: f,

+		setUseDocumentWrite: f,

+		group: f,

+		groupEnd: f,

+		clear: f,

+		focus: f,

+		focusCommandLine: f,

+		focusSearch: f,

+		getCommandWindow: f,

+		setCommandWindow: f,

+		executeLastCommand: f,

+		getCommandLayout: f,

+		setCommandLayout: f,

+		evalCommandAndAppend: f,

+		addCommandLineFunction: f,

+		storeCommandHistory: f,

+		unload: f

+	});

+

+	ConsoleAppender.addGlobalCommandLineFunction = f;

+

+	// InPageAppender

+	log4javascript.InPageAppender = ff();

+	log4javascript.InPageAppender.prototype = new ConsoleAppender();

+	copy(log4javascript.InPageAppender.prototype, {

+		addCssProperty: f,

+		hide: f,

+		show: f,

+		isVisible: f,

+		close: f,

+		defaults: {

+			layout: new log4javascript.PatternLayout(),

+			maxMessages: null

+		}

+	});

+	log4javascript.InlineAppender = log4javascript.InPageAppender;

+

+	// PopUpAppender

+	log4javascript.PopUpAppender = ff();

+	log4javascript.PopUpAppender.prototype = new ConsoleAppender();

+	copy(log4javascript.PopUpAppender.prototype, {

+		isUseOldPopUp: f,

+		setUseOldPopUp: f,

+		isComplainAboutPopUpBlocking: f,

+		setComplainAboutPopUpBlocking: f,

+		isFocusPopUp: f,

+		setFocusPopUp: f,

+		isReopenWhenClosed: f,

+		setReopenWhenClosed: f,

+		close: f,

+		hide: f,

+		show: f,

+		defaults: {

+			layout: new log4javascript.PatternLayout(),

+			maxMessages: null

+		}

+	});

+	return log4javascript;

+})();

+if (typeof window.log4javascript == "undefined") {

+	var log4javascript = log4javascript_stub;

+}

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript.js b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript.js
new file mode 100644
index 0000000..89fd903
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript.js
@@ -0,0 +1,32 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+function array_contains(arr,val){for(var i=0;i<arr.length;i++){if(arr[i]==val){return true;}}

+return false;}

+function compareObjectInterface(obj1,obj1_name,obj2,obj2_name,namePrefix){if(!namePrefix){namePrefix="";}

+var obj1PropertyNames=new Array();for(var i in obj1){if(i!="prototype"&&i!="arguments"){obj1PropertyNames.push(i);}}

+if(obj1&&obj1.prototype&&!array_contains(obj1PropertyNames,"prototype")){}

+for(var j=0;j<obj1PropertyNames.length;j++){var propertyName=obj1PropertyNames[j];if((typeof obj1[propertyName]=="function"||typeof obj1[propertyName]=="object")&&!(obj1[propertyName]instanceof Array)){var propertyFullyQualifiedName=(namePrefix=="")?propertyName:namePrefix+"."+propertyName;try{if(typeof obj2[propertyName]=="undefined"){throw new Error(obj2_name+" does not contain "+propertyFullyQualifiedName+" in "+obj1_name);}else if(typeof obj2[propertyName]!=typeof obj1[propertyName]){throw new Error(obj2_name+"'s "+propertyFullyQualifiedName+" is of the wrong type: "+typeof obj2[propertyName]+" when it is type "+typeof obj1[propertyName]+" in "+obj1_name);}else if(obj1[propertyName]!=Function.prototype.apply){if(!compareObjectInterface(obj1[propertyName],obj1_name,obj2[propertyName],obj2_name,propertyFullyQualifiedName)){throw new Error("Interfaces don't match");}}}catch(ex){throw new Error("Exception while checking property name "+propertyFullyQualifiedName+" in "+obj2_name+": "+ex.message);}}}

+return true;};var testLayoutWithVariables=function(layout,t){var emptyObject={};var emptyArray=[];var emptyString="";var localUndefined=emptyArray[0];var oneLevelObject={"name":"One-level object"};var twoLevelObject={"name":"Two-level object","data":oneLevelObject};var threeLevelObject={"name":"Three-level object","data":twoLevelObject};var anArray=[3,"stuff",true,false,0,null,localUndefined,3.14,function(p){return"I'm a function";},[1,"things"]];var arrayOfTestItems=[emptyObject,emptyString,emptyString,localUndefined,oneLevelObject,twoLevelObject,threeLevelObject,anArray];t.log("Testing layout "+layout)

+for(var i=0;i<arrayOfTestItems.length;i++){var ex=new Error("Test error");var loggingEvent=new log4javascript.LoggingEvent(t.logger,new Date(),log4javascript.Level.INFO,[arrayOfTestItems[i]],null);t.log("Formatting",arrayOfTestItems[i],result);var result=layout.format(loggingEvent);loggingEvent.exception=ex;t.log("Formatting with exception",arrayOfTestItems[i],result);result=layout.format(loggingEvent);}};xn.test.enableTestDebug=true;xn.test.enable_log4javascript=false;xn.test.suite("log4javascript tests",function(s){log4javascript.logLog.setQuietMode(true);var ArrayAppender=function(layout){if(layout){this.setLayout(layout);}

+this.logMessages=[];};ArrayAppender.prototype=new log4javascript.Appender();ArrayAppender.prototype.layout=new log4javascript.NullLayout();ArrayAppender.prototype.append=function(loggingEvent){var formattedMessage=this.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();}

+this.logMessages.push(formattedMessage);};ArrayAppender.prototype.toString=function(){return"[ArrayAppender]";};s.setUp=function(t){t.logger=log4javascript.getLogger("test");t.logger.removeAllAppenders();t.appender=new ArrayAppender();t.logger.addAppender(t.appender);};s.tearDown=function(t){t.logger.removeAppender(t.appender);log4javascript.resetConfiguration();};s.test("Stub script interface test",function(t){try{compareObjectInterface(log4javascript,"log4javascript",log4javascript_stub,"log4javascript_stub");}catch(ex){t.fail(ex);}});s.test("Disable log4javascript test",function(t){log4javascript.setEnabled(false);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,0);log4javascript.setEnabled(true);});s.test("Array.splice test 1",function(t){var a=["Marlon","Ashley","Darius","Lloyd"];var deletedItems=a.splice(1,2);t.assertEquals(a.join(","),"Marlon,Lloyd");t.assertEquals(deletedItems.join(","),"Ashley,Darius");});s.test("Array.splice test 2",function(t){var a=["Marlon","Ashley","Darius","Lloyd"];var deletedItems=a.splice(1,1,"Malky","Jay");t.assertEquals(a.join(","),"Marlon,Malky,Jay,Darius,Lloyd");t.assertEquals(deletedItems.join(","),"Ashley");});s.test("array_remove test",function(t){var array_remove=log4javascript.evalInScope("array_remove");var a=["Marlon","Ashley","Darius"];array_remove(a,"Darius");t.assertEquals(a.join(","),"Marlon,Ashley");});s.test("array_remove with empty array test",function(t){var array_remove=log4javascript.evalInScope("array_remove");var a=[];array_remove(a,"Darius");t.assertEquals(a.join(","),"");});s.test("Logger logging test",function(t){t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,1);});s.test("Logger levels test",function(t){var originalLevel=t.logger.getEffectiveLevel();t.logger.setLevel(log4javascript.Level.INFO);t.logger.debug("TEST");t.logger.setLevel(originalLevel);t.assertEquals(t.appender.logMessages.length,0);});s.test("Logger getEffectiveLevel inheritance test 1",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");parentLogger.setLevel(log4javascript.Level.ERROR);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.ERROR);});s.test("Logger getEffectiveLevel inheritance test 2",function(t){var grandParentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2.test3");grandParentLogger.setLevel(log4javascript.Level.ERROR);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.ERROR);});s.test("Logger getEffectiveLevel inheritance test 3",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");parentLogger.setLevel(log4javascript.Level.ERROR);childLogger.setLevel(log4javascript.Level.INFO);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.INFO);});s.test("Logger getEffectiveLevel root inheritance test",function(t){var rootLogger=log4javascript.getRootLogger();var childLogger=log4javascript.getLogger("test1.test2.test3");rootLogger.setLevel(log4javascript.Level.WARN);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.WARN);});s.test("Logger null level test",function(t){t.logger.setLevel(null);t.assertEquals(t.logger.getEffectiveLevel(),log4javascript.Level.DEBUG);});s.test("Logger appender additivity test 1",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");var parentLoggerAppender=new ArrayAppender();var childLoggerAppender=new ArrayAppender();parentLogger.addAppender(parentLoggerAppender);childLogger.addAppender(childLoggerAppender);parentLogger.info("Parent logger test message");childLogger.info("Child logger test message");t.assertEquals(parentLoggerAppender.logMessages.length,2);t.assertEquals(childLoggerAppender.logMessages.length,1);});s.test("Logger appender additivity test 2",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");var parentLoggerAppender=new ArrayAppender();var childLoggerAppender=new ArrayAppender();parentLogger.addAppender(parentLoggerAppender);childLogger.addAppender(childLoggerAppender);childLogger.setAdditivity(false);parentLogger.info("Parent logger test message");childLogger.info("Child logger test message");t.assertEquals(parentLoggerAppender.logMessages.length,1);t.assertEquals(childLoggerAppender.logMessages.length,1);});s.test("Logger appender additivity test 3",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");var parentLoggerAppender=new ArrayAppender();var childLoggerAppender=new ArrayAppender();parentLogger.addAppender(parentLoggerAppender);childLogger.addAppender(childLoggerAppender);childLogger.setAdditivity(false);parentLogger.info("Parent logger test message");childLogger.info("Child logger test message");childLogger.setAdditivity(true);childLogger.info("Child logger test message 2");t.assertEquals(parentLoggerAppender.logMessages.length,2);t.assertEquals(childLoggerAppender.logMessages.length,2);});s.test("Appender threshold test",function(t){t.appender.setThreshold(log4javascript.Level.INFO);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,0);});s.test("Basic appender / layout test",function(t){t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"TEST");});s.test("Appender uniqueness within logger test",function(t){t.logger.addAppender(t.appender);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,1);});s.test("Logger remove appender test",function(t){t.logger.debug("TEST");t.logger.removeAppender(t.appender);t.logger.debug("TEST AGAIN");t.assertEquals(t.appender.logMessages.length,1);});s.test("",function(t){t.logger.debug("TEST");t.logger.removeAppender(t.appender);t.logger.debug("TEST AGAIN");t.assertEquals(t.appender.logMessages.length,1);});s.test("SimpleLayout format test",function(t){var layout=new log4javascript.SimpleLayout();testLayoutWithVariables(layout,t);});s.test("SimpleLayout test",function(t){t.appender.setLayout(new log4javascript.SimpleLayout());t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"DEBUG - TEST");});s.test("NullLayout format test",function(t){var layout=new log4javascript.NullLayout();testLayoutWithVariables(layout,t);});s.test("NullLayout test",function(t){t.appender.setLayout(new log4javascript.NullLayout());t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"TEST");});s.test("XmlLayout format test",function(t){var layout=new log4javascript.XmlLayout();testLayoutWithVariables(layout,t);});s.test("XmlLayout test",function(t){t.appender.setLayout(new log4javascript.XmlLayout());t.logger.debug("TEST");t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<\/log4javascript:event>\s*$/,t.appender.logMessages[0]);});s.test("XmlLayout with exception test",function(t){t.appender.setLayout(new log4javascript.XmlLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<log4javascript:exception>\s*<!\[CDATA\[.*\]\]><\/log4javascript:exception>\s*<\/log4javascript:event>\s*$/,t.appender.logMessages[0]);});var setUpXmlLayoutMillisecondsTest=function(t){t.date=new Date();t.timeInMilliseconds=t.date.getTime();t.timeInSeconds=Math.floor(t.timeInMilliseconds/1000);t.milliseconds=t.date.getMilliseconds();t.loggingEvent=new log4javascript.LoggingEvent(t.logger,t.date,log4javascript.Level.DEBUG,["TEST"],null);t.layout=new log4javascript.XmlLayout();}

+s.test("XmlLayout seconds/milliseconds test 1",function(t){setUpXmlLayoutMillisecondsTest(t);var regex=new RegExp('^<log4javascript:event logger="test" timestamp="'+t.timeInMilliseconds+'" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');t.assertRegexMatches(regex,t.layout.format(t.loggingEvent));});s.test("XmlLayout seconds/milliseconds test 2",function(t){setUpXmlLayoutMillisecondsTest(t);log4javascript.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);log4javascript.setTimeStampsInMilliseconds(true);var regex=new RegExp('^<log4javascript:event logger="test" timestamp="'+t.timeInSeconds+'" milliseconds="'+t.milliseconds+'" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');t.assertRegexMatches(regex,formatted);});s.test("XmlLayout seconds/milliseconds test 3",function(t){setUpXmlLayoutMillisecondsTest(t);t.layout.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);var regex=new RegExp('^<log4javascript:event logger="test" timestamp="'+t.timeInSeconds+'" milliseconds="'+t.milliseconds+'" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');t.assertRegexMatches(regex,formatted);});s.test("escapeNewLines test",function(t){var escapeNewLines=log4javascript.evalInScope("escapeNewLines");var str="1\r2\n3\n4\r\n5\r6\r\n7";t.assertEquals(escapeNewLines(str),"1\\r\\n2\\r\\n3\\r\\n4\\r\\n5\\r\\n6\\r\\n7");});s.test("JsonLayout format test",function(t){var layout=new log4javascript.JsonLayout();testLayoutWithVariables(layout,t);});s.test("JsonLayout test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST");t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST"}$/,t.appender.logMessages[0]);});s.test("JsonLayout JSON validity test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST");eval("var o = "+t.appender.logMessages[0]);t.assertEquals(o.message,"TEST");});s.test("JsonLayout with number type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug(15);t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":15}$/,t.appender.logMessages[0]);});s.test("JsonLayout with object type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug({});t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"\[object Object\]"}$/,t.appender.logMessages[0]);});s.test("JsonLayout with boolean type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug(false);t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":false}$/,t.appender.logMessages[0]);});s.test("JsonLayout with quote test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TE\"S\"T");t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TE\\"S\\"T"}$/,t.appender.logMessages[0]);});s.test("JsonLayout with exception test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST","exception":.*}$/,t.appender.logMessages[0]);});var setUpJsonLayoutMillisecondsTest=function(t){t.date=new Date();t.timeInMilliseconds=t.date.getTime();t.timeInSeconds=Math.floor(t.timeInMilliseconds/1000);t.milliseconds=t.date.getMilliseconds();t.loggingEvent=new log4javascript.LoggingEvent(t.logger,t.date,log4javascript.Level.DEBUG,["TEST"],null);t.layout=new log4javascript.JsonLayout();};s.test("JsonLayout seconds/milliseconds test 1",function(t){setUpJsonLayoutMillisecondsTest(t);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInMilliseconds+',"level":"DEBUG","url":".*","message":"TEST"}$');t.assertRegexMatches(regex,t.layout.format(t.loggingEvent));});s.test("JsonLayout seconds/milliseconds test 2",function(t){setUpJsonLayoutMillisecondsTest(t);log4javascript.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);log4javascript.setTimeStampsInMilliseconds(true);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInSeconds+',"level":"DEBUG","url":".*","message":"TEST","milliseconds":'+t.milliseconds+'}$');t.assertRegexMatches(regex,formatted);});s.test("JsonLayout seconds/milliseconds test 3",function(t){setUpJsonLayoutMillisecondsTest(t);t.layout.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInSeconds+',"level":"DEBUG","url":".*","message":"TEST","milliseconds":'+t.milliseconds+'}$');t.assertRegexMatches(regex,formatted);});s.test("HttpPostDataLayout format test",function(t){var layout=new log4javascript.HttpPostDataLayout();testLayoutWithVariables(layout,t);});s.test("HttpPostDataLayout test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST");t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST$/,t.appender.logMessages[0]);});s.test("HttpPostDataLayout URL encoding test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST +\"1\"");t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST%20%2B%221%22$/,t.appender.logMessages[0]);});s.test("HttpPostDataLayout with exception test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST&exception=.*$/,t.appender.logMessages[0]);});(function(){var formatObjectExpansion=log4javascript.evalInScope("formatObjectExpansion");var newLine=log4javascript.evalInScope("newLine");var arr=[null,undefined,1.2,"A string",[1,"test"],{a:{b:1}}];s.test("Basic formatObjectExpansion array test (depth: 1)",function(t){t.assertEquals(formatObjectExpansion(arr,1),"["+newLine+"  null,"+newLine+"  undefined,"+newLine+"  1.2,"+newLine+"  A string,"+newLine+"  1,test,"+newLine+"  [object Object]"+newLine+"]");});s.test("Basic formatObjectExpansion array test (depth: 2)",function(t){t.assertEquals(formatObjectExpansion(arr,2),"["+newLine+"  null,"+newLine+"  undefined,"+newLine+"  1.2,"+newLine+"  A string,"+newLine+"  ["+newLine+"    1,"+newLine+"    test"+newLine+"  ],"+newLine+"  {"+newLine+"    a: [object Object]"+newLine+"  }"+newLine+"]");});s.test("formatObjectExpansion simple object test",function(t){var obj={STRING:"A string"};t.assertEquals(formatObjectExpansion(obj,1),"{"+newLine+"  STRING: A string"+newLine+"}");});s.test("formatObjectExpansion simple circular object test",function(t){var obj={};obj.a=obj;t.assertEquals(formatObjectExpansion(obj,2),"{"+newLine+"  a: [object Object] [already expanded]"+newLine+"}");});})();var getSampleDate=function(){var date=new Date();date.setFullYear(2006);date.setMonth(7);date.setDate(30);date.setHours(15);date.setMinutes(38);date.setSeconds(45);return date;};s.test("String.replace test",function(t){t.assertEquals("Hello world".replace(/o/g,"Z"),"HellZ wZrld");});s.test("PatternLayout format test",function(t){var layout=new log4javascript.PatternLayout();testLayoutWithVariables(layout,t);});s.test("PatternLayout dates test",function(t){var layout=new log4javascript.PatternLayout("%d %d{DATE} %d{HH:ss}");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertRegexMatches(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2},\d{3} \d{2}:\d{2}$/,t.appender.logMessages[0]);});s.test("PatternLayout modifiers test",function(t){var layout=new log4javascript.PatternLayout("%m|%3m|%-3m|%6m|%-6m|%.2m|%1.2m|%6.8m|%-1.2m|%-6.8m|");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"TEST|TEST|TEST|  TEST|TEST  |ST|ST|  TEST|ST|TEST  |");});s.test("PatternLayout conversion characters test",function(t){var layout=new log4javascript.PatternLayout("%c %n %p %r literal %%");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertRegexMatches(/^test \s+ DEBUG \d+ literal %$/,t.appender.logMessages[0]);});s.test("PatternLayout message test",function(t){var layout=new log4javascript.PatternLayout("%m{1} %m{2}");t.appender.setLayout(layout);var testObj={strikers:{quick:"Marlon"}};t.logger.debug(testObj);t.assertEquals("{\r\n  strikers: [object Object]\r\n} {\r\n\  strikers: {\r\n    quick: Marlon\r\n  }\r\n}",t.appender.logMessages[0]);});s.test("Logging/grouping test",function(t){var browserConsoleAppender=new log4javascript.BrowserConsoleAppender();t.logger.addAppender(browserConsoleAppender);t.logger.trace("TEST TRACE");t.logger.debug("TEST DEBUG");t.logger.info("TEST INFO");t.logger.warn("TEST WARN");t.logger.error("TEST ERROR");t.logger.fatal("TEST FATAL");t.logger.fatal("TEST FATAL",new Error("Fake error"));t.logger.info("TEST INFO","Second message",["a","b","c"]);t.logger.group("TEST GROUP");t.logger.info("TEST INFO");t.logger.groupEnd("TEST GROUP");t.logger.info("TEST INFO");t.logger.removeAppender(browserConsoleAppender);});var testConsoleAppender=function(t,appender){var timeoutCallback=function(){return(windowLoaded?"Timed out while waiting for messages to appear":"Timed out while waiting for window to load")+". Debug messages: "+

+log4javascript.logLog.debugMessages.join("\r\n");}

+t.async(60000,timeoutCallback);var windowLoaded=false;var domChecked=false;var onLoadHandler=function(){log4javascript.logLog.debug("onLoadHandler");windowLoaded=true;var win=appender.getConsoleWindow();if(win&&win.loaded){var checkDom=function(){log4javascript.logLog.debug("checkDom");domChecked=true;var logContainer=win.logMainContainer;if(logContainer.hasChildNodes()){if(logContainer.innerHTML.indexOf("TEST MESSAGE")==-1){appender.close();t.fail("Log message not correctly logged (log container innerHTML: "+logContainer.innerHTML+")");}else{t.assert(appender.isVisible());appender.close();t.assert(!appender.isVisible());t.succeed();}}else{appender.close();t.fail("Console has no log messages");}}

+window.setTimeout(checkDom,300);}else{appender.close();t.fail("Console mistakenly raised load event");}}

+appender.addEventListener("load",onLoadHandler);t.logger.addAppender(appender);t.logger.debug("TEST MESSAGE");};s.test("InlineAppender test",function(t){var inlineAppender=new log4javascript.InlineAppender();inlineAppender.setInitiallyMinimized(false);inlineAppender.setNewestMessageAtTop(false);inlineAppender.setScrollToLatestMessage(true);inlineAppender.setWidth(600);inlineAppender.setHeight(200);testConsoleAppender(t,inlineAppender);});s.test("InPageAppender with separate console HTML file test",function(t){var inPageAppender=new log4javascript.InPageAppender();inPageAppender.setInitiallyMinimized(false);inPageAppender.setNewestMessageAtTop(false);inPageAppender.setScrollToLatestMessage(true);inPageAppender.setUseDocumentWrite(false);inPageAppender.setWidth(600);inPageAppender.setHeight(200);testConsoleAppender(t,inPageAppender);});s.test("PopUpAppender test",function(t){var popUpAppender=new log4javascript.PopUpAppender();popUpAppender.setFocusPopUp(true);popUpAppender.setUseOldPopUp(false);popUpAppender.setNewestMessageAtTop(false);popUpAppender.setScrollToLatestMessage(true);popUpAppender.setComplainAboutPopUpBlocking(false);popUpAppender.setWidth(600);popUpAppender.setHeight(200);testConsoleAppender(t,popUpAppender);});s.test("PopUpAppender with separate console HTML file test",function(t){var popUpAppender=new log4javascript.PopUpAppender();popUpAppender.setFocusPopUp(true);popUpAppender.setUseOldPopUp(false);popUpAppender.setNewestMessageAtTop(false);popUpAppender.setScrollToLatestMessage(true);popUpAppender.setComplainAboutPopUpBlocking(false);popUpAppender.setUseDocumentWrite(false);popUpAppender.setWidth(600);popUpAppender.setHeight(200);testConsoleAppender(t,popUpAppender);});});

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite.js b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite.js
new file mode 100644
index 0000000..b9eb6b7
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite.js
@@ -0,0 +1,16 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite_uncompressed.js
new file mode 100644
index 0000000..b9eb6b7
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite_uncompressed.js
@@ -0,0 +1,16 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_production.js b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_production.js
new file mode 100644
index 0000000..f5d1090
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_production.js
@@ -0,0 +1,28 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+function array_contains(arr,val){for(var i=0;i<arr.length;i++){if(arr[i]==val){return true;}}

+return false;}

+function compareObjectInterface(obj1,obj1_name,obj2,obj2_name,namePrefix){if(!namePrefix){namePrefix="";}

+var obj1PropertyNames=new Array();for(var i in obj1){if(i!="prototype"&&i!="arguments"){obj1PropertyNames.push(i);}}

+if(obj1&&obj1.prototype&&!array_contains(obj1PropertyNames,"prototype")){}

+for(var j=0;j<obj1PropertyNames.length;j++){var propertyName=obj1PropertyNames[j];if((typeof obj1[propertyName]=="function"||typeof obj1[propertyName]=="object")&&!(obj1[propertyName]instanceof Array)){var propertyFullyQualifiedName=(namePrefix=="")?propertyName:namePrefix+"."+propertyName;try{if(typeof obj2[propertyName]=="undefined"){throw new Error(obj2_name+" does not contain "+propertyFullyQualifiedName+" in "+obj1_name);}else if(typeof obj2[propertyName]!=typeof obj1[propertyName]){throw new Error(obj2_name+"'s "+propertyFullyQualifiedName+" is of the wrong type: "+typeof obj2[propertyName]+" when it is type "+typeof obj1[propertyName]+" in "+obj1_name);}else if(obj1[propertyName]!=Function.prototype.apply){if(!compareObjectInterface(obj1[propertyName],obj1_name,obj2[propertyName],obj2_name,propertyFullyQualifiedName)){throw new Error("Interfaces don't match");}}}catch(ex){throw new Error("Exception while checking property name "+propertyFullyQualifiedName+" in "+obj2_name+": "+ex.message);}}}

+return true;};var testLayoutWithVariables=function(layout,t){var emptyObject={};var emptyArray=[];var emptyString="";var localUndefined=emptyArray[0];var oneLevelObject={"name":"One-level object"};var twoLevelObject={"name":"Two-level object","data":oneLevelObject};var threeLevelObject={"name":"Three-level object","data":twoLevelObject};var anArray=[3,"stuff",true,false,0,null,localUndefined,3.14,function(p){return"I'm a function";},[1,"things"]];var arrayOfTestItems=[emptyObject,emptyString,emptyString,localUndefined,oneLevelObject,twoLevelObject,threeLevelObject,anArray];t.log("Testing layout "+layout)

+for(var i=0;i<arrayOfTestItems.length;i++){var ex=new Error("Test error");var loggingEvent=new log4javascript.LoggingEvent(t.logger,new Date(),log4javascript.Level.INFO,[arrayOfTestItems[i]],null);t.log("Formatting",arrayOfTestItems[i],result);var result=layout.format(loggingEvent);loggingEvent.exception=ex;t.log("Formatting with exception",arrayOfTestItems[i],result);result=layout.format(loggingEvent);}};xn.test.enableTestDebug=true;xn.test.enable_log4javascript=false;xn.test.suite("log4javascript tests",function(s){log4javascript.logLog.setQuietMode(true);var ArrayAppender=function(layout){if(layout){this.setLayout(layout);}

+this.logMessages=[];};ArrayAppender.prototype=new log4javascript.Appender();ArrayAppender.prototype.layout=new log4javascript.NullLayout();ArrayAppender.prototype.append=function(loggingEvent){var formattedMessage=this.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();}

+this.logMessages.push(formattedMessage);};ArrayAppender.prototype.toString=function(){return"[ArrayAppender]";};s.setUp=function(t){t.logger=log4javascript.getLogger("test");t.logger.removeAllAppenders();t.appender=new ArrayAppender();t.logger.addAppender(t.appender);};s.tearDown=function(t){t.logger.removeAppender(t.appender);log4javascript.resetConfiguration();};s.test("Stub script interface test",function(t){try{compareObjectInterface(log4javascript,"log4javascript",log4javascript_stub,"log4javascript_stub");}catch(ex){t.fail(ex);}});s.test("Disable log4javascript test",function(t){log4javascript.setEnabled(false);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,0);log4javascript.setEnabled(true);});s.test("Array.splice test 1",function(t){var a=["Marlon","Ashley","Darius","Lloyd"];var deletedItems=a.splice(1,2);t.assertEquals(a.join(","),"Marlon,Lloyd");t.assertEquals(deletedItems.join(","),"Ashley,Darius");});s.test("Array.splice test 2",function(t){var a=["Marlon","Ashley","Darius","Lloyd"];var deletedItems=a.splice(1,1,"Malky","Jay");t.assertEquals(a.join(","),"Marlon,Malky,Jay,Darius,Lloyd");t.assertEquals(deletedItems.join(","),"Ashley");});s.test("array_remove test",function(t){var array_remove=log4javascript.evalInScope("array_remove");var a=["Marlon","Ashley","Darius"];array_remove(a,"Darius");t.assertEquals(a.join(","),"Marlon,Ashley");});s.test("array_remove with empty array test",function(t){var array_remove=log4javascript.evalInScope("array_remove");var a=[];array_remove(a,"Darius");t.assertEquals(a.join(","),"");});s.test("Logger logging test",function(t){t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,1);});s.test("Logger levels test",function(t){var originalLevel=t.logger.getEffectiveLevel();t.logger.setLevel(log4javascript.Level.INFO);t.logger.debug("TEST");t.logger.setLevel(originalLevel);t.assertEquals(t.appender.logMessages.length,0);});s.test("Logger getEffectiveLevel inheritance test 1",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");parentLogger.setLevel(log4javascript.Level.ERROR);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.ERROR);});s.test("Logger getEffectiveLevel inheritance test 2",function(t){var grandParentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2.test3");grandParentLogger.setLevel(log4javascript.Level.ERROR);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.ERROR);});s.test("Logger getEffectiveLevel inheritance test 3",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");parentLogger.setLevel(log4javascript.Level.ERROR);childLogger.setLevel(log4javascript.Level.INFO);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.INFO);});s.test("Logger getEffectiveLevel root inheritance test",function(t){var rootLogger=log4javascript.getRootLogger();var childLogger=log4javascript.getLogger("test1.test2.test3");rootLogger.setLevel(log4javascript.Level.WARN);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.WARN);});s.test("Logger null level test",function(t){t.logger.setLevel(null);t.assertEquals(t.logger.getEffectiveLevel(),log4javascript.Level.DEBUG);});s.test("Logger appender additivity test 1",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");var parentLoggerAppender=new ArrayAppender();var childLoggerAppender=new ArrayAppender();parentLogger.addAppender(parentLoggerAppender);childLogger.addAppender(childLoggerAppender);parentLogger.info("Parent logger test message");childLogger.info("Child logger test message");t.assertEquals(parentLoggerAppender.logMessages.length,2);t.assertEquals(childLoggerAppender.logMessages.length,1);});s.test("Logger appender additivity test 2",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");var parentLoggerAppender=new ArrayAppender();var childLoggerAppender=new ArrayAppender();parentLogger.addAppender(parentLoggerAppender);childLogger.addAppender(childLoggerAppender);childLogger.setAdditivity(false);parentLogger.info("Parent logger test message");childLogger.info("Child logger test message");t.assertEquals(parentLoggerAppender.logMessages.length,1);t.assertEquals(childLoggerAppender.logMessages.length,1);});s.test("Logger appender additivity test 3",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");var parentLoggerAppender=new ArrayAppender();var childLoggerAppender=new ArrayAppender();parentLogger.addAppender(parentLoggerAppender);childLogger.addAppender(childLoggerAppender);childLogger.setAdditivity(false);parentLogger.info("Parent logger test message");childLogger.info("Child logger test message");childLogger.setAdditivity(true);childLogger.info("Child logger test message 2");t.assertEquals(parentLoggerAppender.logMessages.length,2);t.assertEquals(childLoggerAppender.logMessages.length,2);});s.test("Appender threshold test",function(t){t.appender.setThreshold(log4javascript.Level.INFO);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,0);});s.test("Basic appender / layout test",function(t){t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"TEST");});s.test("Appender uniqueness within logger test",function(t){t.logger.addAppender(t.appender);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,1);});s.test("Logger remove appender test",function(t){t.logger.debug("TEST");t.logger.removeAppender(t.appender);t.logger.debug("TEST AGAIN");t.assertEquals(t.appender.logMessages.length,1);});s.test("",function(t){t.logger.debug("TEST");t.logger.removeAppender(t.appender);t.logger.debug("TEST AGAIN");t.assertEquals(t.appender.logMessages.length,1);});s.test("SimpleLayout format test",function(t){var layout=new log4javascript.SimpleLayout();testLayoutWithVariables(layout,t);});s.test("SimpleLayout test",function(t){t.appender.setLayout(new log4javascript.SimpleLayout());t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"DEBUG - TEST");});s.test("NullLayout format test",function(t){var layout=new log4javascript.NullLayout();testLayoutWithVariables(layout,t);});s.test("NullLayout test",function(t){t.appender.setLayout(new log4javascript.NullLayout());t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"TEST");});s.test("XmlLayout format test",function(t){var layout=new log4javascript.XmlLayout();testLayoutWithVariables(layout,t);});s.test("XmlLayout test",function(t){t.appender.setLayout(new log4javascript.XmlLayout());t.logger.debug("TEST");t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<\/log4javascript:event>\s*$/,t.appender.logMessages[0]);});s.test("XmlLayout with exception test",function(t){t.appender.setLayout(new log4javascript.XmlLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<log4javascript:exception>\s*<!\[CDATA\[.*\]\]><\/log4javascript:exception>\s*<\/log4javascript:event>\s*$/,t.appender.logMessages[0]);});var setUpXmlLayoutMillisecondsTest=function(t){t.date=new Date();t.timeInMilliseconds=t.date.getTime();t.timeInSeconds=Math.floor(t.timeInMilliseconds/1000);t.milliseconds=t.date.getMilliseconds();t.loggingEvent=new log4javascript.LoggingEvent(t.logger,t.date,log4javascript.Level.DEBUG,["TEST"],null);t.layout=new log4javascript.XmlLayout();}

+s.test("XmlLayout seconds/milliseconds test 1",function(t){setUpXmlLayoutMillisecondsTest(t);var regex=new RegExp('^<log4javascript:event logger="test" timestamp="'+t.timeInMilliseconds+'" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');t.assertRegexMatches(regex,t.layout.format(t.loggingEvent));});s.test("XmlLayout seconds/milliseconds test 2",function(t){setUpXmlLayoutMillisecondsTest(t);log4javascript.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);log4javascript.setTimeStampsInMilliseconds(true);var regex=new RegExp('^<log4javascript:event logger="test" timestamp="'+t.timeInSeconds+'" milliseconds="'+t.milliseconds+'" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');t.assertRegexMatches(regex,formatted);});s.test("XmlLayout seconds/milliseconds test 3",function(t){setUpXmlLayoutMillisecondsTest(t);t.layout.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);var regex=new RegExp('^<log4javascript:event logger="test" timestamp="'+t.timeInSeconds+'" milliseconds="'+t.milliseconds+'" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');t.assertRegexMatches(regex,formatted);});s.test("escapeNewLines test",function(t){var escapeNewLines=log4javascript.evalInScope("escapeNewLines");var str="1\r2\n3\n4\r\n5\r6\r\n7";t.assertEquals(escapeNewLines(str),"1\\r\\n2\\r\\n3\\r\\n4\\r\\n5\\r\\n6\\r\\n7");});s.test("JsonLayout format test",function(t){var layout=new log4javascript.JsonLayout();testLayoutWithVariables(layout,t);});s.test("JsonLayout test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST");t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST"}$/,t.appender.logMessages[0]);});s.test("JsonLayout JSON validity test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST");eval("var o = "+t.appender.logMessages[0]);t.assertEquals(o.message,"TEST");});s.test("JsonLayout with number type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug(15);t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":15}$/,t.appender.logMessages[0]);});s.test("JsonLayout with object type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug({});t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"\[object Object\]"}$/,t.appender.logMessages[0]);});s.test("JsonLayout with boolean type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug(false);t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":false}$/,t.appender.logMessages[0]);});s.test("JsonLayout with quote test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TE\"S\"T");t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TE\\"S\\"T"}$/,t.appender.logMessages[0]);});s.test("JsonLayout with exception test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST","exception":.*}$/,t.appender.logMessages[0]);});var setUpJsonLayoutMillisecondsTest=function(t){t.date=new Date();t.timeInMilliseconds=t.date.getTime();t.timeInSeconds=Math.floor(t.timeInMilliseconds/1000);t.milliseconds=t.date.getMilliseconds();t.loggingEvent=new log4javascript.LoggingEvent(t.logger,t.date,log4javascript.Level.DEBUG,["TEST"],null);t.layout=new log4javascript.JsonLayout();};s.test("JsonLayout seconds/milliseconds test 1",function(t){setUpJsonLayoutMillisecondsTest(t);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInMilliseconds+',"level":"DEBUG","url":".*","message":"TEST"}$');t.assertRegexMatches(regex,t.layout.format(t.loggingEvent));});s.test("JsonLayout seconds/milliseconds test 2",function(t){setUpJsonLayoutMillisecondsTest(t);log4javascript.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);log4javascript.setTimeStampsInMilliseconds(true);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInSeconds+',"level":"DEBUG","url":".*","message":"TEST","milliseconds":'+t.milliseconds+'}$');t.assertRegexMatches(regex,formatted);});s.test("JsonLayout seconds/milliseconds test 3",function(t){setUpJsonLayoutMillisecondsTest(t);t.layout.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInSeconds+',"level":"DEBUG","url":".*","message":"TEST","milliseconds":'+t.milliseconds+'}$');t.assertRegexMatches(regex,formatted);});s.test("HttpPostDataLayout format test",function(t){var layout=new log4javascript.HttpPostDataLayout();testLayoutWithVariables(layout,t);});s.test("HttpPostDataLayout test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST");t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST$/,t.appender.logMessages[0]);});s.test("HttpPostDataLayout URL encoding test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST +\"1\"");t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST%20%2B%221%22$/,t.appender.logMessages[0]);});s.test("HttpPostDataLayout with exception test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST&exception=.*$/,t.appender.logMessages[0]);});(function(){var formatObjectExpansion=log4javascript.evalInScope("formatObjectExpansion");var newLine=log4javascript.evalInScope("newLine");var arr=[null,undefined,1.2,"A string",[1,"test"],{a:{b:1}}];s.test("Basic formatObjectExpansion array test (depth: 1)",function(t){t.assertEquals(formatObjectExpansion(arr,1),"["+newLine+"  null,"+newLine+"  undefined,"+newLine+"  1.2,"+newLine+"  A string,"+newLine+"  1,test,"+newLine+"  [object Object]"+newLine+"]");});s.test("Basic formatObjectExpansion array test (depth: 2)",function(t){t.assertEquals(formatObjectExpansion(arr,2),"["+newLine+"  null,"+newLine+"  undefined,"+newLine+"  1.2,"+newLine+"  A string,"+newLine+"  ["+newLine+"    1,"+newLine+"    test"+newLine+"  ],"+newLine+"  {"+newLine+"    a: [object Object]"+newLine+"  }"+newLine+"]");});s.test("formatObjectExpansion simple object test",function(t){var obj={STRING:"A string"};t.assertEquals(formatObjectExpansion(obj,1),"{"+newLine+"  STRING: A string"+newLine+"}");});s.test("formatObjectExpansion simple circular object test",function(t){var obj={};obj.a=obj;t.assertEquals(formatObjectExpansion(obj,2),"{"+newLine+"  a: [object Object] [already expanded]"+newLine+"}");});})();var getSampleDate=function(){var date=new Date();date.setFullYear(2006);date.setMonth(7);date.setDate(30);date.setHours(15);date.setMinutes(38);date.setSeconds(45);return date;};s.test("String.replace test",function(t){t.assertEquals("Hello world".replace(/o/g,"Z"),"HellZ wZrld");});s.test("PatternLayout format test",function(t){var layout=new log4javascript.PatternLayout();testLayoutWithVariables(layout,t);});s.test("PatternLayout dates test",function(t){var layout=new log4javascript.PatternLayout("%d %d{DATE} %d{HH:ss}");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertRegexMatches(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2},\d{3} \d{2}:\d{2}$/,t.appender.logMessages[0]);});s.test("PatternLayout modifiers test",function(t){var layout=new log4javascript.PatternLayout("%m|%3m|%-3m|%6m|%-6m|%.2m|%1.2m|%6.8m|%-1.2m|%-6.8m|");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"TEST|TEST|TEST|  TEST|TEST  |ST|ST|  TEST|ST|TEST  |");});s.test("PatternLayout conversion characters test",function(t){var layout=new log4javascript.PatternLayout("%c %n %p %r literal %%");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertRegexMatches(/^test \s+ DEBUG \d+ literal %$/,t.appender.logMessages[0]);});s.test("PatternLayout message test",function(t){var layout=new log4javascript.PatternLayout("%m{1} %m{2}");t.appender.setLayout(layout);var testObj={strikers:{quick:"Marlon"}};t.logger.debug(testObj);t.assertEquals("{\r\n  strikers: [object Object]\r\n} {\r\n\  strikers: {\r\n    quick: Marlon\r\n  }\r\n}",t.appender.logMessages[0]);});});

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_production_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_production_uncompressed.js
new file mode 100644
index 0000000..e64990f
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_production_uncompressed.js
@@ -0,0 +1,728 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+function array_contains(arr, val) {

+	for (var i = 0; i < arr.length; i++) {

+		if (arr[i] == val) {

+			return true;

+		}

+	}

+	return false;

+}

+

+// Recursively checks that obj2's interface contains all of obj1's

+// interface (functions and objects only)

+function compareObjectInterface(obj1, obj1_name, obj2, obj2_name, namePrefix) {

+	if (!namePrefix) {

+		namePrefix = "";

+	}

+	var obj1PropertyNames = new Array();

+	for (var i in obj1) {

+		if (i != "prototype" && i != "arguments") {

+			obj1PropertyNames.push(i);

+		}

+	}

+	if (obj1 && obj1.prototype && !array_contains(obj1PropertyNames, "prototype")) {

+		//obj1PropertyNames.push("prototype");

+	}

+	for (var j = 0; j < obj1PropertyNames.length; j++) {

+		var propertyName = obj1PropertyNames[j];

+		if ((typeof obj1[propertyName] == "function" || typeof obj1[propertyName] == "object") && !(obj1[propertyName] instanceof Array)) {

+			var propertyFullyQualifiedName = (namePrefix == "") ? propertyName : namePrefix + "." + propertyName;

+			try {

+				if (typeof obj2[propertyName] == "undefined") {

+					throw new Error(obj2_name + " does not contain " + propertyFullyQualifiedName + " in " + obj1_name);

+				} else if (typeof obj2[propertyName] != typeof obj1[propertyName]){

+					throw new Error(obj2_name + "'s " + propertyFullyQualifiedName + " is of the wrong type: " + typeof obj2[propertyName] + " when it is type " + typeof obj1[propertyName] + " in " + obj1_name);

+				} else if (obj1[propertyName] != Function.prototype.apply) {

+					if (!compareObjectInterface(obj1[propertyName], obj1_name, obj2[propertyName], obj2_name, propertyFullyQualifiedName)) {

+						throw new Error("Interfaces don't match");

+					}

+				}

+			} catch(ex) {

+				throw new Error("Exception while checking property name " + propertyFullyQualifiedName + " in " + obj2_name + ": " + ex.message);

+			}

+		}

+	}

+	return true;

+};

+

+// Simply tests a layout for exceptions when formatting

+var testLayoutWithVariables = function(layout, t) {

+	var emptyObject = {};

+	var emptyArray = [];

+	var emptyString = "";

+	var localUndefined = emptyArray[0];

+	var oneLevelObject = {

+		"name": "One-level object"

+	};

+	var twoLevelObject = {

+		"name": "Two-level object",

+		"data": oneLevelObject

+	};

+	var threeLevelObject = {

+		"name": "Three-level object",

+		"data": twoLevelObject

+	};

+	var anArray = [

+		3,

+		"stuff",

+		true,

+		false,

+		0,

+		null,

+		localUndefined,

+		3.14,

+		function(p) { return "I'm a function"; },

+		[1, "things"]

+	];

+	var arrayOfTestItems = [emptyObject, emptyString, emptyString, localUndefined, oneLevelObject,

+			twoLevelObject, threeLevelObject, anArray];

+

+	t.log("Testing layout " + layout)

+	for (var i = 0; i < arrayOfTestItems.length; i++) {

+		var ex = new Error("Test error");

+		var loggingEvent = new log4javascript.LoggingEvent(t.logger, new Date(), log4javascript.Level.INFO,

+				[arrayOfTestItems[i]], null);

+		t.log("Formatting", arrayOfTestItems[i], result);

+		var result = layout.format(loggingEvent);

+		// Now try with an exception

+		loggingEvent.exception = ex;

+		t.log("Formatting with exception", arrayOfTestItems[i], result);

+		result = layout.format(loggingEvent);

+	}

+};

+

+xn.test.enableTestDebug = true;

+xn.test.enable_log4javascript = false;

+

+xn.test.suite("log4javascript tests", function(s) {

+	log4javascript.logLog.setQuietMode(true);

+	var ArrayAppender = function(layout) {

+		if (layout) {

+			this.setLayout(layout);

+		}

+		this.logMessages = [];

+	};

+

+	ArrayAppender.prototype = new log4javascript.Appender();

+

+	ArrayAppender.prototype.layout = new log4javascript.NullLayout();

+

+	ArrayAppender.prototype.append = function(loggingEvent) {

+		var formattedMessage = this.getLayout().format(loggingEvent);

+		if (this.getLayout().ignoresThrowable()) {

+			formattedMessage += loggingEvent.getThrowableStrRep();

+		}

+		this.logMessages.push(formattedMessage);

+	};

+

+	ArrayAppender.prototype.toString = function() {

+		return "[ArrayAppender]";

+	};

+

+    s.setUp = function(t) {

+        t.logger = log4javascript.getLogger("test");

+		t.logger.removeAllAppenders();

+		t.appender = new ArrayAppender();

+        t.logger.addAppender(t.appender);

+    };

+

+    s.tearDown = function(t) {

+        t.logger.removeAppender(t.appender);

+		log4javascript.resetConfiguration();

+	};

+

+    s.test("Stub script interface test", function(t) {

+        try {

+            compareObjectInterface(log4javascript, "log4javascript", log4javascript_stub, "log4javascript_stub");

+        } catch (ex) {

+            t.fail(ex);

+        }

+    });

+

+	s.test("Disable log4javascript test", function(t) {

+		log4javascript.setEnabled(false);

+		t.logger.debug("TEST");

+		t.assertEquals(t.appender.logMessages.length, 0);

+		log4javascript.setEnabled(true);

+	});

+

+    s.test("Array.splice test 1", function(t) {

+        var a = ["Marlon", "Ashley", "Darius", "Lloyd"];

+        var deletedItems = a.splice(1, 2);

+        t.assertEquals(a.join(","), "Marlon,Lloyd");

+        t.assertEquals(deletedItems.join(","), "Ashley,Darius");

+    });

+

+    s.test("Array.splice test 2", function(t) {

+        var a = ["Marlon", "Ashley", "Darius", "Lloyd"];

+        var deletedItems = a.splice(1, 1, "Malky", "Jay");

+        t.assertEquals(a.join(","), "Marlon,Malky,Jay,Darius,Lloyd");

+        t.assertEquals(deletedItems.join(","), "Ashley");

+    });

+

+    s.test("array_remove test", function(t) {

+        var array_remove = log4javascript.evalInScope("array_remove");

+        var a = ["Marlon", "Ashley", "Darius"];

+        array_remove(a, "Darius");

+        t.assertEquals(a.join(","), "Marlon,Ashley");

+    });

+

+	s.test("array_remove with empty array test", function(t) {

+		var array_remove = log4javascript.evalInScope("array_remove");

+		var a = [];

+		array_remove(a, "Darius");

+		t.assertEquals(a.join(","), "");

+	});

+

+    s.test("Logger logging test", function(t) {

+        // Should log since the default level for loggers is DEBUG and

+        // the default threshold for appenders is ALL

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages.length, 1);

+    });

+

+    s.test("Logger levels test", function(t) {

+        var originalLevel = t.logger.getEffectiveLevel();

+        t.logger.setLevel(log4javascript.Level.INFO);

+        t.logger.debug("TEST");

+		t.logger.setLevel(originalLevel);

+        t.assertEquals(t.appender.logMessages.length, 0);

+    });

+

+	s.test("Logger getEffectiveLevel inheritance test 1", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		parentLogger.setLevel(log4javascript.Level.ERROR);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.ERROR);

+	});

+

+	s.test("Logger getEffectiveLevel inheritance test 2", function(t) {

+		var grandParentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2.test3");

+		grandParentLogger.setLevel(log4javascript.Level.ERROR);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.ERROR);

+	});

+

+	s.test("Logger getEffectiveLevel inheritance test 3", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		parentLogger.setLevel(log4javascript.Level.ERROR);

+		childLogger.setLevel(log4javascript.Level.INFO);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.INFO);

+	});

+

+	s.test("Logger getEffectiveLevel root inheritance test", function(t) {

+		var rootLogger = log4javascript.getRootLogger();

+		var childLogger = log4javascript.getLogger("test1.test2.test3");

+		rootLogger.setLevel(log4javascript.Level.WARN);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.WARN);

+	});

+

+	s.test("Logger null level test", function(t) {

+		t.logger.setLevel(null);

+		// Should default to root logger level, which is DEBUG

+		t.assertEquals(t.logger.getEffectiveLevel(), log4javascript.Level.DEBUG);

+	});

+

+	s.test("Logger appender additivity test 1", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		var parentLoggerAppender = new ArrayAppender();

+		var childLoggerAppender = new ArrayAppender();

+

+		parentLogger.addAppender(parentLoggerAppender);

+		childLogger.addAppender(childLoggerAppender);

+

+		parentLogger.info("Parent logger test message");

+		childLogger.info("Child logger test message");

+

+		t.assertEquals(parentLoggerAppender.logMessages.length, 2);

+		t.assertEquals(childLoggerAppender.logMessages.length, 1);

+	});

+

+	s.test("Logger appender additivity test 2", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		var parentLoggerAppender = new ArrayAppender();

+		var childLoggerAppender = new ArrayAppender();

+

+		parentLogger.addAppender(parentLoggerAppender);

+		childLogger.addAppender(childLoggerAppender);

+

+		childLogger.setAdditivity(false);

+

+		parentLogger.info("Parent logger test message");

+		childLogger.info("Child logger test message");

+

+		t.assertEquals(parentLoggerAppender.logMessages.length, 1);

+		t.assertEquals(childLoggerAppender.logMessages.length, 1);

+	});

+

+	s.test("Logger appender additivity test 3", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		var parentLoggerAppender = new ArrayAppender();

+		var childLoggerAppender = new ArrayAppender();

+

+		parentLogger.addAppender(parentLoggerAppender);

+		childLogger.addAppender(childLoggerAppender);

+

+		childLogger.setAdditivity(false);

+

+		parentLogger.info("Parent logger test message");

+		childLogger.info("Child logger test message");

+

+		childLogger.setAdditivity(true);

+

+		childLogger.info("Child logger test message 2");

+

+		t.assertEquals(parentLoggerAppender.logMessages.length, 2);

+		t.assertEquals(childLoggerAppender.logMessages.length, 2);

+	});

+

+	s.test("Appender threshold test", function(t) {

+        t.appender.setThreshold(log4javascript.Level.INFO);

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages.length, 0);

+    });

+

+    s.test("Basic appender / layout test", function(t) {

+        t.logger.debug("TEST");

+		t.assertEquals(t.appender.logMessages[0], "TEST");

+    });

+

+	s.test("Appender uniqueness within logger test", function(t) {

+		// Add the same appender to the logger for a second time

+		t.logger.addAppender(t.appender);

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages.length, 1);

+    });

+

+	s.test("Logger remove appender test", function(t) {

+		t.logger.debug("TEST");

+		t.logger.removeAppender(t.appender);

+		t.logger.debug("TEST AGAIN");

+		t.assertEquals(t.appender.logMessages.length, 1);

+	});

+

+	s.test("", function(t) {

+		t.logger.debug("TEST");

+		t.logger.removeAppender(t.appender);

+		t.logger.debug("TEST AGAIN");

+		t.assertEquals(t.appender.logMessages.length, 1);

+	});

+	s.test("SimpleLayout format test", function(t) {

+		var layout = new log4javascript.SimpleLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("SimpleLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.SimpleLayout());

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages[0], "DEBUG - TEST");

+    });

+	s.test("NullLayout format test", function(t) {

+		var layout = new log4javascript.NullLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("NullLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.NullLayout());

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages[0], "TEST");

+    });

+	s.test("XmlLayout format test", function(t) {

+		var layout = new log4javascript.XmlLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("XmlLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.XmlLayout());

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<\/log4javascript:event>\s*$/, t.appender.logMessages[0]);

+    });

+

+    s.test("XmlLayout with exception test", function(t) {

+        t.appender.setLayout(new log4javascript.XmlLayout());

+        t.logger.debug("TEST", new Error("Test error"));

+        t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<log4javascript:exception>\s*<!\[CDATA\[.*\]\]><\/log4javascript:exception>\s*<\/log4javascript:event>\s*$/, t.appender.logMessages[0]);

+    });

+

+	var setUpXmlLayoutMillisecondsTest = function(t) {

+		t.date = new Date();

+		t.timeInMilliseconds = t.date.getTime();

+		t.timeInSeconds = Math.floor(t.timeInMilliseconds / 1000);

+		t.milliseconds = t.date.getMilliseconds();

+		

+		t.loggingEvent = new log4javascript.LoggingEvent(t.logger, t.date, log4javascript.Level.DEBUG, ["TEST"], null);

+		t.layout = new log4javascript.XmlLayout();

+	}

+

+	s.test("XmlLayout seconds/milliseconds test 1", function(t) {

+		setUpXmlLayoutMillisecondsTest(t);

+

+		// Test default (i.e. timestamps in milliseconds) first

+        var regex = new RegExp('^<log4javascript:event logger="test" timestamp="' + t.timeInMilliseconds + '" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');

+        t.assertRegexMatches(regex, t.layout.format(t.loggingEvent));

+	});

+	

+	s.test("XmlLayout seconds/milliseconds test 2", function(t) {

+		setUpXmlLayoutMillisecondsTest(t);

+

+        // Change the global setting

+        log4javascript.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        log4javascript.setTimeStampsInMilliseconds(true);

+        var regex = new RegExp('^<log4javascript:event logger="test" timestamp="' + t.timeInSeconds + '" milliseconds="' + t.milliseconds + '" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');

+        t.assertRegexMatches(regex, formatted);

+	});

+

+	s.test("XmlLayout seconds/milliseconds test 3", function(t) {

+		setUpXmlLayoutMillisecondsTest(t);

+

+        // Change the layout setting

+        t.layout.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        var regex = new RegExp('^<log4javascript:event logger="test" timestamp="' + t.timeInSeconds + '" milliseconds="' + t.milliseconds + '" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');

+        t.assertRegexMatches(regex, formatted);

+	});

+	s.test("escapeNewLines test", function(t) {

+		var escapeNewLines = log4javascript.evalInScope("escapeNewLines");

+		var str = "1\r2\n3\n4\r\n5\r6\r\n7";

+		t.assertEquals(escapeNewLines(str), "1\\r\\n2\\r\\n3\\r\\n4\\r\\n5\\r\\n6\\r\\n7");

+	});

+

+	s.test("JsonLayout format test", function(t) {

+		var layout = new log4javascript.JsonLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("JsonLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST"}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout JSON validity test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TEST");

+        eval("var o = " + t.appender.logMessages[0]);

+        t.assertEquals(o.message, "TEST");

+    });

+

+    s.test("JsonLayout with number type message test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug(15);

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":15}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with object type message test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug({});

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"\[object Object\]"}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with boolean type message test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug(false);

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":false}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with quote test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TE\"S\"T");

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TE\\"S\\"T"}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with exception test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TEST", new Error("Test error"));

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST","exception":.*}$/, t.appender.logMessages[0]);

+    });

+

+	var setUpJsonLayoutMillisecondsTest = function(t) {

+		t.date = new Date();

+		t.timeInMilliseconds = t.date.getTime();

+		t.timeInSeconds = Math.floor(t.timeInMilliseconds / 1000);

+		t.milliseconds = t.date.getMilliseconds();

+		

+		t.loggingEvent = new log4javascript.LoggingEvent(t.logger, t.date, log4javascript.Level.DEBUG, ["TEST"], null);

+		t.layout = new log4javascript.JsonLayout();

+	};

+

+	s.test("JsonLayout seconds/milliseconds test 1", function(t) {

+		setUpJsonLayoutMillisecondsTest(t);

+

+		// Test default (i.e. timestamps in milliseconds) first

+        var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInMilliseconds + ',"level":"DEBUG","url":".*","message":"TEST"}$');

+        t.assertRegexMatches(regex, t.layout.format(t.loggingEvent));

+	});

+	

+	s.test("JsonLayout seconds/milliseconds test 2", function(t) {

+		setUpJsonLayoutMillisecondsTest(t);

+

+        // Change the global setting

+        log4javascript.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        log4javascript.setTimeStampsInMilliseconds(true);

+        var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInSeconds + ',"level":"DEBUG","url":".*","message":"TEST","milliseconds":' + t.milliseconds + '}$');

+        t.assertRegexMatches(regex, formatted);

+	});

+

+	s.test("JsonLayout seconds/milliseconds test 3", function(t) {

+		setUpJsonLayoutMillisecondsTest(t);

+

+        // Change the layout setting

+        t.layout.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInSeconds + ',"level":"DEBUG","url":".*","message":"TEST","milliseconds":' + t.milliseconds + '}$');

+        t.assertRegexMatches(regex, formatted);

+	});

+	s.test("HttpPostDataLayout format test", function(t) {

+		var layout = new log4javascript.HttpPostDataLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("HttpPostDataLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.HttpPostDataLayout());

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST$/, t.appender.logMessages[0]);

+    });

+

+    s.test("HttpPostDataLayout URL encoding test", function(t) {

+        t.appender.setLayout(new log4javascript.HttpPostDataLayout());

+        t.logger.debug("TEST +\"1\"");

+        t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST%20%2B%221%22$/, t.appender.logMessages[0]);

+    });

+

+    s.test("HttpPostDataLayout with exception test", function(t) {

+        t.appender.setLayout(new log4javascript.HttpPostDataLayout());

+        t.logger.debug("TEST", new Error("Test error"));

+        t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST&exception=.*$/, t.appender.logMessages[0]);

+    });

+

+	(function() {

+		var formatObjectExpansion = log4javascript.evalInScope("formatObjectExpansion");

+		var newLine = log4javascript.evalInScope("newLine");

+		var arr = [

+			null,

+			undefined,

+			1.2,

+			"A string",

+			[1, "test"],

+			{

+				a: {

+					b: 1

+				}

+			}

+		];

+

+		s.test("Basic formatObjectExpansion array test (depth: 1)", function(t) {

+			t.assertEquals(formatObjectExpansion(arr, 1),

+				"[" + newLine +

+				"  null," + newLine +

+				"  undefined," + newLine +

+				"  1.2," + newLine +

+				"  A string," + newLine +

+				"  1,test," + newLine +

+				"  [object Object]" + newLine +

+				"]"

+			);

+		});

+

+		s.test("Basic formatObjectExpansion array test (depth: 2)", function(t) {

+			t.assertEquals(formatObjectExpansion(arr, 2),

+				"[" + newLine +

+				"  null," + newLine +

+				"  undefined," + newLine +

+				"  1.2," + newLine +

+				"  A string," + newLine +

+				"  [" + newLine +

+				"    1," + newLine +

+				"    test" + newLine +

+				"  ]," + newLine +

+				"  {" + newLine +

+				"    a: [object Object]" + newLine +

+				"  }" + newLine +

+				"]"

+			);

+		});

+

+		s.test("formatObjectExpansion simple object test", function(t) {

+			var obj = {

+				STRING: "A string"

+			};

+			t.assertEquals(formatObjectExpansion(obj, 1), 

+				"{" + newLine +

+				"  STRING: A string" + newLine +

+				"}"

+			);

+		});

+

+		s.test("formatObjectExpansion simple circular object test", function(t) {

+			var obj = {};

+			obj.a = obj;

+			

+			t.assertEquals(formatObjectExpansion(obj, 2), 

+				"{" + newLine +

+				"  a: [object Object] [already expanded]" + newLine +

+				"}"

+			);

+		});

+	})();    /* ---------------------------------------------------------- */

+

+    var getSampleDate = function() {

+        var date = new Date();

+        date.setFullYear(2006);

+        date.setMonth(7);

+        date.setDate(30);

+        date.setHours(15);

+        date.setMinutes(38);

+        date.setSeconds(45);

+        return date;

+    };

+

+    /* ---------------------------------------------------------- */

+

+    s.test("String.replace test", function(t) {

+        t.assertEquals("Hello world".replace(/o/g, "Z"), "HellZ wZrld");

+    });

+

+	s.test("PatternLayout format test", function(t) {

+		var layout = new log4javascript.PatternLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("PatternLayout dates test", function(t) {

+        var layout = new log4javascript.PatternLayout("%d %d{DATE} %d{HH:ss}");

+        t.appender.setLayout(layout);

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2},\d{3} \d{2}:\d{2}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("PatternLayout modifiers test", function(t) {

+        var layout = new log4javascript.PatternLayout("%m|%3m|%-3m|%6m|%-6m|%.2m|%1.2m|%6.8m|%-1.2m|%-6.8m|");

+        t.appender.setLayout(layout);

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages[0], "TEST|TEST|TEST|  TEST|TEST  |ST|ST|  TEST|ST|TEST  |");

+    });

+

+    s.test("PatternLayout conversion characters test", function(t) {

+        var layout = new log4javascript.PatternLayout("%c %n %p %r literal %%");

+        t.appender.setLayout(layout);

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^test \s+ DEBUG \d+ literal %$/, t.appender.logMessages[0]);

+    });

+

+    s.test("PatternLayout message test", function(t) {

+        var layout = new log4javascript.PatternLayout("%m{1} %m{2}");

+        t.appender.setLayout(layout);

+        var testObj = {

+            strikers: {

+                quick: "Marlon"

+            }

+        };

+        t.logger.debug(testObj);

+        t.assertEquals("{\r\n  strikers: [object Object]\r\n} {\r\n\  strikers: {\r\n    quick: Marlon\r\n  }\r\n}", t.appender.logMessages[0]);

+    });

+/*

+	s.test("AjaxAppender JsonLayout single message test", function(t) {

+		t.async(10000);

+		// Create and add an Ajax appender

+		var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");

+		ajaxAppender.setLayout(new log4javascript.JsonLayout());

+		ajaxAppender.setRequestSuccessCallback(

+			function(xmlHttp) {

+				// Response comes back as JSON array of messages logged

+				var jsonResponse = xmlHttp.responseText;

+				var arr = eval(jsonResponse);

+				t.assertEquals(arr.length, 1);

+				t.assertEquals(arr[0], "TEST");

+				t.succeed();

+			}

+		);

+		ajaxAppender.setFailCallback(

+			function(msg) {

+				t.fail(msg);

+				ajaxErrorMessage = msg;

+			}

+		);

+		t.logger.addAppender(ajaxAppender);

+		t.logger.debug("TEST");

+	});

+

+	s.test("AjaxAppender JsonLayout batched messages test", function(t) {

+		t.async(10000);

+		var message1 = "TEST 1";

+		var message2 = "String with \"lots of 'quotes'\" + plusses in";

+		var message3 = "A non-threatening string";

+		// Create and add an Ajax appender

+		var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");

+		ajaxAppender.setLayout(new log4javascript.JsonLayout());

+		ajaxAppender.setBatchSize(3);

+		ajaxAppender.setRequestSuccessCallback(

+			function(xmlHttp) {

+				// Response comes back as JSON array of messages logged

+				var jsonResponse = xmlHttp.responseText;

+				var arr = eval(jsonResponse);

+				t.assertEquals(arr.length, 3);

+				t.assertEquals(arr[0], message1);

+				t.assertEquals(arr[1], message2);

+				t.assertEquals(arr[2], message3);

+				t.succeed();

+			}

+		);

+		ajaxAppender.setFailCallback(

+			function(msg) {

+				t.fail(msg);

+				ajaxErrorMessage = msg;

+			}

+		);

+		t.logger.addAppender(ajaxAppender);

+		t.logger.debug(message1);

+		t.logger.info(message2);

+		t.logger.warn(message3);

+	});

+

+	s.test("AjaxAppender HttpPostDataLayout single message test", function(t) {

+		t.async(10000);

+		// Create and add an Ajax appender

+		var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");

+		var testMessage = "TEST +\"1\"";

+		ajaxAppender.setLayout(new log4javascript.HttpPostDataLayout());

+		ajaxAppender.setRequestSuccessCallback(

+			function(xmlHttp) {

+				// Response comes back as JSON array of messages logged

+				var jsonResponse = xmlHttp.responseText;

+				var arr = eval(jsonResponse);

+				t.assertEquals(arr.length, 1);

+				t.assertEquals(arr[0], testMessage);

+				t.succeed();

+			}

+		);

+		ajaxAppender.setFailCallback(

+			function(msg) {

+				t.fail(msg);

+				ajaxErrorMessage = msg;

+			}

+		);

+		t.logger.addAppender(ajaxAppender);

+		t.logger.debug(testMessage);

+	});

+*/

+});
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_uncompressed.js
new file mode 100644
index 0000000..55bd2ca
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_uncompressed.js
@@ -0,0 +1,862 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+function array_contains(arr, val) {

+	for (var i = 0; i < arr.length; i++) {

+		if (arr[i] == val) {

+			return true;

+		}

+	}

+	return false;

+}

+

+// Recursively checks that obj2's interface contains all of obj1's

+// interface (functions and objects only)

+function compareObjectInterface(obj1, obj1_name, obj2, obj2_name, namePrefix) {

+	if (!namePrefix) {

+		namePrefix = "";

+	}

+	var obj1PropertyNames = new Array();

+	for (var i in obj1) {

+		if (i != "prototype" && i != "arguments") {

+			obj1PropertyNames.push(i);

+		}

+	}

+	if (obj1 && obj1.prototype && !array_contains(obj1PropertyNames, "prototype")) {

+		//obj1PropertyNames.push("prototype");

+	}

+	for (var j = 0; j < obj1PropertyNames.length; j++) {

+		var propertyName = obj1PropertyNames[j];

+		if ((typeof obj1[propertyName] == "function" || typeof obj1[propertyName] == "object") && !(obj1[propertyName] instanceof Array)) {

+			var propertyFullyQualifiedName = (namePrefix == "") ? propertyName : namePrefix + "." + propertyName;

+			try {

+				if (typeof obj2[propertyName] == "undefined") {

+					throw new Error(obj2_name + " does not contain " + propertyFullyQualifiedName + " in " + obj1_name);

+				} else if (typeof obj2[propertyName] != typeof obj1[propertyName]){

+					throw new Error(obj2_name + "'s " + propertyFullyQualifiedName + " is of the wrong type: " + typeof obj2[propertyName] + " when it is type " + typeof obj1[propertyName] + " in " + obj1_name);

+				} else if (obj1[propertyName] != Function.prototype.apply) {

+					if (!compareObjectInterface(obj1[propertyName], obj1_name, obj2[propertyName], obj2_name, propertyFullyQualifiedName)) {

+						throw new Error("Interfaces don't match");

+					}

+				}

+			} catch(ex) {

+				throw new Error("Exception while checking property name " + propertyFullyQualifiedName + " in " + obj2_name + ": " + ex.message);

+			}

+		}

+	}

+	return true;

+};

+

+// Simply tests a layout for exceptions when formatting

+var testLayoutWithVariables = function(layout, t) {

+	var emptyObject = {};

+	var emptyArray = [];

+	var emptyString = "";

+	var localUndefined = emptyArray[0];

+	var oneLevelObject = {

+		"name": "One-level object"

+	};

+	var twoLevelObject = {

+		"name": "Two-level object",

+		"data": oneLevelObject

+	};

+	var threeLevelObject = {

+		"name": "Three-level object",

+		"data": twoLevelObject

+	};

+	var anArray = [

+		3,

+		"stuff",

+		true,

+		false,

+		0,

+		null,

+		localUndefined,

+		3.14,

+		function(p) { return "I'm a function"; },

+		[1, "things"]

+	];

+	var arrayOfTestItems = [emptyObject, emptyString, emptyString, localUndefined, oneLevelObject,

+			twoLevelObject, threeLevelObject, anArray];

+

+	t.log("Testing layout " + layout)

+	for (var i = 0; i < arrayOfTestItems.length; i++) {

+		var ex = new Error("Test error");

+		var loggingEvent = new log4javascript.LoggingEvent(t.logger, new Date(), log4javascript.Level.INFO,

+				[arrayOfTestItems[i]], null);

+		t.log("Formatting", arrayOfTestItems[i], result);

+		var result = layout.format(loggingEvent);

+		// Now try with an exception

+		loggingEvent.exception = ex;

+		t.log("Formatting with exception", arrayOfTestItems[i], result);

+		result = layout.format(loggingEvent);

+	}

+};

+

+xn.test.enableTestDebug = true;

+xn.test.enable_log4javascript = false;

+

+xn.test.suite("log4javascript tests", function(s) {

+	log4javascript.logLog.setQuietMode(true);

+	var ArrayAppender = function(layout) {

+		if (layout) {

+			this.setLayout(layout);

+		}

+		this.logMessages = [];

+	};

+

+	ArrayAppender.prototype = new log4javascript.Appender();

+

+	ArrayAppender.prototype.layout = new log4javascript.NullLayout();

+

+	ArrayAppender.prototype.append = function(loggingEvent) {

+		var formattedMessage = this.getLayout().format(loggingEvent);

+		if (this.getLayout().ignoresThrowable()) {

+			formattedMessage += loggingEvent.getThrowableStrRep();

+		}

+		this.logMessages.push(formattedMessage);

+	};

+

+	ArrayAppender.prototype.toString = function() {

+		return "[ArrayAppender]";

+	};

+

+    s.setUp = function(t) {

+        t.logger = log4javascript.getLogger("test");

+		t.logger.removeAllAppenders();

+		t.appender = new ArrayAppender();

+        t.logger.addAppender(t.appender);

+    };

+

+    s.tearDown = function(t) {

+        t.logger.removeAppender(t.appender);

+		log4javascript.resetConfiguration();

+	};

+

+    s.test("Stub script interface test", function(t) {

+        try {

+            compareObjectInterface(log4javascript, "log4javascript", log4javascript_stub, "log4javascript_stub");

+        } catch (ex) {

+            t.fail(ex);

+        }

+    });

+

+	s.test("Disable log4javascript test", function(t) {

+		log4javascript.setEnabled(false);

+		t.logger.debug("TEST");

+		t.assertEquals(t.appender.logMessages.length, 0);

+		log4javascript.setEnabled(true);

+	});

+

+    s.test("Array.splice test 1", function(t) {

+        var a = ["Marlon", "Ashley", "Darius", "Lloyd"];

+        var deletedItems = a.splice(1, 2);

+        t.assertEquals(a.join(","), "Marlon,Lloyd");

+        t.assertEquals(deletedItems.join(","), "Ashley,Darius");

+    });

+

+    s.test("Array.splice test 2", function(t) {

+        var a = ["Marlon", "Ashley", "Darius", "Lloyd"];

+        var deletedItems = a.splice(1, 1, "Malky", "Jay");

+        t.assertEquals(a.join(","), "Marlon,Malky,Jay,Darius,Lloyd");

+        t.assertEquals(deletedItems.join(","), "Ashley");

+    });

+

+    s.test("array_remove test", function(t) {

+        var array_remove = log4javascript.evalInScope("array_remove");

+        var a = ["Marlon", "Ashley", "Darius"];

+        array_remove(a, "Darius");

+        t.assertEquals(a.join(","), "Marlon,Ashley");

+    });

+

+	s.test("array_remove with empty array test", function(t) {

+		var array_remove = log4javascript.evalInScope("array_remove");

+		var a = [];

+		array_remove(a, "Darius");

+		t.assertEquals(a.join(","), "");

+	});

+

+    s.test("Logger logging test", function(t) {

+        // Should log since the default level for loggers is DEBUG and

+        // the default threshold for appenders is ALL

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages.length, 1);

+    });

+

+    s.test("Logger levels test", function(t) {

+        var originalLevel = t.logger.getEffectiveLevel();

+        t.logger.setLevel(log4javascript.Level.INFO);

+        t.logger.debug("TEST");

+		t.logger.setLevel(originalLevel);

+        t.assertEquals(t.appender.logMessages.length, 0);

+    });

+

+	s.test("Logger getEffectiveLevel inheritance test 1", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		parentLogger.setLevel(log4javascript.Level.ERROR);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.ERROR);

+	});

+

+	s.test("Logger getEffectiveLevel inheritance test 2", function(t) {

+		var grandParentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2.test3");

+		grandParentLogger.setLevel(log4javascript.Level.ERROR);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.ERROR);

+	});

+

+	s.test("Logger getEffectiveLevel inheritance test 3", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		parentLogger.setLevel(log4javascript.Level.ERROR);

+		childLogger.setLevel(log4javascript.Level.INFO);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.INFO);

+	});

+

+	s.test("Logger getEffectiveLevel root inheritance test", function(t) {

+		var rootLogger = log4javascript.getRootLogger();

+		var childLogger = log4javascript.getLogger("test1.test2.test3");

+		rootLogger.setLevel(log4javascript.Level.WARN);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.WARN);

+	});

+

+	s.test("Logger null level test", function(t) {

+		t.logger.setLevel(null);

+		// Should default to root logger level, which is DEBUG

+		t.assertEquals(t.logger.getEffectiveLevel(), log4javascript.Level.DEBUG);

+	});

+

+	s.test("Logger appender additivity test 1", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		var parentLoggerAppender = new ArrayAppender();

+		var childLoggerAppender = new ArrayAppender();

+

+		parentLogger.addAppender(parentLoggerAppender);

+		childLogger.addAppender(childLoggerAppender);

+

+		parentLogger.info("Parent logger test message");

+		childLogger.info("Child logger test message");

+

+		t.assertEquals(parentLoggerAppender.logMessages.length, 2);

+		t.assertEquals(childLoggerAppender.logMessages.length, 1);

+	});

+

+	s.test("Logger appender additivity test 2", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		var parentLoggerAppender = new ArrayAppender();

+		var childLoggerAppender = new ArrayAppender();

+

+		parentLogger.addAppender(parentLoggerAppender);

+		childLogger.addAppender(childLoggerAppender);

+

+		childLogger.setAdditivity(false);

+

+		parentLogger.info("Parent logger test message");

+		childLogger.info("Child logger test message");

+

+		t.assertEquals(parentLoggerAppender.logMessages.length, 1);

+		t.assertEquals(childLoggerAppender.logMessages.length, 1);

+	});

+

+	s.test("Logger appender additivity test 3", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		var parentLoggerAppender = new ArrayAppender();

+		var childLoggerAppender = new ArrayAppender();

+

+		parentLogger.addAppender(parentLoggerAppender);

+		childLogger.addAppender(childLoggerAppender);

+

+		childLogger.setAdditivity(false);

+

+		parentLogger.info("Parent logger test message");

+		childLogger.info("Child logger test message");

+

+		childLogger.setAdditivity(true);

+

+		childLogger.info("Child logger test message 2");

+

+		t.assertEquals(parentLoggerAppender.logMessages.length, 2);

+		t.assertEquals(childLoggerAppender.logMessages.length, 2);

+	});

+

+	s.test("Appender threshold test", function(t) {

+        t.appender.setThreshold(log4javascript.Level.INFO);

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages.length, 0);

+    });

+

+    s.test("Basic appender / layout test", function(t) {

+        t.logger.debug("TEST");

+		t.assertEquals(t.appender.logMessages[0], "TEST");

+    });

+

+	s.test("Appender uniqueness within logger test", function(t) {

+		// Add the same appender to the logger for a second time

+		t.logger.addAppender(t.appender);

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages.length, 1);

+    });

+

+	s.test("Logger remove appender test", function(t) {

+		t.logger.debug("TEST");

+		t.logger.removeAppender(t.appender);

+		t.logger.debug("TEST AGAIN");

+		t.assertEquals(t.appender.logMessages.length, 1);

+	});

+

+	s.test("", function(t) {

+		t.logger.debug("TEST");

+		t.logger.removeAppender(t.appender);

+		t.logger.debug("TEST AGAIN");

+		t.assertEquals(t.appender.logMessages.length, 1);

+	});

+	s.test("SimpleLayout format test", function(t) {

+		var layout = new log4javascript.SimpleLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("SimpleLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.SimpleLayout());

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages[0], "DEBUG - TEST");

+    });

+	s.test("NullLayout format test", function(t) {

+		var layout = new log4javascript.NullLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("NullLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.NullLayout());

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages[0], "TEST");

+    });

+	s.test("XmlLayout format test", function(t) {

+		var layout = new log4javascript.XmlLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("XmlLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.XmlLayout());

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<\/log4javascript:event>\s*$/, t.appender.logMessages[0]);

+    });

+

+    s.test("XmlLayout with exception test", function(t) {

+        t.appender.setLayout(new log4javascript.XmlLayout());

+        t.logger.debug("TEST", new Error("Test error"));

+        t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<log4javascript:exception>\s*<!\[CDATA\[.*\]\]><\/log4javascript:exception>\s*<\/log4javascript:event>\s*$/, t.appender.logMessages[0]);

+    });

+

+	var setUpXmlLayoutMillisecondsTest = function(t) {

+		t.date = new Date();

+		t.timeInMilliseconds = t.date.getTime();

+		t.timeInSeconds = Math.floor(t.timeInMilliseconds / 1000);

+		t.milliseconds = t.date.getMilliseconds();

+		

+		t.loggingEvent = new log4javascript.LoggingEvent(t.logger, t.date, log4javascript.Level.DEBUG, ["TEST"], null);

+		t.layout = new log4javascript.XmlLayout();

+	}

+

+	s.test("XmlLayout seconds/milliseconds test 1", function(t) {

+		setUpXmlLayoutMillisecondsTest(t);

+

+		// Test default (i.e. timestamps in milliseconds) first

+        var regex = new RegExp('^<log4javascript:event logger="test" timestamp="' + t.timeInMilliseconds + '" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');

+        t.assertRegexMatches(regex, t.layout.format(t.loggingEvent));

+	});

+	

+	s.test("XmlLayout seconds/milliseconds test 2", function(t) {

+		setUpXmlLayoutMillisecondsTest(t);

+

+        // Change the global setting

+        log4javascript.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        log4javascript.setTimeStampsInMilliseconds(true);

+        var regex = new RegExp('^<log4javascript:event logger="test" timestamp="' + t.timeInSeconds + '" milliseconds="' + t.milliseconds + '" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');

+        t.assertRegexMatches(regex, formatted);

+	});

+

+	s.test("XmlLayout seconds/milliseconds test 3", function(t) {

+		setUpXmlLayoutMillisecondsTest(t);

+

+        // Change the layout setting

+        t.layout.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        var regex = new RegExp('^<log4javascript:event logger="test" timestamp="' + t.timeInSeconds + '" milliseconds="' + t.milliseconds + '" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');

+        t.assertRegexMatches(regex, formatted);

+	});

+	s.test("escapeNewLines test", function(t) {

+		var escapeNewLines = log4javascript.evalInScope("escapeNewLines");

+		var str = "1\r2\n3\n4\r\n5\r6\r\n7";

+		t.assertEquals(escapeNewLines(str), "1\\r\\n2\\r\\n3\\r\\n4\\r\\n5\\r\\n6\\r\\n7");

+	});

+

+	s.test("JsonLayout format test", function(t) {

+		var layout = new log4javascript.JsonLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("JsonLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST"}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout JSON validity test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TEST");

+        eval("var o = " + t.appender.logMessages[0]);

+        t.assertEquals(o.message, "TEST");

+    });

+

+    s.test("JsonLayout with number type message test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug(15);

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":15}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with object type message test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug({});

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"\[object Object\]"}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with boolean type message test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug(false);

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":false}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with quote test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TE\"S\"T");

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TE\\"S\\"T"}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with exception test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TEST", new Error("Test error"));

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST","exception":.*}$/, t.appender.logMessages[0]);

+    });

+

+	var setUpJsonLayoutMillisecondsTest = function(t) {

+		t.date = new Date();

+		t.timeInMilliseconds = t.date.getTime();

+		t.timeInSeconds = Math.floor(t.timeInMilliseconds / 1000);

+		t.milliseconds = t.date.getMilliseconds();

+		

+		t.loggingEvent = new log4javascript.LoggingEvent(t.logger, t.date, log4javascript.Level.DEBUG, ["TEST"], null);

+		t.layout = new log4javascript.JsonLayout();

+	};

+

+	s.test("JsonLayout seconds/milliseconds test 1", function(t) {

+		setUpJsonLayoutMillisecondsTest(t);

+

+		// Test default (i.e. timestamps in milliseconds) first

+        var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInMilliseconds + ',"level":"DEBUG","url":".*","message":"TEST"}$');

+        t.assertRegexMatches(regex, t.layout.format(t.loggingEvent));

+	});

+	

+	s.test("JsonLayout seconds/milliseconds test 2", function(t) {

+		setUpJsonLayoutMillisecondsTest(t);

+

+        // Change the global setting

+        log4javascript.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        log4javascript.setTimeStampsInMilliseconds(true);

+        var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInSeconds + ',"level":"DEBUG","url":".*","message":"TEST","milliseconds":' + t.milliseconds + '}$');

+        t.assertRegexMatches(regex, formatted);

+	});

+

+	s.test("JsonLayout seconds/milliseconds test 3", function(t) {

+		setUpJsonLayoutMillisecondsTest(t);

+

+        // Change the layout setting

+        t.layout.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInSeconds + ',"level":"DEBUG","url":".*","message":"TEST","milliseconds":' + t.milliseconds + '}$');

+        t.assertRegexMatches(regex, formatted);

+	});

+	s.test("HttpPostDataLayout format test", function(t) {

+		var layout = new log4javascript.HttpPostDataLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("HttpPostDataLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.HttpPostDataLayout());

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST$/, t.appender.logMessages[0]);

+    });

+

+    s.test("HttpPostDataLayout URL encoding test", function(t) {

+        t.appender.setLayout(new log4javascript.HttpPostDataLayout());

+        t.logger.debug("TEST +\"1\"");

+        t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST%20%2B%221%22$/, t.appender.logMessages[0]);

+    });

+

+    s.test("HttpPostDataLayout with exception test", function(t) {

+        t.appender.setLayout(new log4javascript.HttpPostDataLayout());

+        t.logger.debug("TEST", new Error("Test error"));

+        t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST&exception=.*$/, t.appender.logMessages[0]);

+    });

+

+	(function() {

+		var formatObjectExpansion = log4javascript.evalInScope("formatObjectExpansion");

+		var newLine = log4javascript.evalInScope("newLine");

+		var arr = [

+			null,

+			undefined,

+			1.2,

+			"A string",

+			[1, "test"],

+			{

+				a: {

+					b: 1

+				}

+			}

+		];

+

+		s.test("Basic formatObjectExpansion array test (depth: 1)", function(t) {

+			t.assertEquals(formatObjectExpansion(arr, 1),

+				"[" + newLine +

+				"  null," + newLine +

+				"  undefined," + newLine +

+				"  1.2," + newLine +

+				"  A string," + newLine +

+				"  1,test," + newLine +

+				"  [object Object]" + newLine +

+				"]"

+			);

+		});

+

+		s.test("Basic formatObjectExpansion array test (depth: 2)", function(t) {

+			t.assertEquals(formatObjectExpansion(arr, 2),

+				"[" + newLine +

+				"  null," + newLine +

+				"  undefined," + newLine +

+				"  1.2," + newLine +

+				"  A string," + newLine +

+				"  [" + newLine +

+				"    1," + newLine +

+				"    test" + newLine +

+				"  ]," + newLine +

+				"  {" + newLine +

+				"    a: [object Object]" + newLine +

+				"  }" + newLine +

+				"]"

+			);

+		});

+

+		s.test("formatObjectExpansion simple object test", function(t) {

+			var obj = {

+				STRING: "A string"

+			};

+			t.assertEquals(formatObjectExpansion(obj, 1), 

+				"{" + newLine +

+				"  STRING: A string" + newLine +

+				"}"

+			);

+		});

+

+		s.test("formatObjectExpansion simple circular object test", function(t) {

+			var obj = {};

+			obj.a = obj;

+			

+			t.assertEquals(formatObjectExpansion(obj, 2), 

+				"{" + newLine +

+				"  a: [object Object] [already expanded]" + newLine +

+				"}"

+			);

+		});

+	})();    /* ---------------------------------------------------------- */

+

+    var getSampleDate = function() {

+        var date = new Date();

+        date.setFullYear(2006);

+        date.setMonth(7);

+        date.setDate(30);

+        date.setHours(15);

+        date.setMinutes(38);

+        date.setSeconds(45);

+        return date;

+    };

+

+    /* ---------------------------------------------------------- */

+

+    s.test("String.replace test", function(t) {

+        t.assertEquals("Hello world".replace(/o/g, "Z"), "HellZ wZrld");

+    });

+

+	s.test("PatternLayout format test", function(t) {

+		var layout = new log4javascript.PatternLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("PatternLayout dates test", function(t) {

+        var layout = new log4javascript.PatternLayout("%d %d{DATE} %d{HH:ss}");

+        t.appender.setLayout(layout);

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2},\d{3} \d{2}:\d{2}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("PatternLayout modifiers test", function(t) {

+        var layout = new log4javascript.PatternLayout("%m|%3m|%-3m|%6m|%-6m|%.2m|%1.2m|%6.8m|%-1.2m|%-6.8m|");

+        t.appender.setLayout(layout);

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages[0], "TEST|TEST|TEST|  TEST|TEST  |ST|ST|  TEST|ST|TEST  |");

+    });

+

+    s.test("PatternLayout conversion characters test", function(t) {

+        var layout = new log4javascript.PatternLayout("%c %n %p %r literal %%");

+        t.appender.setLayout(layout);

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^test \s+ DEBUG \d+ literal %$/, t.appender.logMessages[0]);

+    });

+

+    s.test("PatternLayout message test", function(t) {

+        var layout = new log4javascript.PatternLayout("%m{1} %m{2}");

+        t.appender.setLayout(layout);

+        var testObj = {

+            strikers: {

+                quick: "Marlon"

+            }

+        };

+        t.logger.debug(testObj);

+        t.assertEquals("{\r\n  strikers: [object Object]\r\n} {\r\n\  strikers: {\r\n    quick: Marlon\r\n  }\r\n}", t.appender.logMessages[0]);

+    });

+	// Tests for exceptions when logging

+	s.test("Logging/grouping test", function(t) {

+		var browserConsoleAppender = new log4javascript.BrowserConsoleAppender();

+		t.logger.addAppender(browserConsoleAppender);

+

+		// Test each level

+		t.logger.trace("TEST TRACE");

+		t.logger.debug("TEST DEBUG");

+		t.logger.info("TEST INFO");

+		t.logger.warn("TEST WARN");

+		t.logger.error("TEST ERROR");

+		t.logger.fatal("TEST FATAL");

+		

+		// Test with exception

+		t.logger.fatal("TEST FATAL", new Error("Fake error"));

+		

+		// Test multiple messages

+		t.logger.info("TEST INFO", "Second message", ["a", "b", "c"]);

+		

+		// Test groups

+		t.logger.group("TEST GROUP");

+		t.logger.info("TEST INFO");

+		t.logger.groupEnd("TEST GROUP");

+		t.logger.info("TEST INFO");

+		

+		t.logger.removeAppender(browserConsoleAppender);

+	});

+

+/*

+	s.test("AjaxAppender JsonLayout single message test", function(t) {

+		t.async(10000);

+		// Create and add an Ajax appender

+		var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");

+		ajaxAppender.setLayout(new log4javascript.JsonLayout());

+		ajaxAppender.setRequestSuccessCallback(

+			function(xmlHttp) {

+				// Response comes back as JSON array of messages logged

+				var jsonResponse = xmlHttp.responseText;

+				var arr = eval(jsonResponse);

+				t.assertEquals(arr.length, 1);

+				t.assertEquals(arr[0], "TEST");

+				t.succeed();

+			}

+		);

+		ajaxAppender.setFailCallback(

+			function(msg) {

+				t.fail(msg);

+				ajaxErrorMessage = msg;

+			}

+		);

+		t.logger.addAppender(ajaxAppender);

+		t.logger.debug("TEST");

+	});

+

+	s.test("AjaxAppender JsonLayout batched messages test", function(t) {

+		t.async(10000);

+		var message1 = "TEST 1";

+		var message2 = "String with \"lots of 'quotes'\" + plusses in";

+		var message3 = "A non-threatening string";

+		// Create and add an Ajax appender

+		var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");

+		ajaxAppender.setLayout(new log4javascript.JsonLayout());

+		ajaxAppender.setBatchSize(3);

+		ajaxAppender.setRequestSuccessCallback(

+			function(xmlHttp) {

+				// Response comes back as JSON array of messages logged

+				var jsonResponse = xmlHttp.responseText;

+				var arr = eval(jsonResponse);

+				t.assertEquals(arr.length, 3);

+				t.assertEquals(arr[0], message1);

+				t.assertEquals(arr[1], message2);

+				t.assertEquals(arr[2], message3);

+				t.succeed();

+			}

+		);

+		ajaxAppender.setFailCallback(

+			function(msg) {

+				t.fail(msg);

+				ajaxErrorMessage = msg;

+			}

+		);

+		t.logger.addAppender(ajaxAppender);

+		t.logger.debug(message1);

+		t.logger.info(message2);

+		t.logger.warn(message3);

+	});

+

+	s.test("AjaxAppender HttpPostDataLayout single message test", function(t) {

+		t.async(10000);

+		// Create and add an Ajax appender

+		var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");

+		var testMessage = "TEST +\"1\"";

+		ajaxAppender.setLayout(new log4javascript.HttpPostDataLayout());

+		ajaxAppender.setRequestSuccessCallback(

+			function(xmlHttp) {

+				// Response comes back as JSON array of messages logged

+				var jsonResponse = xmlHttp.responseText;

+				var arr = eval(jsonResponse);

+				t.assertEquals(arr.length, 1);

+				t.assertEquals(arr[0], testMessage);

+				t.succeed();

+			}

+		);

+		ajaxAppender.setFailCallback(

+			function(msg) {

+				t.fail(msg);

+				ajaxErrorMessage = msg;

+			}

+		);

+		t.logger.addAppender(ajaxAppender);

+		t.logger.debug(testMessage);

+	});

+*/

+	var testConsoleAppender = function(t, appender) {

+		var timeoutCallback = function() {

+			//alert("Failed. Debug messages follow.");

+			//log4javascript.logLog.displayDebug();

+			return (windowLoaded ? "Timed out while waiting for messages to appear" :

+				   "Timed out while waiting for window to load") + ". Debug messages: " +

+				   log4javascript.logLog.debugMessages.join("\r\n");

+		}

+

+		t.async(60000, timeoutCallback);

+

+		var windowLoaded = false;

+		var domChecked = false;

+

+		// Set a timeout to allow the pop-up to appear

+		var onLoadHandler = function() {

+			log4javascript.logLog.debug("onLoadHandler");

+			windowLoaded = true;

+			var win = appender.getConsoleWindow();

+

+			if (win && win.loaded) {

+				// Check that the log container element contains the log message. Since

+				// the console window waits 100 milliseconds before actually rendering the

+				// message as a DOM element, we need to use a timer

+				var checkDom = function() {

+					log4javascript.logLog.debug("checkDom");

+					domChecked = true;

+					var logContainer = win.logMainContainer;

+					if (logContainer.hasChildNodes()) {

+						if (logContainer.innerHTML.indexOf("TEST MESSAGE") == -1) {

+							appender.close();

+							t.fail("Log message not correctly logged (log container innerHTML: " + logContainer.innerHTML + ")");

+						} else {

+							t.assert(appender.isVisible());

+							appender.close();

+							t.assert(!appender.isVisible());

+							t.succeed();

+						}

+					} else {

+						appender.close();

+						t.fail("Console has no log messages");

+					}

+				}

+				window.setTimeout(checkDom, 300);

+			} else {

+				appender.close();

+				t.fail("Console mistakenly raised load event");

+			}

+		}

+

+		appender.addEventListener("load", onLoadHandler);

+		t.logger.addAppender(appender);

+		t.logger.debug("TEST MESSAGE");

+	};

+

+	s.test("InlineAppender test", function(t) {

+		var inlineAppender = new log4javascript.InlineAppender();

+		inlineAppender.setInitiallyMinimized(false);

+		inlineAppender.setNewestMessageAtTop(false);

+		inlineAppender.setScrollToLatestMessage(true);

+		inlineAppender.setWidth(600);

+		inlineAppender.setHeight(200);

+

+		testConsoleAppender(t, inlineAppender);

+	});

+

+	s.test("InPageAppender with separate console HTML file test", function(t) {

+		var inPageAppender = new log4javascript.InPageAppender();

+		inPageAppender.setInitiallyMinimized(false);

+		inPageAppender.setNewestMessageAtTop(false);

+		inPageAppender.setScrollToLatestMessage(true);

+		inPageAppender.setUseDocumentWrite(false);

+		inPageAppender.setWidth(600);

+		inPageAppender.setHeight(200);

+

+		testConsoleAppender(t, inPageAppender);

+	});

+

+	s.test("PopUpAppender test", function(t) {

+		var popUpAppender = new log4javascript.PopUpAppender();

+		popUpAppender.setFocusPopUp(true);

+		popUpAppender.setUseOldPopUp(false);

+		popUpAppender.setNewestMessageAtTop(false);

+		popUpAppender.setScrollToLatestMessage(true);

+		popUpAppender.setComplainAboutPopUpBlocking(false);

+		popUpAppender.setWidth(600);

+		popUpAppender.setHeight(200);

+

+		testConsoleAppender(t, popUpAppender);

+		

+		

+	});

+

+	s.test("PopUpAppender with separate console HTML file test", function(t) {

+		var popUpAppender = new log4javascript.PopUpAppender();

+		popUpAppender.setFocusPopUp(true);

+		popUpAppender.setUseOldPopUp(false);

+		popUpAppender.setNewestMessageAtTop(false);

+		popUpAppender.setScrollToLatestMessage(true);

+		popUpAppender.setComplainAboutPopUpBlocking(false);

+		popUpAppender.setUseDocumentWrite(false);

+		popUpAppender.setWidth(600);

+		popUpAppender.setHeight(200);

+

+		testConsoleAppender(t, popUpAppender);

+	});

+});
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/license.txt b/planetstack/core/static/log4javascript-1.4.6/license.txt
new file mode 100644
index 0000000..29f81d8
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/license.txt
@@ -0,0 +1,201 @@
+                                 Apache License

+                           Version 2.0, January 2004

+                        http://www.apache.org/licenses/

+

+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

+

+   1. Definitions.

+

+      "License" shall mean the terms and conditions for use, reproduction,

+      and distribution as defined by Sections 1 through 9 of this document.

+

+      "Licensor" shall mean the copyright owner or entity authorized by

+      the copyright owner that is granting the License.

+

+      "Legal Entity" shall mean the union of the acting entity and all

+      other entities that control, are controlled by, or are under common

+      control with that entity. For the purposes of this definition,

+      "control" means (i) the power, direct or indirect, to cause the

+      direction or management of such entity, whether by contract or

+      otherwise, or (ii) ownership of fifty percent (50%) or more of the

+      outstanding shares, or (iii) beneficial ownership of such entity.

+

+      "You" (or "Your") shall mean an individual or Legal Entity

+      exercising permissions granted by this License.

+

+      "Source" form shall mean the preferred form for making modifications,

+      including but not limited to software source code, documentation

+      source, and configuration files.

+

+      "Object" form shall mean any form resulting from mechanical

+      transformation or translation of a Source form, including but

+      not limited to compiled object code, generated documentation,

+      and conversions to other media types.

+

+      "Work" shall mean the work of authorship, whether in Source or

+      Object form, made available under the License, as indicated by a

+      copyright notice that is included in or attached to the work

+      (an example is provided in the Appendix below).

+

+      "Derivative Works" shall mean any work, whether in Source or Object

+      form, that is based on (or derived from) the Work and for which the

+      editorial revisions, annotations, elaborations, or other modifications

+      represent, as a whole, an original work of authorship. For the purposes

+      of this License, Derivative Works shall not include works that remain

+      separable from, or merely link (or bind by name) to the interfaces of,

+      the Work and Derivative Works thereof.

+

+      "Contribution" shall mean any work of authorship, including

+      the original version of the Work and any modifications or additions

+      to that Work or Derivative Works thereof, that is intentionally

+      submitted to Licensor for inclusion in the Work by the copyright owner

+      or by an individual or Legal Entity authorized to submit on behalf of

+      the copyright owner. For the purposes of this definition, "submitted"

+      means any form of electronic, verbal, or written communication sent

+      to the Licensor or its representatives, including but not limited to

+      communication on electronic mailing lists, source code control systems,

+      and issue tracking systems that are managed by, or on behalf of, the

+      Licensor for the purpose of discussing and improving the Work, but

+      excluding communication that is conspicuously marked or otherwise

+      designated in writing by the copyright owner as "Not a Contribution."

+

+      "Contributor" shall mean Licensor and any individual or Legal Entity

+      on behalf of whom a Contribution has been received by Licensor and

+      subsequently incorporated within the Work.

+

+   2. Grant of Copyright License. Subject to the terms and conditions of

+      this License, each Contributor hereby grants to You a perpetual,

+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable

+      copyright license to reproduce, prepare Derivative Works of,

+      publicly display, publicly perform, sublicense, and distribute the

+      Work and such Derivative Works in Source or Object form.

+

+   3. Grant of Patent License. Subject to the terms and conditions of

+      this License, each Contributor hereby grants to You a perpetual,

+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable

+      (except as stated in this section) patent license to make, have made,

+      use, offer to sell, sell, import, and otherwise transfer the Work,

+      where such license applies only to those patent claims licensable

+      by such Contributor that are necessarily infringed by their

+      Contribution(s) alone or by combination of their Contribution(s)

+      with the Work to which such Contribution(s) was submitted. If You

+      institute patent litigation against any entity (including a

+      cross-claim or counterclaim in a lawsuit) alleging that the Work

+      or a Contribution incorporated within the Work constitutes direct

+      or contributory patent infringement, then any patent licenses

+      granted to You under this License for that Work shall terminate

+      as of the date such litigation is filed.

+

+   4. Redistribution. You may reproduce and distribute copies of the

+      Work or Derivative Works thereof in any medium, with or without

+      modifications, and in Source or Object form, provided that You

+      meet the following conditions:

+

+      (a) You must give any other recipients of the Work or

+          Derivative Works a copy of this License; and

+

+      (b) You must cause any modified files to carry prominent notices

+          stating that You changed the files; and

+

+      (c) You must retain, in the Source form of any Derivative Works

+          that You distribute, all copyright, patent, trademark, and

+          attribution notices from the Source form of the Work,

+          excluding those notices that do not pertain to any part of

+          the Derivative Works; and

+

+      (d) If the Work includes a "NOTICE" text file as part of its

+          distribution, then any Derivative Works that You distribute must

+          include a readable copy of the attribution notices contained

+          within such NOTICE file, excluding those notices that do not

+          pertain to any part of the Derivative Works, in at least one

+          of the following places: within a NOTICE text file distributed

+          as part of the Derivative Works; within the Source form or

+          documentation, if provided along with the Derivative Works; or,

+          within a display generated by the Derivative Works, if and

+          wherever such third-party notices normally appear. The contents

+          of the NOTICE file are for informational purposes only and

+          do not modify the License. You may add Your own attribution

+          notices within Derivative Works that You distribute, alongside

+          or as an addendum to the NOTICE text from the Work, provided

+          that such additional attribution notices cannot be construed

+          as modifying the License.

+

+      You may add Your own copyright statement to Your modifications and

+      may provide additional or different license terms and conditions

+      for use, reproduction, or distribution of Your modifications, or

+      for any such Derivative Works as a whole, provided Your use,

+      reproduction, and distribution of the Work otherwise complies with

+      the conditions stated in this License.

+

+   5. Submission of Contributions. Unless You explicitly state otherwise,

+      any Contribution intentionally submitted for inclusion in the Work

+      by You to the Licensor shall be under the terms and conditions of

+      this License, without any additional terms or conditions.

+      Notwithstanding the above, nothing herein shall supersede or modify

+      the terms of any separate license agreement you may have executed

+      with Licensor regarding such Contributions.

+

+   6. Trademarks. This License does not grant permission to use the trade

+      names, trademarks, service marks, or product names of the Licensor,

+      except as required for reasonable and customary use in describing the

+      origin of the Work and reproducing the content of the NOTICE file.

+

+   7. Disclaimer of Warranty. Unless required by applicable law or

+      agreed to in writing, Licensor provides the Work (and each

+      Contributor provides its Contributions) on an "AS IS" BASIS,

+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or

+      implied, including, without limitation, any warranties or conditions

+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A

+      PARTICULAR PURPOSE. You are solely responsible for determining the

+      appropriateness of using or redistributing the Work and assume any

+      risks associated with Your exercise of permissions under this License.

+

+   8. Limitation of Liability. In no event and under no legal theory,

+      whether in tort (including negligence), contract, or otherwise,

+      unless required by applicable law (such as deliberate and grossly

+      negligent acts) or agreed to in writing, shall any Contributor be

+      liable to You for damages, including any direct, indirect, special,

+      incidental, or consequential damages of any character arising as a

+      result of this License or out of the use or inability to use the

+      Work (including but not limited to damages for loss of goodwill,

+      work stoppage, computer failure or malfunction, or any and all

+      other commercial damages or losses), even if such Contributor

+      has been advised of the possibility of such damages.

+

+   9. Accepting Warranty or Additional Liability. While redistributing

+      the Work or Derivative Works thereof, You may choose to offer,

+      and charge a fee for, acceptance of support, warranty, indemnity,

+      or other liability obligations and/or rights consistent with this

+      License. However, in accepting such obligations, You may act only

+      on Your own behalf and on Your sole responsibility, not on behalf

+      of any other Contributor, and only if You agree to indemnify,

+      defend, and hold each Contributor harmless for any liability

+      incurred by, or claims asserted against, such Contributor by reason

+      of your accepting any such warranty or additional liability.

+

+   END OF TERMS AND CONDITIONS

+

+   APPENDIX: How to apply the Apache License to your work.

+

+      To apply the Apache License to your work, attach the following

+      boilerplate notice, with the fields enclosed by brackets "[]"

+      replaced with your own identifying information. (Don't include

+      the brackets!)  The text should be enclosed in the appropriate

+      comment syntax for the file format. We also recommend that a

+      file or class name and description of purpose be included on the

+      same "printed page" as the copyright notice for easier

+      identification within third-party archives.

+

+   Copyright [yyyy] [name of copyright owner]

+

+   Licensed under the Apache License, Version 2.0 (the "License");

+   you may not use this file except in compliance with the License.

+   You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

diff --git a/planetstack/core/static/log4javascript-1.4.6/log4javascript.js b/planetstack/core/static/log4javascript-1.4.6/log4javascript.js
new file mode 100644
index 0000000..042daa9
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/log4javascript.js
@@ -0,0 +1,274 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}

+return this.length;};}

+if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}

+this.length=this.length-1;return firstItem;}};}

+if(!Array.prototype.splice){Array.prototype.splice=function(startIndex,deleteCount){var itemsAfterDeleted=this.slice(startIndex+deleteCount);var itemsDeleted=this.slice(startIndex,startIndex+deleteCount);this.length=startIndex;var argumentsArray=[];for(var i=0,len=arguments.length;i<len;i++){argumentsArray[i]=arguments[i];}

+var itemsToAppend=(argumentsArray.length>2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i<len;i++){this.push(itemsToAppend[i]);}

+return itemsDeleted;};}

+var log4javascript=(function(){function isUndefined(obj){return typeof obj=="undefined";}

+function EventSupport(){}

+EventSupport.prototype={eventTypes:[],eventListeners:{},setEventTypes:function(eventTypesParam){if(eventTypesParam instanceof Array){this.eventTypes=eventTypesParam;this.eventListeners={};for(var i=0,len=this.eventTypes.length;i<len;i++){this.eventListeners[this.eventTypes[i]]=[];}}else{handleError("log4javascript.EventSupport ["+this+"]: setEventTypes: eventTypes parameter must be an Array");}},addEventListener:function(eventType,listener){if(typeof listener=="function"){if(!array_contains(this.eventTypes,eventType)){handleError("log4javascript.EventSupport ["+this+"]: addEventListener: no event called '"+eventType+"'");}

+this.eventListeners[eventType].push(listener);}else{handleError("log4javascript.EventSupport ["+this+"]: addEventListener: listener must be a function");}},removeEventListener:function(eventType,listener){if(typeof listener=="function"){if(!array_contains(this.eventTypes,eventType)){handleError("log4javascript.EventSupport ["+this+"]: removeEventListener: no event called '"+eventType+"'");}

+array_remove(this.eventListeners[eventType],listener);}else{handleError("log4javascript.EventSupport ["+this+"]: removeEventListener: listener must be a function");}},dispatchEvent:function(eventType,eventArgs){if(array_contains(this.eventTypes,eventType)){var listeners=this.eventListeners[eventType];for(var i=0,len=listeners.length;i<len;i++){listeners[i](this,eventType,eventArgs);}}else{handleError("log4javascript.EventSupport ["+this+"]: dispatchEvent: no event called '"+eventType+"'");}}};var applicationStartDate=new Date();var uniqueId="log4javascript_"+applicationStartDate.getTime()+"_"+

+Math.floor(Math.random()*100000000);var emptyFunction=function(){};var newLine="\r\n";var pageLoaded=false;function Log4JavaScript(){}

+Log4JavaScript.prototype=new EventSupport();log4javascript=new Log4JavaScript();log4javascript.version="1.4.6";log4javascript.edition="log4javascript";function toStr(obj){if(obj&&obj.toString){return obj.toString();}else{return String(obj);}}

+function getExceptionMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}else{return toStr(ex);}}

+function getUrlFileName(url){var lastSlashIndex=Math.max(url.lastIndexOf("/"),url.lastIndexOf("\\"));return url.substr(lastSlashIndex+1);}

+function getExceptionStringRep(ex){if(ex){var exStr="Exception: "+getExceptionMessage(ex);try{if(ex.lineNumber){exStr+=" on line number "+ex.lineNumber;}

+if(ex.fileName){exStr+=" in file "+getUrlFileName(ex.fileName);}}catch(localEx){logLog.warn("Unable to obtain file and line information for error");}

+if(showStackTraces&&ex.stack){exStr+=newLine+"Stack trace:"+newLine+ex.stack;}

+return exStr;}

+return null;}

+function bool(obj){return Boolean(obj);}

+function trim(str){return str.replace(/^\s+/,"").replace(/\s+$/,"");}

+function splitIntoLines(text){var text2=text.replace(/\r\n/g,"\n").replace(/\r/g,"\n");return text2.split("\n");}

+var urlEncode=(typeof window.encodeURIComponent!="undefined")?function(str){return encodeURIComponent(str);}:function(str){return escape(str).replace(/\+/g,"%2B").replace(/"/g,"%22").replace(/'/g,"%27").replace(/\//g,"%2F").replace(/=/g,"%3D");};var urlDecode=(typeof window.decodeURIComponent!="undefined")?function(str){return decodeURIComponent(str);}:function(str){return unescape(str).replace(/%2B/g,"+").replace(/%22/g,"\"").replace(/%27/g,"'").replace(/%2F/g,"/").replace(/%3D/g,"=");};function array_remove(arr,val){var index=-1;for(var i=0,len=arr.length;i<len;i++){if(arr[i]===val){index=i;break;}}

+if(index>=0){arr.splice(index,1);return true;}else{return false;}}

+function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}

+return false;}

+function extractBooleanFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return bool(param);}}

+function extractStringFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return String(param);}}

+function extractIntFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{try{var value=parseInt(param,10);return isNaN(value)?defaultValue:value;}catch(ex){logLog.warn("Invalid int param "+param,ex);return defaultValue;}}}

+function extractFunctionFromParam(param,defaultValue){if(typeof param=="function"){return param;}else{return defaultValue;}}

+function isError(err){return(err instanceof Error);}

+if(!Function.prototype.apply){Function.prototype.apply=function(obj,args){var methodName="__apply__";if(typeof obj[methodName]!="undefined"){methodName+=String(Math.random()).substr(2);}

+obj[methodName]=this;var argsStrings=[];for(var i=0,len=args.length;i<len;i++){argsStrings[i]="args["+i+"]";}

+var script="obj."+methodName+"("+argsStrings.join(",")+")";var returnValue=eval(script);delete obj[methodName];return returnValue;};}

+if(!Function.prototype.call){Function.prototype.call=function(obj){var args=[];for(var i=1,len=arguments.length;i<len;i++){args[i-1]=arguments[i];}

+return this.apply(obj,args);};}

+function getListenersPropertyName(eventName){return"__log4javascript_listeners__"+eventName;}

+function addEvent(node,eventName,listener,useCapture,win){win=win?win:window;if(node.addEventListener){node.addEventListener(eventName,listener,useCapture);}else if(node.attachEvent){node.attachEvent("on"+eventName,listener);}else{var propertyName=getListenersPropertyName(eventName);if(!node[propertyName]){node[propertyName]=[];node["on"+eventName]=function(evt){evt=getEvent(evt,win);var listenersPropertyName=getListenersPropertyName(eventName);var listeners=this[listenersPropertyName].concat([]);var currentListener;while((currentListener=listeners.shift())){currentListener.call(this,evt);}};}

+node[propertyName].push(listener);}}

+function removeEvent(node,eventName,listener,useCapture){if(node.removeEventListener){node.removeEventListener(eventName,listener,useCapture);}else if(node.detachEvent){node.detachEvent("on"+eventName,listener);}else{var propertyName=getListenersPropertyName(eventName);if(node[propertyName]){array_remove(node[propertyName],listener);}}}

+function getEvent(evt,win){win=win?win:window;return evt?evt:win.event;}

+function stopEventPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}

+evt.returnValue=false;}

+var logLog={quietMode:false,debugMessages:[],setQuietMode:function(quietMode){this.quietMode=bool(quietMode);},numberOfErrors:0,alertAllErrors:false,setAlertAllErrors:function(alertAllErrors){this.alertAllErrors=alertAllErrors;},debug:function(message){this.debugMessages.push(message);},displayDebug:function(){alert(this.debugMessages.join(newLine));},warn:function(message,exception){},error:function(message,exception){if(++this.numberOfErrors==1||this.alertAllErrors){if(!this.quietMode){var alertMessage="log4javascript error: "+message;if(exception){alertMessage+=newLine+newLine+"Original error: "+getExceptionStringRep(exception);}

+alert(alertMessage);}}}};log4javascript.logLog=logLog;log4javascript.setEventTypes(["load","error"]);function handleError(message,exception){logLog.error(message,exception);log4javascript.dispatchEvent("error",{"message":message,"exception":exception});}

+log4javascript.handleError=handleError;var enabled=!((typeof log4javascript_disabled!="undefined")&&log4javascript_disabled);log4javascript.setEnabled=function(enable){enabled=bool(enable);};log4javascript.isEnabled=function(){return enabled;};var useTimeStampsInMilliseconds=true;log4javascript.setTimeStampsInMilliseconds=function(timeStampsInMilliseconds){useTimeStampsInMilliseconds=bool(timeStampsInMilliseconds);};log4javascript.isTimeStampsInMilliseconds=function(){return useTimeStampsInMilliseconds;};log4javascript.evalInScope=function(expr){return eval(expr);};var showStackTraces=false;log4javascript.setShowStackTraces=function(show){showStackTraces=bool(show);};var Level=function(level,name){this.level=level;this.name=name;};Level.prototype={toString:function(){return this.name;},equals:function(level){return this.level==level.level;},isGreaterOrEqual:function(level){return this.level>=level.level;}};Level.ALL=new Level(Number.MIN_VALUE,"ALL");Level.TRACE=new Level(10000,"TRACE");Level.DEBUG=new Level(20000,"DEBUG");Level.INFO=new Level(30000,"INFO");Level.WARN=new Level(40000,"WARN");Level.ERROR=new Level(50000,"ERROR");Level.FATAL=new Level(60000,"FATAL");Level.OFF=new Level(Number.MAX_VALUE,"OFF");log4javascript.Level=Level;function Timer(name,level){this.name=name;this.level=isUndefined(level)?Level.INFO:level;this.start=new Date();}

+Timer.prototype.getElapsedTime=function(){return new Date().getTime()-this.start.getTime();};var anonymousLoggerName="[anonymous]";var defaultLoggerName="[default]";var nullLoggerName="[null]";var rootLoggerName="root";function Logger(name){this.name=name;this.parent=null;this.children=[];var appenders=[];var loggerLevel=null;var isRoot=(this.name===rootLoggerName);var isNull=(this.name===nullLoggerName);var appenderCache=null;var appenderCacheInvalidated=false;this.addChild=function(childLogger){this.children.push(childLogger);childLogger.parent=this;childLogger.invalidateAppenderCache();};var additive=true;this.getAdditivity=function(){return additive;};this.setAdditivity=function(additivity){var valueChanged=(additive!=additivity);additive=additivity;if(valueChanged){this.invalidateAppenderCache();}};this.addAppender=function(appender){if(isNull){handleError("Logger.addAppender: you may not add an appender to the null logger");}else{if(appender instanceof log4javascript.Appender){if(!array_contains(appenders,appender)){appenders.push(appender);appender.setAddedToLogger(this);this.invalidateAppenderCache();}}else{handleError("Logger.addAppender: appender supplied ('"+

+toStr(appender)+"') is not a subclass of Appender");}}};this.removeAppender=function(appender){array_remove(appenders,appender);appender.setRemovedFromLogger(this);this.invalidateAppenderCache();};this.removeAllAppenders=function(){var appenderCount=appenders.length;if(appenderCount>0){for(var i=0;i<appenderCount;i++){appenders[i].setRemovedFromLogger(this);}

+appenders.length=0;this.invalidateAppenderCache();}};this.getEffectiveAppenders=function(){if(appenderCache===null||appenderCacheInvalidated){var parentEffectiveAppenders=(isRoot||!this.getAdditivity())?[]:this.parent.getEffectiveAppenders();appenderCache=parentEffectiveAppenders.concat(appenders);appenderCacheInvalidated=false;}

+return appenderCache;};this.invalidateAppenderCache=function(){appenderCacheInvalidated=true;for(var i=0,len=this.children.length;i<len;i++){this.children[i].invalidateAppenderCache();}};this.log=function(level,params){if(enabled&&level.isGreaterOrEqual(this.getEffectiveLevel())){var exception;var finalParamIndex=params.length-1;var lastParam=params[finalParamIndex];if(params.length>1&&isError(lastParam)){exception=lastParam;finalParamIndex--;}

+var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];}

+var loggingEvent=new LoggingEvent(this,new Date(),level,messages,exception);this.callAppenders(loggingEvent);}};this.callAppenders=function(loggingEvent){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].doAppend(loggingEvent);}};this.setLevel=function(level){if(isRoot&&level===null){handleError("Logger.setLevel: you cannot set the level of the root logger to null");}else if(level instanceof Level){loggerLevel=level;}else{handleError("Logger.setLevel: level supplied to logger "+

+this.name+" is not an instance of log4javascript.Level");}};this.getLevel=function(){return loggerLevel;};this.getEffectiveLevel=function(){for(var logger=this;logger!==null;logger=logger.parent){var level=logger.getLevel();if(level!==null){return level;}}};this.group=function(name,initiallyExpanded){if(enabled){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].group(name,initiallyExpanded);}}};this.groupEnd=function(){if(enabled){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].groupEnd();}}};var timers={};this.time=function(name,level){if(enabled){if(isUndefined(name)){handleError("Logger.time: a name for the timer must be supplied");}else if(level&&!(level instanceof Level)){handleError("Logger.time: level supplied to timer "+

+name+" is not an instance of log4javascript.Level");}else{timers[name]=new Timer(name,level);}}};this.timeEnd=function(name){if(enabled){if(isUndefined(name)){handleError("Logger.timeEnd: a name for the timer must be supplied");}else if(timers[name]){var timer=timers[name];var milliseconds=timer.getElapsedTime();this.log(timer.level,["Timer "+toStr(name)+" completed in "+milliseconds+"ms"]);delete timers[name];}else{logLog.warn("Logger.timeEnd: no timer found with name "+name);}}};this.assert=function(expr){if(enabled&&!expr){var args=[];for(var i=1,len=arguments.length;i<len;i++){args.push(arguments[i]);}

+args=(args.length>0)?args:["Assertion Failure"];args.push(newLine);args.push(expr);this.log(Level.ERROR,args);}};this.toString=function(){return"Logger["+this.name+"]";};}

+Logger.prototype={trace:function(){this.log(Level.TRACE,arguments);},debug:function(){this.log(Level.DEBUG,arguments);},info:function(){this.log(Level.INFO,arguments);},warn:function(){this.log(Level.WARN,arguments);},error:function(){this.log(Level.ERROR,arguments);},fatal:function(){this.log(Level.FATAL,arguments);},isEnabledFor:function(level){return level.isGreaterOrEqual(this.getEffectiveLevel());},isTraceEnabled:function(){return this.isEnabledFor(Level.TRACE);},isDebugEnabled:function(){return this.isEnabledFor(Level.DEBUG);},isInfoEnabled:function(){return this.isEnabledFor(Level.INFO);},isWarnEnabled:function(){return this.isEnabledFor(Level.WARN);},isErrorEnabled:function(){return this.isEnabledFor(Level.ERROR);},isFatalEnabled:function(){return this.isEnabledFor(Level.FATAL);}};Logger.prototype.trace.isEntryPoint=true;Logger.prototype.debug.isEntryPoint=true;Logger.prototype.info.isEntryPoint=true;Logger.prototype.warn.isEntryPoint=true;Logger.prototype.error.isEntryPoint=true;Logger.prototype.fatal.isEntryPoint=true;var loggers={};var loggerNames=[];var ROOT_LOGGER_DEFAULT_LEVEL=Level.DEBUG;var rootLogger=new Logger(rootLoggerName);rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);log4javascript.getRootLogger=function(){return rootLogger;};log4javascript.getLogger=function(loggerName){if(!(typeof loggerName=="string")){loggerName=anonymousLoggerName;logLog.warn("log4javascript.getLogger: non-string logger name "+

+toStr(loggerName)+" supplied, returning anonymous logger");}

+if(loggerName==rootLoggerName){handleError("log4javascript.getLogger: root logger may not be obtained by name");}

+if(!loggers[loggerName]){var logger=new Logger(loggerName);loggers[loggerName]=logger;loggerNames.push(loggerName);var lastDotIndex=loggerName.lastIndexOf(".");var parentLogger;if(lastDotIndex>-1){var parentLoggerName=loggerName.substring(0,lastDotIndex);parentLogger=log4javascript.getLogger(parentLoggerName);}else{parentLogger=rootLogger;}

+parentLogger.addChild(logger);}

+return loggers[loggerName];};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=log4javascript.getLogger(defaultLoggerName);var a=new log4javascript.PopUpAppender();defaultLogger.addAppender(a);}

+return defaultLogger;};var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger(nullLoggerName);nullLogger.setLevel(Level.OFF);}

+return nullLogger;};log4javascript.resetConfiguration=function(){rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);loggers={};};var LoggingEvent=function(logger,timeStamp,level,messages,exception){this.logger=logger;this.timeStamp=timeStamp;this.timeStampInMilliseconds=timeStamp.getTime();this.timeStampInSeconds=Math.floor(this.timeStampInMilliseconds/1000);this.milliseconds=this.timeStamp.getMilliseconds();this.level=level;this.messages=messages;this.exception=exception;};LoggingEvent.prototype={getThrowableStrRep:function(){return this.exception?getExceptionStringRep(this.exception):"";},getCombinedMessages:function(){return(this.messages.length==1)?this.messages[0]:this.messages.join(newLine);},toString:function(){return"LoggingEvent["+this.level+"]";}};log4javascript.LoggingEvent=LoggingEvent;var Layout=function(){};Layout.prototype={defaults:{loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url"},loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url",batchHeader:"",batchFooter:"",batchSeparator:"",returnsPostData:false,overrideTimeStampsSetting:false,useTimeStampsInMilliseconds:null,format:function(){handleError("Layout.format: layout supplied has no format() method");},ignoresThrowable:function(){handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");},getContentType:function(){return"text/plain";},allowBatching:function(){return true;},setTimeStampsInMilliseconds:function(timeStampsInMilliseconds){this.overrideTimeStampsSetting=true;this.useTimeStampsInMilliseconds=bool(timeStampsInMilliseconds);},isTimeStampsInMilliseconds:function(){return this.overrideTimeStampsSetting?this.useTimeStampsInMilliseconds:useTimeStampsInMilliseconds;},getTimeStampValue:function(loggingEvent){return this.isTimeStampsInMilliseconds()?loggingEvent.timeStampInMilliseconds:loggingEvent.timeStampInSeconds;},getDataValues:function(loggingEvent,combineMessages){var dataValues=[[this.loggerKey,loggingEvent.logger.name],[this.timeStampKey,this.getTimeStampValue(loggingEvent)],[this.levelKey,loggingEvent.level.name],[this.urlKey,window.location.href],[this.messageKey,combineMessages?loggingEvent.getCombinedMessages():loggingEvent.messages]];if(!this.isTimeStampsInMilliseconds()){dataValues.push([this.millisecondsKey,loggingEvent.milliseconds]);}

+if(loggingEvent.exception){dataValues.push([this.exceptionKey,getExceptionStringRep(loggingEvent.exception)]);}

+if(this.hasCustomFields()){for(var i=0,len=this.customFields.length;i<len;i++){var val=this.customFields[i].value;if(typeof val==="function"){val=val(this,loggingEvent);}

+dataValues.push([this.customFields[i].name,val]);}}

+return dataValues;},setKeys:function(loggerKey,timeStampKey,levelKey,messageKey,exceptionKey,urlKey,millisecondsKey){this.loggerKey=extractStringFromParam(loggerKey,this.defaults.loggerKey);this.timeStampKey=extractStringFromParam(timeStampKey,this.defaults.timeStampKey);this.levelKey=extractStringFromParam(levelKey,this.defaults.levelKey);this.messageKey=extractStringFromParam(messageKey,this.defaults.messageKey);this.exceptionKey=extractStringFromParam(exceptionKey,this.defaults.exceptionKey);this.urlKey=extractStringFromParam(urlKey,this.defaults.urlKey);this.millisecondsKey=extractStringFromParam(millisecondsKey,this.defaults.millisecondsKey);},setCustomField:function(name,value){var fieldUpdated=false;for(var i=0,len=this.customFields.length;i<len;i++){if(this.customFields[i].name===name){this.customFields[i].value=value;fieldUpdated=true;}}

+if(!fieldUpdated){this.customFields.push({"name":name,"value":value});}},hasCustomFields:function(){return(this.customFields.length>0);},toString:function(){handleError("Layout.toString: all layouts must override this method");}};log4javascript.Layout=Layout;var Appender=function(){};Appender.prototype=new EventSupport();Appender.prototype.layout=new PatternLayout();Appender.prototype.threshold=Level.ALL;Appender.prototype.loggers=[];Appender.prototype.doAppend=function(loggingEvent){if(enabled&&loggingEvent.level.level>=this.threshold.level){this.append(loggingEvent);}};Appender.prototype.append=function(loggingEvent){};Appender.prototype.setLayout=function(layout){if(layout instanceof Layout){this.layout=layout;}else{handleError("Appender.setLayout: layout supplied to "+

+this.toString()+" is not a subclass of Layout");}};Appender.prototype.getLayout=function(){return this.layout;};Appender.prototype.setThreshold=function(threshold){if(threshold instanceof Level){this.threshold=threshold;}else{handleError("Appender.setThreshold: threshold supplied to "+

+this.toString()+" is not a subclass of Level");}};Appender.prototype.getThreshold=function(){return this.threshold;};Appender.prototype.setAddedToLogger=function(logger){this.loggers.push(logger);};Appender.prototype.setRemovedFromLogger=function(logger){array_remove(this.loggers,logger);};Appender.prototype.group=emptyFunction;Appender.prototype.groupEnd=emptyFunction;Appender.prototype.toString=function(){handleError("Appender.toString: all appenders must override this method");};log4javascript.Appender=Appender;function SimpleLayout(){this.customFields=[];}

+SimpleLayout.prototype=new Layout();SimpleLayout.prototype.format=function(loggingEvent){return loggingEvent.level.name+" - "+loggingEvent.getCombinedMessages();};SimpleLayout.prototype.ignoresThrowable=function(){return true;};SimpleLayout.prototype.toString=function(){return"SimpleLayout";};log4javascript.SimpleLayout=SimpleLayout;function NullLayout(){this.customFields=[];}

+NullLayout.prototype=new Layout();NullLayout.prototype.format=function(loggingEvent){return loggingEvent.messages;};NullLayout.prototype.ignoresThrowable=function(){return true;};NullLayout.prototype.toString=function(){return"NullLayout";};log4javascript.NullLayout=NullLayout;function XmlLayout(combineMessages){this.combineMessages=extractBooleanFromParam(combineMessages,true);this.customFields=[];}

+XmlLayout.prototype=new Layout();XmlLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};XmlLayout.prototype.getContentType=function(){return"text/xml";};XmlLayout.prototype.escapeCdata=function(str){return str.replace(/\]\]>/,"]]>]]&gt;<![CDATA[");};XmlLayout.prototype.format=function(loggingEvent){var layout=this;var i,len;function formatMessage(message){message=(typeof message==="string")?message:toStr(message);return"<log4javascript:message><![CDATA["+

+layout.escapeCdata(message)+"]]></log4javascript:message>";}

+var str="<log4javascript:event logger=\""+loggingEvent.logger.name+"\" timestamp=\""+this.getTimeStampValue(loggingEvent)+"\"";if(!this.isTimeStampsInMilliseconds()){str+=" milliseconds=\""+loggingEvent.milliseconds+"\"";}

+str+=" level=\""+loggingEvent.level.name+"\">"+newLine;if(this.combineMessages){str+=formatMessage(loggingEvent.getCombinedMessages());}else{str+="<log4javascript:messages>"+newLine;for(i=0,len=loggingEvent.messages.length;i<len;i++){str+=formatMessage(loggingEvent.messages[i])+newLine;}

+str+="</log4javascript:messages>"+newLine;}

+if(this.hasCustomFields()){for(i=0,len=this.customFields.length;i<len;i++){str+="<log4javascript:customfield name=\""+

+this.customFields[i].name+"\"><![CDATA["+

+this.customFields[i].value.toString()+"]]></log4javascript:customfield>"+newLine;}}

+if(loggingEvent.exception){str+="<log4javascript:exception><![CDATA["+

+getExceptionStringRep(loggingEvent.exception)+"]]></log4javascript:exception>"+newLine;}

+str+="</log4javascript:event>"+newLine+newLine;return str;};XmlLayout.prototype.ignoresThrowable=function(){return false;};XmlLayout.prototype.toString=function(){return"XmlLayout";};log4javascript.XmlLayout=XmlLayout;function escapeNewLines(str){return str.replace(/\r\n|\r|\n/g,"\\r\\n");}

+function JsonLayout(readable,combineMessages){this.readable=extractBooleanFromParam(readable,false);this.combineMessages=extractBooleanFromParam(combineMessages,true);this.batchHeader=this.readable?"["+newLine:"[";this.batchFooter=this.readable?"]"+newLine:"]";this.batchSeparator=this.readable?","+newLine:",";this.setKeys();this.colon=this.readable?": ":":";this.tab=this.readable?"\t":"";this.lineBreak=this.readable?newLine:"";this.customFields=[];}

+JsonLayout.prototype=new Layout();JsonLayout.prototype.isReadable=function(){return this.readable;};JsonLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};JsonLayout.prototype.format=function(loggingEvent){var layout=this;var dataValues=this.getDataValues(loggingEvent,this.combineMessages);var str="{"+this.lineBreak;var i,len;function formatValue(val,prefix,expand){var formattedValue;var valType=typeof val;if(val instanceof Date){formattedValue=String(val.getTime());}else if(expand&&(val instanceof Array)){formattedValue="["+layout.lineBreak;for(var i=0,len=val.length;i<len;i++){var childPrefix=prefix+layout.tab;formattedValue+=childPrefix+formatValue(val[i],childPrefix,false);if(i<val.length-1){formattedValue+=",";}

+formattedValue+=layout.lineBreak;}

+formattedValue+=prefix+"]";}else if(valType!=="number"&&valType!=="boolean"){formattedValue="\""+escapeNewLines(toStr(val).replace(/\"/g,"\\\""))+"\"";}else{formattedValue=val;}

+return formattedValue;}

+for(i=0,len=dataValues.length-1;i<=len;i++){str+=this.tab+"\""+dataValues[i][0]+"\""+this.colon+formatValue(dataValues[i][1],this.tab,true);if(i<len){str+=",";}

+str+=this.lineBreak;}

+str+="}"+this.lineBreak;return str;};JsonLayout.prototype.ignoresThrowable=function(){return false;};JsonLayout.prototype.toString=function(){return"JsonLayout";};JsonLayout.prototype.getContentType=function(){return"application/json";};log4javascript.JsonLayout=JsonLayout;function HttpPostDataLayout(){this.setKeys();this.customFields=[];this.returnsPostData=true;}

+HttpPostDataLayout.prototype=new Layout();HttpPostDataLayout.prototype.allowBatching=function(){return false;};HttpPostDataLayout.prototype.format=function(loggingEvent){var dataValues=this.getDataValues(loggingEvent);var queryBits=[];for(var i=0,len=dataValues.length;i<len;i++){var val=(dataValues[i][1]instanceof Date)?String(dataValues[i][1].getTime()):dataValues[i][1];queryBits.push(urlEncode(dataValues[i][0])+"="+urlEncode(val));}

+return queryBits.join("&");};HttpPostDataLayout.prototype.ignoresThrowable=function(loggingEvent){return false;};HttpPostDataLayout.prototype.toString=function(){return"HttpPostDataLayout";};log4javascript.HttpPostDataLayout=HttpPostDataLayout;function formatObjectExpansion(obj,depth,indentation){var objectsExpanded=[];function doFormat(obj,depth,indentation){var i,j,len,childDepth,childIndentation,childLines,expansion,childExpansion;if(!indentation){indentation="";}

+function formatString(text){var lines=splitIntoLines(text);for(var j=1,jLen=lines.length;j<jLen;j++){lines[j]=indentation+lines[j];}

+return lines.join(newLine);}

+if(obj===null){return"null";}else if(typeof obj=="undefined"){return"undefined";}else if(typeof obj=="string"){return formatString(obj);}else if(typeof obj=="object"&&array_contains(objectsExpanded,obj)){try{expansion=toStr(obj);}catch(ex){expansion="Error formatting property. Details: "+getExceptionStringRep(ex);}

+return expansion+" [already expanded]";}else if((obj instanceof Array)&&depth>0){objectsExpanded.push(obj);expansion="["+newLine;childDepth=depth-1;childIndentation=indentation+"  ";childLines=[];for(i=0,len=obj.length;i<len;i++){try{childExpansion=doFormat(obj[i],childDepth,childIndentation);childLines.push(childIndentation+childExpansion);}catch(ex){childLines.push(childIndentation+"Error formatting array member. Details: "+

+getExceptionStringRep(ex)+"");}}

+expansion+=childLines.join(","+newLine)+newLine+indentation+"]";return expansion;}else if(Object.prototype.toString.call(obj)=="[object Date]"){return obj.toString();}else if(typeof obj=="object"&&depth>0){objectsExpanded.push(obj);expansion="{"+newLine;childDepth=depth-1;childIndentation=indentation+"  ";childLines=[];for(i in obj){try{childExpansion=doFormat(obj[i],childDepth,childIndentation);childLines.push(childIndentation+i+": "+childExpansion);}catch(ex){childLines.push(childIndentation+i+": Error formatting property. Details: "+

+getExceptionStringRep(ex));}}

+expansion+=childLines.join(","+newLine)+newLine+indentation+"}";return expansion;}else{return formatString(toStr(obj));}}

+return doFormat(obj,depth,indentation);}

+var SimpleDateFormat;(function(){var regex=/('[^']*')|(G+|y+|M+|w+|W+|D+|d+|F+|E+|a+|H+|k+|K+|h+|m+|s+|S+|Z+)|([a-zA-Z]+)|([^a-zA-Z']+)/;var monthNames=["January","February","March","April","May","June","July","August","September","October","November","December"];var dayNames=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var TEXT2=0,TEXT3=1,NUMBER=2,YEAR=3,MONTH=4,TIMEZONE=5;var types={G:TEXT2,y:YEAR,M:MONTH,w:NUMBER,W:NUMBER,D:NUMBER,d:NUMBER,F:NUMBER,E:TEXT3,a:TEXT2,H:NUMBER,k:NUMBER,K:NUMBER,h:NUMBER,m:NUMBER,s:NUMBER,S:NUMBER,Z:TIMEZONE};var ONE_DAY=24*60*60*1000;var ONE_WEEK=7*ONE_DAY;var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK=1;var newDateAtMidnight=function(year,month,day){var d=new Date(year,month,day,0,0,0);d.setMilliseconds(0);return d;};Date.prototype.getDifference=function(date){return this.getTime()-date.getTime();};Date.prototype.isBefore=function(d){return this.getTime()<d.getTime();};Date.prototype.getUTCTime=function(){return Date.UTC(this.getFullYear(),this.getMonth(),this.getDate(),this.getHours(),this.getMinutes(),this.getSeconds(),this.getMilliseconds());};Date.prototype.getTimeSince=function(d){return this.getUTCTime()-d.getUTCTime();};Date.prototype.getPreviousSunday=function(){var midday=new Date(this.getFullYear(),this.getMonth(),this.getDate(),12,0,0);var previousSunday=new Date(midday.getTime()-this.getDay()*ONE_DAY);return newDateAtMidnight(previousSunday.getFullYear(),previousSunday.getMonth(),previousSunday.getDate());};Date.prototype.getWeekInYear=function(minimalDaysInFirstWeek){if(isUndefined(this.minimalDaysInFirstWeek)){minimalDaysInFirstWeek=DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;}

+var previousSunday=this.getPreviousSunday();var startOfYear=newDateAtMidnight(this.getFullYear(),0,1);var numberOfSundays=previousSunday.isBefore(startOfYear)?0:1+Math.floor(previousSunday.getTimeSince(startOfYear)/ONE_WEEK);var numberOfDaysInFirstWeek=7-startOfYear.getDay();var weekInYear=numberOfSundays;if(numberOfDaysInFirstWeek<minimalDaysInFirstWeek){weekInYear--;}

+return weekInYear;};Date.prototype.getWeekInMonth=function(minimalDaysInFirstWeek){if(isUndefined(this.minimalDaysInFirstWeek)){minimalDaysInFirstWeek=DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;}

+var previousSunday=this.getPreviousSunday();var startOfMonth=newDateAtMidnight(this.getFullYear(),this.getMonth(),1);var numberOfSundays=previousSunday.isBefore(startOfMonth)?0:1+Math.floor(previousSunday.getTimeSince(startOfMonth)/ONE_WEEK);var numberOfDaysInFirstWeek=7-startOfMonth.getDay();var weekInMonth=numberOfSundays;if(numberOfDaysInFirstWeek>=minimalDaysInFirstWeek){weekInMonth++;}

+return weekInMonth;};Date.prototype.getDayInYear=function(){var startOfYear=newDateAtMidnight(this.getFullYear(),0,1);return 1+Math.floor(this.getTimeSince(startOfYear)/ONE_DAY);};SimpleDateFormat=function(formatString){this.formatString=formatString;};SimpleDateFormat.prototype.setMinimalDaysInFirstWeek=function(days){this.minimalDaysInFirstWeek=days;};SimpleDateFormat.prototype.getMinimalDaysInFirstWeek=function(){return isUndefined(this.minimalDaysInFirstWeek)?DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK:this.minimalDaysInFirstWeek;};var padWithZeroes=function(str,len){while(str.length<len){str="0"+str;}

+return str;};var formatText=function(data,numberOfLetters,minLength){return(numberOfLetters>=4)?data:data.substr(0,Math.max(minLength,numberOfLetters));};var formatNumber=function(data,numberOfLetters){var dataString=""+data;return padWithZeroes(dataString,numberOfLetters);};SimpleDateFormat.prototype.format=function(date){var formattedString="";var result;var searchString=this.formatString;while((result=regex.exec(searchString))){var quotedString=result[1];var patternLetters=result[2];var otherLetters=result[3];var otherCharacters=result[4];if(quotedString){if(quotedString=="''"){formattedString+="'";}else{formattedString+=quotedString.substring(1,quotedString.length-1);}}else if(otherLetters){}else if(otherCharacters){formattedString+=otherCharacters;}else if(patternLetters){var patternLetter=patternLetters.charAt(0);var numberOfLetters=patternLetters.length;var rawData="";switch(patternLetter){case"G":rawData="AD";break;case"y":rawData=date.getFullYear();break;case"M":rawData=date.getMonth();break;case"w":rawData=date.getWeekInYear(this.getMinimalDaysInFirstWeek());break;case"W":rawData=date.getWeekInMonth(this.getMinimalDaysInFirstWeek());break;case"D":rawData=date.getDayInYear();break;case"d":rawData=date.getDate();break;case"F":rawData=1+Math.floor((date.getDate()-1)/7);break;case"E":rawData=dayNames[date.getDay()];break;case"a":rawData=(date.getHours()>=12)?"PM":"AM";break;case"H":rawData=date.getHours();break;case"k":rawData=date.getHours()||24;break;case"K":rawData=date.getHours()%12;break;case"h":rawData=(date.getHours()%12)||12;break;case"m":rawData=date.getMinutes();break;case"s":rawData=date.getSeconds();break;case"S":rawData=date.getMilliseconds();break;case"Z":rawData=date.getTimezoneOffset();break;}

+switch(types[patternLetter]){case TEXT2:formattedString+=formatText(rawData,numberOfLetters,2);break;case TEXT3:formattedString+=formatText(rawData,numberOfLetters,3);break;case NUMBER:formattedString+=formatNumber(rawData,numberOfLetters);break;case YEAR:if(numberOfLetters<=3){var dataString=""+rawData;formattedString+=dataString.substr(2,2);}else{formattedString+=formatNumber(rawData,numberOfLetters);}

+break;case MONTH:if(numberOfLetters>=3){formattedString+=formatText(monthNames[rawData],numberOfLetters,numberOfLetters);}else{formattedString+=formatNumber(rawData+1,numberOfLetters);}

+break;case TIMEZONE:var isPositive=(rawData>0);var prefix=isPositive?"-":"+";var absData=Math.abs(rawData);var hours=""+Math.floor(absData/60);hours=padWithZeroes(hours,2);var minutes=""+(absData%60);minutes=padWithZeroes(minutes,2);formattedString+=prefix+hours+minutes;break;}}

+searchString=searchString.substr(result.index+result[0].length);}

+return formattedString;};})();log4javascript.SimpleDateFormat=SimpleDateFormat;function PatternLayout(pattern){if(pattern){this.pattern=pattern;}else{this.pattern=PatternLayout.DEFAULT_CONVERSION_PATTERN;}

+this.customFields=[];}

+PatternLayout.TTCC_CONVERSION_PATTERN="%r %p %c - %m%n";PatternLayout.DEFAULT_CONVERSION_PATTERN="%m%n";PatternLayout.ISO8601_DATEFORMAT="yyyy-MM-dd HH:mm:ss,SSS";PatternLayout.DATETIME_DATEFORMAT="dd MMM yyyy HH:mm:ss,SSS";PatternLayout.ABSOLUTETIME_DATEFORMAT="HH:mm:ss,SSS";PatternLayout.prototype=new Layout();PatternLayout.prototype.format=function(loggingEvent){var regex=/%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;var formattedString="";var result;var searchString=this.pattern;while((result=regex.exec(searchString))){var matchedString=result[0];var padding=result[1];var truncation=result[2];var conversionCharacter=result[3];var specifier=result[5];var text=result[6];if(text){formattedString+=""+text;}else{var replacement="";switch(conversionCharacter){case"a":case"m":var depth=0;if(specifier){depth=parseInt(specifier,10);if(isNaN(depth)){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character '"+conversionCharacter+"' - should be a number");depth=0;}}

+var messages=(conversionCharacter==="a")?loggingEvent.messages[0]:loggingEvent.messages;for(var i=0,len=messages.length;i<len;i++){if(i>0&&(replacement.charAt(replacement.length-1)!==" ")){replacement+=" ";}

+if(depth===0){replacement+=messages[i];}else{replacement+=formatObjectExpansion(messages[i],depth);}}

+break;case"c":var loggerName=loggingEvent.logger.name;if(specifier){var precision=parseInt(specifier,10);var loggerNameBits=loggingEvent.logger.name.split(".");if(precision>=loggerNameBits.length){replacement=loggerName;}else{replacement=loggerNameBits.slice(loggerNameBits.length-precision).join(".");}}else{replacement=loggerName;}

+break;case"d":var dateFormat=PatternLayout.ISO8601_DATEFORMAT;if(specifier){dateFormat=specifier;if(dateFormat=="ISO8601"){dateFormat=PatternLayout.ISO8601_DATEFORMAT;}else if(dateFormat=="ABSOLUTE"){dateFormat=PatternLayout.ABSOLUTETIME_DATEFORMAT;}else if(dateFormat=="DATE"){dateFormat=PatternLayout.DATETIME_DATEFORMAT;}}

+replacement=(new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);break;case"f":if(this.hasCustomFields()){var fieldIndex=0;if(specifier){fieldIndex=parseInt(specifier,10);if(isNaN(fieldIndex)){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - should be a number");}else if(fieldIndex===0){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - must be greater than zero");}else if(fieldIndex>this.customFields.length){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - there aren't that many custom fields");}else{fieldIndex=fieldIndex-1;}}

+var val=this.customFields[fieldIndex].value;if(typeof val=="function"){val=val(this,loggingEvent);}

+replacement=val;}

+break;case"n":replacement=newLine;break;case"p":replacement=loggingEvent.level.name;break;case"r":replacement=""+loggingEvent.timeStamp.getDifference(applicationStartDate);break;case"%":replacement="%";break;default:replacement=matchedString;break;}

+var l;if(truncation){l=parseInt(truncation.substr(1),10);var strLen=replacement.length;if(l<strLen){replacement=replacement.substring(strLen-l,strLen);}}

+if(padding){if(padding.charAt(0)=="-"){l=parseInt(padding.substr(1),10);while(replacement.length<l){replacement+=" ";}}else{l=parseInt(padding,10);while(replacement.length<l){replacement=" "+replacement;}}}

+formattedString+=replacement;}

+searchString=searchString.substr(result.index+result[0].length);}

+return formattedString;};PatternLayout.prototype.ignoresThrowable=function(){return true;};PatternLayout.prototype.toString=function(){return"PatternLayout";};log4javascript.PatternLayout=PatternLayout;function AlertAppender(){}

+AlertAppender.prototype=new Appender();AlertAppender.prototype.layout=new SimpleLayout();AlertAppender.prototype.append=function(loggingEvent){var formattedMessage=this.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();}

+alert(formattedMessage);};AlertAppender.prototype.toString=function(){return"AlertAppender";};log4javascript.AlertAppender=AlertAppender;function BrowserConsoleAppender(){}

+BrowserConsoleAppender.prototype=new log4javascript.Appender();BrowserConsoleAppender.prototype.layout=new NullLayout();BrowserConsoleAppender.prototype.threshold=Level.DEBUG;BrowserConsoleAppender.prototype.append=function(loggingEvent){var appender=this;var getFormattedMessage=function(){var layout=appender.getLayout();var formattedMessage=layout.format(loggingEvent);if(layout.ignoresThrowable()&&loggingEvent.exception){formattedMessage+=loggingEvent.getThrowableStrRep();}

+return formattedMessage;};if((typeof opera!="undefined")&&opera.postError){opera.postError(getFormattedMessage());}else if(window.console&&window.console.log){var formattedMesage=getFormattedMessage();if(window.console.debug&&Level.DEBUG.isGreaterOrEqual(loggingEvent.level)){window.console.debug(formattedMesage);}else if(window.console.info&&Level.INFO.equals(loggingEvent.level)){window.console.info(formattedMesage);}else if(window.console.warn&&Level.WARN.equals(loggingEvent.level)){window.console.warn(formattedMesage);}else if(window.console.error&&loggingEvent.level.isGreaterOrEqual(Level.ERROR)){window.console.error(formattedMesage);}else{window.console.log(formattedMesage);}}};BrowserConsoleAppender.prototype.group=function(name){if(window.console&&window.console.group){window.console.group(name);}};BrowserConsoleAppender.prototype.groupEnd=function(){if(window.console&&window.console.groupEnd){window.console.groupEnd();}};BrowserConsoleAppender.prototype.toString=function(){return"BrowserConsoleAppender";};log4javascript.BrowserConsoleAppender=BrowserConsoleAppender;var xmlHttpFactories=[function(){return new XMLHttpRequest();},function(){return new ActiveXObject("Msxml2.XMLHTTP");},function(){return new ActiveXObject("Microsoft.XMLHTTP");}];var getXmlHttp=function(errorHandler){var xmlHttp=null,factory;for(var i=0,len=xmlHttpFactories.length;i<len;i++){factory=xmlHttpFactories[i];try{xmlHttp=factory();getXmlHttp=factory;return xmlHttp;}catch(e){}}

+if(errorHandler){errorHandler();}else{handleError("getXmlHttp: unable to obtain XMLHttpRequest object");}};function isHttpRequestSuccessful(xmlHttp){return isUndefined(xmlHttp.status)||xmlHttp.status===0||(xmlHttp.status>=200&&xmlHttp.status<300)||xmlHttp.status==1223;}

+function AjaxAppender(url){var appender=this;var isSupported=true;if(!url){handleError("AjaxAppender: URL must be specified in constructor");isSupported=false;}

+var timed=this.defaults.timed;var waitForResponse=this.defaults.waitForResponse;var batchSize=this.defaults.batchSize;var timerInterval=this.defaults.timerInterval;var requestSuccessCallback=this.defaults.requestSuccessCallback;var failCallback=this.defaults.failCallback;var postVarName=this.defaults.postVarName;var sendAllOnUnload=this.defaults.sendAllOnUnload;var contentType=this.defaults.contentType;var sessionId=null;var queuedLoggingEvents=[];var queuedRequests=[];var headers=[];var sending=false;var initialized=false;function checkCanConfigure(configOptionName){if(initialized){handleError("AjaxAppender: configuration option '"+

+configOptionName+"' may not be set after the appender has been initialized");return false;}

+return true;}

+this.getSessionId=function(){return sessionId;};this.setSessionId=function(sessionIdParam){sessionId=extractStringFromParam(sessionIdParam,null);this.layout.setCustomField("sessionid",sessionId);};this.setLayout=function(layoutParam){if(checkCanConfigure("layout")){this.layout=layoutParam;if(sessionId!==null){this.setSessionId(sessionId);}}};this.isTimed=function(){return timed;};this.setTimed=function(timedParam){if(checkCanConfigure("timed")){timed=bool(timedParam);}};this.getTimerInterval=function(){return timerInterval;};this.setTimerInterval=function(timerIntervalParam){if(checkCanConfigure("timerInterval")){timerInterval=extractIntFromParam(timerIntervalParam,timerInterval);}};this.isWaitForResponse=function(){return waitForResponse;};this.setWaitForResponse=function(waitForResponseParam){if(checkCanConfigure("waitForResponse")){waitForResponse=bool(waitForResponseParam);}};this.getBatchSize=function(){return batchSize;};this.setBatchSize=function(batchSizeParam){if(checkCanConfigure("batchSize")){batchSize=extractIntFromParam(batchSizeParam,batchSize);}};this.isSendAllOnUnload=function(){return sendAllOnUnload;};this.setSendAllOnUnload=function(sendAllOnUnloadParam){if(checkCanConfigure("sendAllOnUnload")){sendAllOnUnload=extractBooleanFromParam(sendAllOnUnloadParam,sendAllOnUnload);}};this.setRequestSuccessCallback=function(requestSuccessCallbackParam){requestSuccessCallback=extractFunctionFromParam(requestSuccessCallbackParam,requestSuccessCallback);};this.setFailCallback=function(failCallbackParam){failCallback=extractFunctionFromParam(failCallbackParam,failCallback);};this.getPostVarName=function(){return postVarName;};this.setPostVarName=function(postVarNameParam){if(checkCanConfigure("postVarName")){postVarName=extractStringFromParam(postVarNameParam,postVarName);}};this.getHeaders=function(){return headers;};this.addHeader=function(name,value){if(name.toLowerCase()=="content-type"){contentType=value;}else{headers.push({name:name,value:value});}};function sendAll(){if(isSupported&&enabled){sending=true;var currentRequestBatch;if(waitForResponse){if(queuedRequests.length>0){currentRequestBatch=queuedRequests.shift();sendRequest(preparePostData(currentRequestBatch),sendAll);}else{sending=false;if(timed){scheduleSending();}}}else{while((currentRequestBatch=queuedRequests.shift())){sendRequest(preparePostData(currentRequestBatch));}

+sending=false;if(timed){scheduleSending();}}}}

+this.sendAll=sendAll;function sendAllRemaining(){var sendingAnything=false;if(isSupported&&enabled){var actualBatchSize=appender.getLayout().allowBatching()?batchSize:1;var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);if(queuedLoggingEvents.length>=actualBatchSize){queuedRequests.push(batchedLoggingEvents);batchedLoggingEvents=[];}}

+if(batchedLoggingEvents.length>0){queuedRequests.push(batchedLoggingEvents);}

+sendingAnything=(queuedRequests.length>0);waitForResponse=false;timed=false;sendAll();}

+return sendingAnything;}

+this.sendAllRemaining=sendAllRemaining;function preparePostData(batchedLoggingEvents){var formattedMessages=[];var currentLoggingEvent;var postData="";while((currentLoggingEvent=batchedLoggingEvents.shift())){var currentFormattedMessage=appender.getLayout().format(currentLoggingEvent);if(appender.getLayout().ignoresThrowable()){currentFormattedMessage+=currentLoggingEvent.getThrowableStrRep();}

+formattedMessages.push(currentFormattedMessage);}

+if(batchedLoggingEvents.length==1){postData=formattedMessages.join("");}else{postData=appender.getLayout().batchHeader+

+formattedMessages.join(appender.getLayout().batchSeparator)+

+appender.getLayout().batchFooter;}

+if(contentType==appender.defaults.contentType){postData=appender.getLayout().returnsPostData?postData:urlEncode(postVarName)+"="+urlEncode(postData);if(postData.length>0){postData+="&";}

+postData+="layout="+urlEncode(appender.getLayout().toString());}

+return postData;}

+function scheduleSending(){window.setTimeout(sendAll,timerInterval);}

+function xmlHttpErrorHandler(){var msg="AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}}

+function sendRequest(postData,successCallback){try{var xmlHttp=getXmlHttp(xmlHttpErrorHandler);if(isSupported){if(xmlHttp.overrideMimeType){xmlHttp.overrideMimeType(appender.getLayout().getContentType());}

+xmlHttp.onreadystatechange=function(){if(xmlHttp.readyState==4){if(isHttpRequestSuccessful(xmlHttp)){if(requestSuccessCallback){requestSuccessCallback(xmlHttp);}

+if(successCallback){successCallback(xmlHttp);}}else{var msg="AjaxAppender.append: XMLHttpRequest request to URL "+

+url+" returned status code "+xmlHttp.status;handleError(msg);if(failCallback){failCallback(msg);}}

+xmlHttp.onreadystatechange=emptyFunction;xmlHttp=null;}};xmlHttp.open("POST",url,true);try{for(var i=0,header;header=headers[i++];){xmlHttp.setRequestHeader(header.name,header.value);}

+xmlHttp.setRequestHeader("Content-Type",contentType);}catch(headerEx){var msg="AjaxAppender.append: your browser's XMLHttpRequest implementation"+" does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}

+return;}

+xmlHttp.send(postData);}}catch(ex){var errMsg="AjaxAppender.append: error sending log message to "+url;handleError(errMsg,ex);isSupported=false;if(failCallback){failCallback(errMsg+". Details: "+getExceptionStringRep(ex));}}}

+this.append=function(loggingEvent){if(isSupported){if(!initialized){init();}

+queuedLoggingEvents.push(loggingEvent);var actualBatchSize=this.getLayout().allowBatching()?batchSize:1;if(queuedLoggingEvents.length>=actualBatchSize){var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);}

+queuedRequests.push(batchedLoggingEvents);if(!timed&&(!waitForResponse||(waitForResponse&&!sending))){sendAll();}}}};function init(){initialized=true;if(sendAllOnUnload){var oldBeforeUnload=window.onbeforeunload;window.onbeforeunload=function(){if(oldBeforeUnload){oldBeforeUnload();}

+if(sendAllRemaining()){return"Sending log messages";}};}

+if(timed){scheduleSending();}}}

+AjaxAppender.prototype=new Appender();AjaxAppender.prototype.defaults={waitForResponse:false,timed:false,timerInterval:1000,batchSize:1,sendAllOnUnload:false,requestSuccessCallback:null,failCallback:null,postVarName:"data",contentType:"application/x-www-form-urlencoded"};AjaxAppender.prototype.layout=new HttpPostDataLayout();AjaxAppender.prototype.toString=function(){return"AjaxAppender";};log4javascript.AjaxAppender=AjaxAppender;function setCookie(name,value,days,path){var expires;path=path?"; path="+path:"";if(days){var date=new Date();date.setTime(date.getTime()+(days*24*60*60*1000));expires="; expires="+date.toGMTString();}else{expires="";}

+document.cookie=escape(name)+"="+escape(value)+expires+path;}

+function getCookie(name){var nameEquals=escape(name)+"=";var ca=document.cookie.split(";");for(var i=0,len=ca.length;i<len;i++){var c=ca[i];while(c.charAt(0)===" "){c=c.substring(1,c.length);}

+if(c.indexOf(nameEquals)===0){return unescape(c.substring(nameEquals.length,c.length));}}

+return null;}

+function getBaseUrl(){var scripts=document.getElementsByTagName("script");for(var i=0,len=scripts.length;i<len;++i){if(scripts[i].src.indexOf("log4javascript")!=-1){var lastSlash=scripts[i].src.lastIndexOf("/");return(lastSlash==-1)?"":scripts[i].src.substr(0,lastSlash+1);}}

+return null;}

+function isLoaded(win){try{return bool(win.loaded);}catch(ex){return false;}}

+var ConsoleAppender;(function(){var getConsoleHtmlLines=function(){return['<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">','<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">','<head>','<title>log4javascript</title>','<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />','<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->','<meta http-equiv="X-UA-Compatible" content="IE=7" />','<script type="text/javascript">var isIe = false, isIePre7 = false;</script>','<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->','<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->','<script type="text/javascript">','//<![CDATA[','var loggingEnabled=true;var logQueuedEventsTimer=null;var logEntries=[];var logEntriesAndSeparators=[];var logItems=[];var renderDelay=100;var unrenderedLogItemsExist=false;var rootGroup,currentGroup=null;var loaded=false;var currentLogItem=null;var logMainContainer;function copyProperties(obj,props){for(var i in props){obj[i]=props[i];}}','function LogItem(){}','LogItem.prototype={mainContainer:null,wrappedContainer:null,unwrappedContainer:null,group:null,appendToLog:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].appendToLog();}','this.group.update();},doRemove:function(doUpdate,removeFromGroup){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].remove();}','this.unwrappedElementContainer=null;this.wrappedElementContainer=null;this.mainElementContainer=null;}','if(this.group&&removeFromGroup){this.group.removeChild(this,doUpdate);}','if(this===currentLogItem){currentLogItem=null;}},remove:function(doUpdate,removeFromGroup){this.doRemove(doUpdate,removeFromGroup);},render:function(){},accept:function(visitor){visitor.visit(this);},getUnwrappedDomContainer:function(){return this.group.unwrappedElementContainer.contentDiv;},getWrappedDomContainer:function(){return this.group.wrappedElementContainer.contentDiv;},getMainDomContainer:function(){return this.group.mainElementContainer.contentDiv;}};LogItem.serializedItemKeys={LOG_ENTRY:0,GROUP_START:1,GROUP_END:2};function LogItemContainerElement(){}','LogItemContainerElement.prototype={appendToLog:function(){var insertBeforeFirst=(newestAtTop&&this.containerDomNode.hasChildNodes());if(insertBeforeFirst){this.containerDomNode.insertBefore(this.mainDiv,this.containerDomNode.firstChild);}else{this.containerDomNode.appendChild(this.mainDiv);}}};function SeparatorElementContainer(containerDomNode){this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="separator";this.mainDiv.innerHTML="&nbsp;";}','SeparatorElementContainer.prototype=new LogItemContainerElement();SeparatorElementContainer.prototype.remove=function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;};function Separator(){this.rendered=false;}','Separator.prototype=new LogItem();copyProperties(Separator.prototype,{render:function(){var containerDomNode=this.group.contentDiv;if(isIe){this.unwrappedElementContainer=new SeparatorElementContainer(this.getUnwrappedDomContainer());this.wrappedElementContainer=new SeparatorElementContainer(this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new SeparatorElementContainer(this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}','this.content=this.formattedMessage;this.rendered=true;}});function GroupElementContainer(group,containerDomNode,isRoot,isWrapped){this.group=group;this.containerDomNode=containerDomNode;this.isRoot=isRoot;this.isWrapped=isWrapped;this.expandable=false;if(this.isRoot){if(isIe){this.contentDiv=logMainContainer.appendChild(document.createElement("div"));this.contentDiv.id=this.isWrapped?"log_wrapped":"log_unwrapped";}else{this.contentDiv=logMainContainer;}}else{var groupElementContainer=this;this.mainDiv=document.createElement("div");this.mainDiv.className="group";this.headingDiv=this.mainDiv.appendChild(document.createElement("div"));this.headingDiv.className="groupheading";this.expander=this.headingDiv.appendChild(document.createElement("span"));this.expander.className="expander unselectable greyedout";this.expander.unselectable=true;var expanderText=this.group.expanded?"-":"+";this.expanderTextNode=this.expander.appendChild(document.createTextNode(expanderText));this.headingDiv.appendChild(document.createTextNode(" "+this.group.name));this.contentDiv=this.mainDiv.appendChild(document.createElement("div"));var contentCssClass=this.group.expanded?"expanded":"collapsed";this.contentDiv.className="groupcontent "+contentCssClass;this.expander.onclick=function(){if(groupElementContainer.group.expandable){groupElementContainer.group.toggleExpanded();}};}}','GroupElementContainer.prototype=new LogItemContainerElement();copyProperties(GroupElementContainer.prototype,{toggleExpanded:function(){if(!this.isRoot){var oldCssClass,newCssClass,expanderText;if(this.group.expanded){newCssClass="expanded";oldCssClass="collapsed";expanderText="-";}else{newCssClass="collapsed";oldCssClass="expanded";expanderText="+";}','replaceClass(this.contentDiv,newCssClass,oldCssClass);this.expanderTextNode.nodeValue=expanderText;}},remove:function(){if(!this.isRoot){this.headingDiv=null;this.expander.onclick=null;this.expander=null;this.expanderTextNode=null;this.contentDiv=null;this.containerDomNode=null;this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;}},reverseChildren:function(){var node=null;var childDomNodes=[];while((node=this.contentDiv.firstChild)){this.contentDiv.removeChild(node);childDomNodes.push(node);}','while((node=childDomNodes.pop())){this.contentDiv.appendChild(node);}},update:function(){if(!this.isRoot){if(this.group.expandable){removeClass(this.expander,"greyedout");}else{addClass(this.expander,"greyedout");}}},clear:function(){if(this.isRoot){this.contentDiv.innerHTML="";}}});function Group(name,isRoot,initiallyExpanded){this.name=name;this.group=null;this.isRoot=isRoot;this.initiallyExpanded=initiallyExpanded;this.elementContainers=[];this.children=[];this.expanded=initiallyExpanded;this.rendered=false;this.expandable=false;}','Group.prototype=new LogItem();copyProperties(Group.prototype,{addChild:function(logItem){this.children.push(logItem);logItem.group=this;},render:function(){if(isIe){var unwrappedDomContainer,wrappedDomContainer;if(this.isRoot){unwrappedDomContainer=logMainContainer;wrappedDomContainer=logMainContainer;}else{unwrappedDomContainer=this.getUnwrappedDomContainer();wrappedDomContainer=this.getWrappedDomContainer();}','this.unwrappedElementContainer=new GroupElementContainer(this,unwrappedDomContainer,this.isRoot,false);this.wrappedElementContainer=new GroupElementContainer(this,wrappedDomContainer,this.isRoot,true);this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{var mainDomContainer=this.isRoot?logMainContainer:this.getMainDomContainer();this.mainElementContainer=new GroupElementContainer(this,mainDomContainer,this.isRoot,false);this.elementContainers=[this.mainElementContainer];}','this.rendered=true;},toggleExpanded:function(){this.expanded=!this.expanded;for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].toggleExpanded();}},expand:function(){if(!this.expanded){this.toggleExpanded();}},accept:function(visitor){visitor.visitGroup(this);},reverseChildren:function(){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].reverseChildren();}}},update:function(){var previouslyExpandable=this.expandable;this.expandable=(this.children.length!==0);if(this.expandable!==previouslyExpandable){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].update();}}},flatten:function(){var visitor=new GroupFlattener();this.accept(visitor);return visitor.logEntriesAndSeparators;},removeChild:function(child,doUpdate){array_remove(this.children,child);child.group=null;if(doUpdate){this.update();}},remove:function(doUpdate,removeFromGroup){for(var i=0,len=this.children.length;i<len;i++){this.children[i].remove(false,false);}','this.children=[];this.update();if(this===currentGroup){currentGroup=this.group;}','this.doRemove(doUpdate,removeFromGroup);},serialize:function(items){items.push([LogItem.serializedItemKeys.GROUP_START,this.name]);for(var i=0,len=this.children.length;i<len;i++){this.children[i].serialize(items);}','if(this!==currentGroup){items.push([LogItem.serializedItemKeys.GROUP_END]);}},clear:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clear();}}});function LogEntryElementContainer(){}','LogEntryElementContainer.prototype=new LogItemContainerElement();copyProperties(LogEntryElementContainer.prototype,{remove:function(){this.doRemove();},doRemove:function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;this.contentElement=null;this.containerDomNode=null;},setContent:function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=content;}},setSearchMatch:function(isMatch){var oldCssClass=isMatch?"searchnonmatch":"searchmatch";var newCssClass=isMatch?"searchmatch":"searchnonmatch";replaceClass(this.mainDiv,newCssClass,oldCssClass);},clearSearch:function(){removeClass(this.mainDiv,"searchmatch");removeClass(this.mainDiv,"searchnonmatch");}});function LogEntryWrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.mainDiv.className="logentry wrapped "+this.logEntry.level;this.contentElement=this.mainDiv;}','LogEntryWrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryWrappedElementContainer.prototype.setContent=function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=wrappedContent;}};function LogEntryUnwrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry unwrapped "+this.logEntry.level;this.pre=this.mainDiv.appendChild(document.createElement("pre"));this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.pre.className="unwrapped";this.contentElement=this.pre;}','LogEntryUnwrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryUnwrappedElementContainer.prototype.remove=function(){this.doRemove();this.pre=null;};function LogEntryMainElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry nonielogentry "+this.logEntry.level;this.contentElement=this.mainDiv.appendChild(document.createElement("span"));this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));}','LogEntryMainElementContainer.prototype=new LogEntryElementContainer();function LogEntry(level,formattedMessage){this.level=level;this.formattedMessage=formattedMessage;this.rendered=false;}','LogEntry.prototype=new LogItem();copyProperties(LogEntry.prototype,{render:function(){var logEntry=this;var containerDomNode=this.group.contentDiv;if(isIe){this.formattedMessage=this.formattedMessage.replace(/\\r\\n/g,"\\r");this.unwrappedElementContainer=new LogEntryUnwrappedElementContainer(this,this.getUnwrappedDomContainer());this.wrappedElementContainer=new LogEntryWrappedElementContainer(this,this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new LogEntryMainElementContainer(this,this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}','this.content=this.formattedMessage;this.rendered=true;},setContent:function(content,wrappedContent){if(content!=this.content){if(isIe&&(content!==this.formattedMessage)){content=content.replace(/\\r\\n/g,"\\r");}','for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setContent(content,wrappedContent);}','this.content=content;}},getSearchMatches:function(){var matches=[];var i,len;if(isIe){var unwrappedEls=getElementsByClass(this.unwrappedElementContainer.mainDiv,"searchterm","span");var wrappedEls=getElementsByClass(this.wrappedElementContainer.mainDiv,"searchterm","span");for(i=0,len=unwrappedEls.length;i<len;i++){matches[i]=new Match(this.level,null,unwrappedEls[i],wrappedEls[i]);}}else{var els=getElementsByClass(this.mainElementContainer.mainDiv,"searchterm","span");for(i=0,len=els.length;i<len;i++){matches[i]=new Match(this.level,els[i]);}}','return matches;},setSearchMatch:function(isMatch){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setSearchMatch(isMatch);}},clearSearch:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clearSearch();}},accept:function(visitor){visitor.visitLogEntry(this);},serialize:function(items){items.push([LogItem.serializedItemKeys.LOG_ENTRY,this.level,this.formattedMessage]);}});function LogItemVisitor(){}','LogItemVisitor.prototype={visit:function(logItem){},visitParent:function(logItem){if(logItem.group){logItem.group.accept(this);}},visitChildren:function(logItem){for(var i=0,len=logItem.children.length;i<len;i++){logItem.children[i].accept(this);}},visitLogEntry:function(logEntry){this.visit(logEntry);},visitSeparator:function(separator){this.visit(separator);},visitGroup:function(group){this.visit(group);}};function GroupFlattener(){this.logEntriesAndSeparators=[];}','GroupFlattener.prototype=new LogItemVisitor();GroupFlattener.prototype.visitGroup=function(group){this.visitChildren(group);};GroupFlattener.prototype.visitLogEntry=function(logEntry){this.logEntriesAndSeparators.push(logEntry);};GroupFlattener.prototype.visitSeparator=function(separator){this.logEntriesAndSeparators.push(separator);};window.onload=function(){if(location.search){var queryBits=unescape(location.search).substr(1).split("&"),nameValueBits;for(var i=0,len=queryBits.length;i<len;i++){nameValueBits=queryBits[i].split("=");if(nameValueBits[0]=="log4javascript_domain"){document.domain=nameValueBits[1];break;}}}','logMainContainer=$("log");if(isIePre7){addClass(logMainContainer,"oldIe");}','rootGroup=new Group("root",true);rootGroup.render();currentGroup=rootGroup;setCommandInputWidth();setLogContainerHeight();toggleLoggingEnabled();toggleSearchEnabled();toggleSearchFilter();toggleSearchHighlight();applyFilters();checkAllLevels();toggleWrap();toggleNewestAtTop();toggleScrollToLatest();renderQueuedLogItems();loaded=true;$("command").value="";$("command").autocomplete="off";$("command").onkeydown=function(evt){evt=getEvent(evt);if(evt.keyCode==10||evt.keyCode==13){evalCommandLine();stopPropagation(evt);}else if(evt.keyCode==27){this.value="";this.focus();}else if(evt.keyCode==38&&commandHistory.length>0){currentCommandIndex=Math.max(0,currentCommandIndex-1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}else if(evt.keyCode==40&&commandHistory.length>0){currentCommandIndex=Math.min(commandHistory.length-1,currentCommandIndex+1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}};$("command").onkeypress=function(evt){evt=getEvent(evt);if(evt.keyCode==38&&commandHistory.length>0&&evt.preventDefault){evt.preventDefault();}};$("command").onkeyup=function(evt){evt=getEvent(evt);if(evt.keyCode==27&&evt.preventDefault){evt.preventDefault();this.focus();}};document.onkeydown=function keyEventHandler(evt){evt=getEvent(evt);switch(evt.keyCode){case 69:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){evalLastCommand();cancelKeyEvent(evt);return false;}','break;case 75:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusSearch();cancelKeyEvent(evt);return false;}','break;case 40:case 76:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusCommandLine();cancelKeyEvent(evt);return false;}','break;}};setTimeout(setLogContainerHeight,20);setShowCommandLine(showCommandLine);doSearch();};window.onunload=function(){if(mainWindowExists()){appender.unload();}','appender=null;};function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}','function setLoggingEnabled(enable){loggingEnabled=enable;}','var appender=null;function setAppender(appenderParam){appender=appenderParam;}','function setShowCloseButton(showCloseButton){$("closeButton").style.display=showCloseButton?"inline":"none";}','function setShowHideButton(showHideButton){$("hideButton").style.display=showHideButton?"inline":"none";}','var newestAtTop=false;function LogItemContentReverser(){}','LogItemContentReverser.prototype=new LogItemVisitor();LogItemContentReverser.prototype.visitGroup=function(group){group.reverseChildren();this.visitChildren(group);};function setNewestAtTop(isNewestAtTop){var oldNewestAtTop=newestAtTop;var i,iLen,j,jLen;newestAtTop=Boolean(isNewestAtTop);if(oldNewestAtTop!=newestAtTop){var visitor=new LogItemContentReverser();rootGroup.accept(visitor);if(currentSearch){var currentMatch=currentSearch.matches[currentMatchIndex];var matchIndex=0;var matches=[];var actOnLogEntry=function(logEntry){var logEntryMatches=logEntry.getSearchMatches();for(j=0,jLen=logEntryMatches.length;j<jLen;j++){matches[matchIndex]=logEntryMatches[j];if(currentMatch&&logEntryMatches[j].equals(currentMatch)){currentMatchIndex=matchIndex;}','matchIndex++;}};if(newestAtTop){for(i=logEntries.length-1;i>=0;i--){actOnLogEntry(logEntries[i]);}}else{for(i=0,iLen=logEntries.length;i<iLen;i++){actOnLogEntry(logEntries[i]);}}','currentSearch.matches=matches;if(currentMatch){currentMatch.setCurrent();}}else if(scrollToLatest){doScrollToLatest();}}','$("newestAtTop").checked=isNewestAtTop;}','function toggleNewestAtTop(){var isNewestAtTop=$("newestAtTop").checked;setNewestAtTop(isNewestAtTop);}','var scrollToLatest=true;function setScrollToLatest(isScrollToLatest){scrollToLatest=isScrollToLatest;if(scrollToLatest){doScrollToLatest();}','$("scrollToLatest").checked=isScrollToLatest;}','function toggleScrollToLatest(){var isScrollToLatest=$("scrollToLatest").checked;setScrollToLatest(isScrollToLatest);}','function doScrollToLatest(){var l=logMainContainer;if(typeof l.scrollTop!="undefined"){if(newestAtTop){l.scrollTop=0;}else{var latestLogEntry=l.lastChild;if(latestLogEntry){l.scrollTop=l.scrollHeight;}}}}','var closeIfOpenerCloses=true;function setCloseIfOpenerCloses(isCloseIfOpenerCloses){closeIfOpenerCloses=isCloseIfOpenerCloses;}','var maxMessages=null;function setMaxMessages(max){maxMessages=max;pruneLogEntries();}','var showCommandLine=false;function setShowCommandLine(isShowCommandLine){showCommandLine=isShowCommandLine;if(loaded){$("commandLine").style.display=showCommandLine?"block":"none";setCommandInputWidth();setLogContainerHeight();}}','function focusCommandLine(){if(loaded){$("command").focus();}}','function focusSearch(){if(loaded){$("searchBox").focus();}}','function getLogItems(){var items=[];for(var i=0,len=logItems.length;i<len;i++){logItems[i].serialize(items);}','return items;}','function setLogItems(items){var loggingReallyEnabled=loggingEnabled;loggingEnabled=true;for(var i=0,len=items.length;i<len;i++){switch(items[i][0]){case LogItem.serializedItemKeys.LOG_ENTRY:log(items[i][1],items[i][2]);break;case LogItem.serializedItemKeys.GROUP_START:group(items[i][1]);break;case LogItem.serializedItemKeys.GROUP_END:groupEnd();break;}}','loggingEnabled=loggingReallyEnabled;}','function log(logLevel,formattedMessage){if(loggingEnabled){var logEntry=new LogEntry(logLevel,formattedMessage);logEntries.push(logEntry);logEntriesAndSeparators.push(logEntry);logItems.push(logEntry);currentGroup.addChild(logEntry);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}','logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}','function renderQueuedLogItems(){logQueuedEventsTimer=null;var pruned=pruneLogEntries();var initiallyHasMatches=currentSearch?currentSearch.hasMatches():false;for(var i=0,len=logItems.length;i<len;i++){if(!logItems[i].rendered){logItems[i].render();logItems[i].appendToLog();if(currentSearch&&(logItems[i]instanceof LogEntry)){currentSearch.applyTo(logItems[i]);}}}','if(currentSearch){if(pruned){if(currentSearch.hasVisibleMatches()){if(currentMatchIndex===null){setCurrentMatchIndex(0);}','displayMatches();}else{displayNoMatches();}}else if(!initiallyHasMatches&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}}','if(scrollToLatest){doScrollToLatest();}','unrenderedLogItemsExist=false;}','function pruneLogEntries(){if((maxMessages!==null)&&(logEntriesAndSeparators.length>maxMessages)){var numberToDelete=logEntriesAndSeparators.length-maxMessages;var prunedLogEntries=logEntriesAndSeparators.slice(0,numberToDelete);if(currentSearch){currentSearch.removeMatches(prunedLogEntries);}','var group;for(var i=0;i<numberToDelete;i++){group=logEntriesAndSeparators[i].group;array_remove(logItems,logEntriesAndSeparators[i]);array_remove(logEntries,logEntriesAndSeparators[i]);logEntriesAndSeparators[i].remove(true,true);if(group.children.length===0&&group!==currentGroup&&group!==rootGroup){array_remove(logItems,group);group.remove(true,true);}}','logEntriesAndSeparators=array_removeFromStart(logEntriesAndSeparators,numberToDelete);return true;}','return false;}','function group(name,startExpanded){if(loggingEnabled){initiallyExpanded=(typeof startExpanded==="undefined")?true:Boolean(startExpanded);var newGroup=new Group(name,false,initiallyExpanded);currentGroup.addChild(newGroup);currentGroup=newGroup;logItems.push(newGroup);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}','logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}','function groupEnd(){currentGroup=(currentGroup===rootGroup)?rootGroup:currentGroup.group;}','function mainPageReloaded(){currentGroup=rootGroup;var separator=new Separator();logEntriesAndSeparators.push(separator);logItems.push(separator);currentGroup.addChild(separator);}','function closeWindow(){if(appender&&mainWindowExists()){appender.close(true);}else{window.close();}}','function hide(){if(appender&&mainWindowExists()){appender.hide();}}','var mainWindow=window;var windowId="log4javascriptConsoleWindow_"+new Date().getTime()+"_"+(""+Math.random()).substr(2);function setMainWindow(win){mainWindow=win;mainWindow[windowId]=window;if(opener&&closeIfOpenerCloses){pollOpener();}}','function pollOpener(){if(closeIfOpenerCloses){if(mainWindowExists()){setTimeout(pollOpener,500);}else{closeWindow();}}}','function mainWindowExists(){try{return(mainWindow&&!mainWindow.closed&&mainWindow[windowId]==window);}catch(ex){}','return false;}','var logLevels=["TRACE","DEBUG","INFO","WARN","ERROR","FATAL"];function getCheckBox(logLevel){return $("switch_"+logLevel);}','function getIeWrappedLogContainer(){return $("log_wrapped");}','function getIeUnwrappedLogContainer(){return $("log_unwrapped");}','function applyFilters(){for(var i=0;i<logLevels.length;i++){if(getCheckBox(logLevels[i]).checked){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}','updateSearchFromFilters();}','function toggleAllLevels(){var turnOn=$("switch_ALL").checked;for(var i=0;i<logLevels.length;i++){getCheckBox(logLevels[i]).checked=turnOn;if(turnOn){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}}','function checkAllLevels(){for(var i=0;i<logLevels.length;i++){if(!getCheckBox(logLevels[i]).checked){getCheckBox("ALL").checked=false;return;}}','getCheckBox("ALL").checked=true;}','function clearLog(){rootGroup.clear();currentGroup=rootGroup;logEntries=[];logItems=[];logEntriesAndSeparators=[];doSearch();}','function toggleWrap(){var enable=$("wrap").checked;if(enable){addClass(logMainContainer,"wrap");}else{removeClass(logMainContainer,"wrap");}','refreshCurrentMatch();}','var searchTimer=null;function scheduleSearch(){try{clearTimeout(searchTimer);}catch(ex){}','searchTimer=setTimeout(doSearch,500);}','function Search(searchTerm,isRegex,searchRegex,isCaseSensitive){this.searchTerm=searchTerm;this.isRegex=isRegex;this.searchRegex=searchRegex;this.isCaseSensitive=isCaseSensitive;this.matches=[];}','Search.prototype={hasMatches:function(){return this.matches.length>0;},hasVisibleMatches:function(){if(this.hasMatches()){for(var i=0;i<this.matches.length;i++){if(this.matches[i].isVisible()){return true;}}}','return false;},match:function(logEntry){var entryText=String(logEntry.formattedMessage);var matchesSearch=false;if(this.isRegex){matchesSearch=this.searchRegex.test(entryText);}else if(this.isCaseSensitive){matchesSearch=(entryText.indexOf(this.searchTerm)>-1);}else{matchesSearch=(entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase())>-1);}','return matchesSearch;},getNextVisibleMatchIndex:function(){for(var i=currentMatchIndex+1;i<this.matches.length;i++){if(this.matches[i].isVisible()){return i;}}','for(i=0;i<=currentMatchIndex;i++){if(this.matches[i].isVisible()){return i;}}','return-1;},getPreviousVisibleMatchIndex:function(){for(var i=currentMatchIndex-1;i>=0;i--){if(this.matches[i].isVisible()){return i;}}','for(var i=this.matches.length-1;i>=currentMatchIndex;i--){if(this.matches[i].isVisible()){return i;}}','return-1;},applyTo:function(logEntry){var doesMatch=this.match(logEntry);if(doesMatch){logEntry.group.expand();logEntry.setSearchMatch(true);var logEntryContent;var wrappedLogEntryContent;var searchTermReplacementStartTag="<span class=\\\"searchterm\\\">";var searchTermReplacementEndTag="<"+"/span>";var preTagName=isIe?"pre":"span";var preStartTag="<"+preTagName+" class=\\\"pre\\\">";var preEndTag="<"+"/"+preTagName+">";var startIndex=0;var searchIndex,matchedText,textBeforeMatch;if(this.isRegex){var flags=this.isCaseSensitive?"g":"gi";var capturingRegex=new RegExp("("+this.searchRegex.source+")",flags);var rnd=(""+Math.random()).substr(2);var startToken="%%s"+rnd+"%%";var endToken="%%e"+rnd+"%%";logEntryContent=logEntry.formattedMessage.replace(capturingRegex,startToken+"$1"+endToken);logEntryContent=escapeHtml(logEntryContent);var result;var searchString=logEntryContent;logEntryContent="";wrappedLogEntryContent="";while((searchIndex=searchString.indexOf(startToken,startIndex))>-1){var endTokenIndex=searchString.indexOf(endToken,searchIndex);matchedText=searchString.substring(searchIndex+startToken.length,endTokenIndex);textBeforeMatch=searchString.substring(startIndex,searchIndex);logEntryContent+=preStartTag+textBeforeMatch+preEndTag;logEntryContent+=searchTermReplacementStartTag+preStartTag+matchedText+','preEndTag+searchTermReplacementEndTag;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+','matchedText+searchTermReplacementEndTag;}','startIndex=endTokenIndex+endToken.length;}','logEntryContent+=preStartTag+searchString.substr(startIndex)+preEndTag;if(isIe){wrappedLogEntryContent+=searchString.substr(startIndex);}}else{logEntryContent="";wrappedLogEntryContent="";var searchTermReplacementLength=searchTermReplacementStartTag.length+','this.searchTerm.length+searchTermReplacementEndTag.length;var searchTermLength=this.searchTerm.length;var searchTermLowerCase=this.searchTerm.toLowerCase();var logTextLowerCase=logEntry.formattedMessage.toLowerCase();while((searchIndex=logTextLowerCase.indexOf(searchTermLowerCase,startIndex))>-1){matchedText=escapeHtml(logEntry.formattedMessage.substr(searchIndex,this.searchTerm.length));textBeforeMatch=escapeHtml(logEntry.formattedMessage.substring(startIndex,searchIndex));var searchTermReplacement=searchTermReplacementStartTag+','preStartTag+matchedText+preEndTag+searchTermReplacementEndTag;logEntryContent+=preStartTag+textBeforeMatch+preEndTag+searchTermReplacement;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+','matchedText+searchTermReplacementEndTag;}','startIndex=searchIndex+searchTermLength;}','var textAfterLastMatch=escapeHtml(logEntry.formattedMessage.substr(startIndex));logEntryContent+=preStartTag+textAfterLastMatch+preEndTag;if(isIe){wrappedLogEntryContent+=textAfterLastMatch;}}','logEntry.setContent(logEntryContent,wrappedLogEntryContent);var logEntryMatches=logEntry.getSearchMatches();this.matches=this.matches.concat(logEntryMatches);}else{logEntry.setSearchMatch(false);logEntry.setContent(logEntry.formattedMessage,logEntry.formattedMessage);}','return doesMatch;},removeMatches:function(logEntries){var matchesToRemoveCount=0;var currentMatchRemoved=false;var matchesToRemove=[];var i,iLen,j,jLen;for(i=0,iLen=this.matches.length;i<iLen;i++){for(j=0,jLen=logEntries.length;j<jLen;j++){if(this.matches[i].belongsTo(logEntries[j])){matchesToRemove.push(this.matches[i]);if(i===currentMatchIndex){currentMatchRemoved=true;}}}}','var newMatch=currentMatchRemoved?null:this.matches[currentMatchIndex];if(currentMatchRemoved){for(i=currentMatchIndex,iLen=this.matches.length;i<iLen;i++){if(this.matches[i].isVisible()&&!array_contains(matchesToRemove,this.matches[i])){newMatch=this.matches[i];break;}}}','for(i=0,iLen=matchesToRemove.length;i<iLen;i++){array_remove(this.matches,matchesToRemove[i]);matchesToRemove[i].remove();}','if(this.hasVisibleMatches()){if(newMatch===null){setCurrentMatchIndex(0);}else{var newMatchIndex=0;for(i=0,iLen=this.matches.length;i<iLen;i++){if(newMatch===this.matches[i]){newMatchIndex=i;break;}}','setCurrentMatchIndex(newMatchIndex);}}else{currentMatchIndex=null;displayNoMatches();}}};function getPageOffsetTop(el,container){var currentEl=el;var y=0;while(currentEl&&currentEl!=container){y+=currentEl.offsetTop;currentEl=currentEl.offsetParent;}','return y;}','function scrollIntoView(el){var logContainer=logMainContainer;if(!$("wrap").checked){var logContainerLeft=logContainer.scrollLeft;var logContainerRight=logContainerLeft+logContainer.offsetWidth;var elLeft=el.offsetLeft;var elRight=elLeft+el.offsetWidth;if(elLeft<logContainerLeft||elRight>logContainerRight){logContainer.scrollLeft=elLeft-(logContainer.offsetWidth-el.offsetWidth)/2;}}','var logContainerTop=logContainer.scrollTop;var logContainerBottom=logContainerTop+logContainer.offsetHeight;var elTop=getPageOffsetTop(el)-getToolBarsHeight();var elBottom=elTop+el.offsetHeight;if(elTop<logContainerTop||elBottom>logContainerBottom){logContainer.scrollTop=elTop-(logContainer.offsetHeight-el.offsetHeight)/2;}}','function Match(logEntryLevel,spanInMainDiv,spanInUnwrappedPre,spanInWrappedDiv){this.logEntryLevel=logEntryLevel;this.spanInMainDiv=spanInMainDiv;if(isIe){this.spanInUnwrappedPre=spanInUnwrappedPre;this.spanInWrappedDiv=spanInWrappedDiv;}','this.mainSpan=isIe?spanInUnwrappedPre:spanInMainDiv;}','Match.prototype={equals:function(match){return this.mainSpan===match.mainSpan;},setCurrent:function(){if(isIe){addClass(this.spanInUnwrappedPre,"currentmatch");addClass(this.spanInWrappedDiv,"currentmatch");var elementToScroll=$("wrap").checked?this.spanInWrappedDiv:this.spanInUnwrappedPre;scrollIntoView(elementToScroll);}else{addClass(this.spanInMainDiv,"currentmatch");scrollIntoView(this.spanInMainDiv);}},belongsTo:function(logEntry){if(isIe){return isDescendant(this.spanInUnwrappedPre,logEntry.unwrappedPre);}else{return isDescendant(this.spanInMainDiv,logEntry.mainDiv);}},setNotCurrent:function(){if(isIe){removeClass(this.spanInUnwrappedPre,"currentmatch");removeClass(this.spanInWrappedDiv,"currentmatch");}else{removeClass(this.spanInMainDiv,"currentmatch");}},isOrphan:function(){return isOrphan(this.mainSpan);},isVisible:function(){return getCheckBox(this.logEntryLevel).checked;},remove:function(){if(isIe){this.spanInUnwrappedPre=null;this.spanInWrappedDiv=null;}else{this.spanInMainDiv=null;}}};var currentSearch=null;var currentMatchIndex=null;function doSearch(){var searchBox=$("searchBox");var searchTerm=searchBox.value;var isRegex=$("searchRegex").checked;var isCaseSensitive=$("searchCaseSensitive").checked;var i;if(searchTerm===""){$("searchReset").disabled=true;$("searchNav").style.display="none";removeClass(document.body,"searching");removeClass(searchBox,"hasmatches");removeClass(searchBox,"nomatches");for(i=0;i<logEntries.length;i++){logEntries[i].clearSearch();logEntries[i].setContent(logEntries[i].formattedMessage,logEntries[i].formattedMessage);}','currentSearch=null;setLogContainerHeight();}else{$("searchReset").disabled=false;$("searchNav").style.display="block";var searchRegex;var regexValid;if(isRegex){try{searchRegex=isCaseSensitive?new RegExp(searchTerm,"g"):new RegExp(searchTerm,"gi");regexValid=true;replaceClass(searchBox,"validregex","invalidregex");searchBox.title="Valid regex";}catch(ex){regexValid=false;replaceClass(searchBox,"invalidregex","validregex");searchBox.title="Invalid regex: "+(ex.message?ex.message:(ex.description?ex.description:"unknown error"));return;}}else{searchBox.title="";removeClass(searchBox,"validregex");removeClass(searchBox,"invalidregex");}','addClass(document.body,"searching");currentSearch=new Search(searchTerm,isRegex,searchRegex,isCaseSensitive);for(i=0;i<logEntries.length;i++){currentSearch.applyTo(logEntries[i]);}','setLogContainerHeight();if(currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}else{displayNoMatches();}}}','function updateSearchFromFilters(){if(currentSearch){if(currentSearch.hasMatches()){if(currentMatchIndex===null){currentMatchIndex=0;}','var currentMatch=currentSearch.matches[currentMatchIndex];if(currentMatch.isVisible()){displayMatches();setCurrentMatchIndex(currentMatchIndex);}else{currentMatch.setNotCurrent();var nextVisibleMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextVisibleMatchIndex>-1){setCurrentMatchIndex(nextVisibleMatchIndex);displayMatches();}else{displayNoMatches();}}}else{displayNoMatches();}}}','function refreshCurrentMatch(){if(currentSearch&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(currentMatchIndex);}}','function displayMatches(){replaceClass($("searchBox"),"hasmatches","nomatches");$("searchBox").title=""+currentSearch.matches.length+" matches found";$("searchNav").style.display="block";setLogContainerHeight();}','function displayNoMatches(){replaceClass($("searchBox"),"nomatches","hasmatches");$("searchBox").title="No matches found";$("searchNav").style.display="none";setLogContainerHeight();}','function toggleSearchEnabled(enable){enable=(typeof enable=="undefined")?!$("searchDisable").checked:enable;$("searchBox").disabled=!enable;$("searchReset").disabled=!enable;$("searchRegex").disabled=!enable;$("searchNext").disabled=!enable;$("searchPrevious").disabled=!enable;$("searchCaseSensitive").disabled=!enable;$("searchNav").style.display=(enable&&($("searchBox").value!=="")&&currentSearch&&currentSearch.hasVisibleMatches())?"block":"none";if(enable){removeClass($("search"),"greyedout");addClass(document.body,"searching");if($("searchHighlight").checked){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}','if($("searchFilter").checked){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}','$("searchDisable").checked=!enable;}else{addClass($("search"),"greyedout");removeClass(document.body,"searching");removeClass(logMainContainer,"searchhighlight");removeClass(logMainContainer,"searchfilter");}','setLogContainerHeight();}','function toggleSearchFilter(){var enable=$("searchFilter").checked;if(enable){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}','refreshCurrentMatch();}','function toggleSearchHighlight(){var enable=$("searchHighlight").checked;if(enable){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}}','function clearSearch(){$("searchBox").value="";doSearch();}','function searchNext(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var nextMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextMatchIndex>currentMatchIndex||confirm("Reached the end of the page. Start from the top?")){setCurrentMatchIndex(nextMatchIndex);}}}','function searchPrevious(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var previousMatchIndex=currentSearch.getPreviousVisibleMatchIndex();if(previousMatchIndex<currentMatchIndex||confirm("Reached the start of the page. Continue from the bottom?")){setCurrentMatchIndex(previousMatchIndex);}}}','function setCurrentMatchIndex(index){currentMatchIndex=index;currentSearch.matches[currentMatchIndex].setCurrent();}','function addClass(el,cssClass){if(!hasClass(el,cssClass)){if(el.className){el.className+=" "+cssClass;}else{el.className=cssClass;}}}','function hasClass(el,cssClass){if(el.className){var classNames=el.className.split(" ");return array_contains(classNames,cssClass);}','return false;}','function removeClass(el,cssClass){if(hasClass(el,cssClass)){var existingClasses=el.className.split(" ");var newClasses=[];for(var i=0,len=existingClasses.length;i<len;i++){if(existingClasses[i]!=cssClass){newClasses[newClasses.length]=existingClasses[i];}}','el.className=newClasses.join(" ");}}','function replaceClass(el,newCssClass,oldCssClass){removeClass(el,oldCssClass);addClass(el,newCssClass);}','function getElementsByClass(el,cssClass,tagName){var elements=el.getElementsByTagName(tagName);var matches=[];for(var i=0,len=elements.length;i<len;i++){if(hasClass(elements[i],cssClass)){matches.push(elements[i]);}}','return matches;}','function $(id){return document.getElementById(id);}','function isDescendant(node,ancestorNode){while(node!=null){if(node===ancestorNode){return true;}','node=node.parentNode;}','return false;}','function isOrphan(node){var currentNode=node;while(currentNode){if(currentNode==document.body){return false;}','currentNode=currentNode.parentNode;}','return true;}','function escapeHtml(str){return str.replace(/&/g,"&amp;").replace(/[<]/g,"&lt;").replace(/>/g,"&gt;");}','function getWindowWidth(){if(window.innerWidth){return window.innerWidth;}else if(document.documentElement&&document.documentElement.clientWidth){return document.documentElement.clientWidth;}else if(document.body){return document.body.clientWidth;}','return 0;}','function getWindowHeight(){if(window.innerHeight){return window.innerHeight;}else if(document.documentElement&&document.documentElement.clientHeight){return document.documentElement.clientHeight;}else if(document.body){return document.body.clientHeight;}','return 0;}','function getToolBarsHeight(){return $("switches").offsetHeight;}','function getChromeHeight(){var height=getToolBarsHeight();if(showCommandLine){height+=$("commandLine").offsetHeight;}','return height;}','function setLogContainerHeight(){if(logMainContainer){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";logMainContainer.style.height=""+','Math.max(0,windowHeight-getChromeHeight())+"px";}}','function setCommandInputWidth(){if(showCommandLine){$("command").style.width=""+Math.max(0,$("commandLineContainer").offsetWidth-','($("evaluateButton").offsetWidth+13))+"px";}}','window.onresize=function(){setCommandInputWidth();setLogContainerHeight();};if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}','return this.length;};}','if(!Array.prototype.pop){Array.prototype.pop=function(){if(this.length>0){var val=this[this.length-1];this.length=this.length-1;return val;}};}','if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}','this.length=this.length-1;return firstItem;}};}','if(!Array.prototype.splice){Array.prototype.splice=function(startIndex,deleteCount){var itemsAfterDeleted=this.slice(startIndex+deleteCount);var itemsDeleted=this.slice(startIndex,startIndex+deleteCount);this.length=startIndex;var argumentsArray=[];for(var i=0,len=arguments.length;i<len;i++){argumentsArray[i]=arguments[i];}','var itemsToAppend=(argumentsArray.length>2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i<len;i++){this.push(itemsToAppend[i]);}','return itemsDeleted;};}','function array_remove(arr,val){var index=-1;for(var i=0,len=arr.length;i<len;i++){if(arr[i]===val){index=i;break;}}','if(index>=0){arr.splice(index,1);return index;}else{return false;}}','function array_removeFromStart(array,numberToRemove){if(Array.prototype.splice){array.splice(0,numberToRemove);}else{for(var i=numberToRemove,len=array.length;i<len;i++){array[i-numberToRemove]=array[i];}','array.length=array.length-numberToRemove;}','return array;}','function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}','return false;}','function getErrorMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}','return""+ex;}','function moveCaretToEnd(input){if(input.setSelectionRange){input.focus();var length=input.value.length;input.setSelectionRange(length,length);}else if(input.createTextRange){var range=input.createTextRange();range.collapse(false);range.select();}','input.focus();}','function stopPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}}','function getEvent(evt){return evt?evt:event;}','function getTarget(evt){return evt.target?evt.target:evt.srcElement;}','function getRelatedTarget(evt){if(evt.relatedTarget){return evt.relatedTarget;}else if(evt.srcElement){switch(evt.type){case"mouseover":return evt.fromElement;case"mouseout":return evt.toElement;default:return evt.srcElement;}}}','function cancelKeyEvent(evt){evt.returnValue=false;stopPropagation(evt);}','function evalCommandLine(){var expr=$("command").value;evalCommand(expr);$("command").value="";}','function evalLastCommand(){if(lastCommand!=null){evalCommand(lastCommand);}}','var lastCommand=null;var commandHistory=[];var currentCommandIndex=0;function evalCommand(expr){if(appender){appender.evalCommandAndAppend(expr);}else{var prefix=">>> "+expr+"\\r\\n";try{log("INFO",prefix+eval(expr));}catch(ex){log("ERROR",prefix+"Error: "+getErrorMessage(ex));}}','if(expr!=commandHistory[commandHistory.length-1]){commandHistory.push(expr);if(appender){appender.storeCommandHistory(commandHistory);}}','currentCommandIndex=(expr==commandHistory[currentCommandIndex])?currentCommandIndex+1:commandHistory.length;lastCommand=expr;}','//]]>','</script>','<style type="text/css">','body{background-color:white;color:black;padding:0;margin:0;font-family:tahoma,verdana,arial,helvetica,sans-serif;overflow:hidden}div#switchesContainer input{margin-bottom:0}div.toolbar{border-top:solid #ffffff 1px;border-bottom:solid #aca899 1px;background-color:#f1efe7;padding:3px 5px;font-size:68.75%}div.toolbar,div#search input{font-family:tahoma,verdana,arial,helvetica,sans-serif}div.toolbar input.button{padding:0 5px;font-size:100%}div.toolbar input.hidden{display:none}div#switches input#clearButton{margin-left:20px}div#levels label{font-weight:bold}div#levels label,div#options label{margin-right:5px}div#levels label#wrapLabel{font-weight:normal}div#search label{margin-right:10px}div#search label.searchboxlabel{margin-right:0}div#search input{font-size:100%}div#search input.validregex{color:green}div#search input.invalidregex{color:red}div#search input.nomatches{color:white;background-color:#ff6666}div#search input.nomatches{color:white;background-color:#ff6666}div#searchNav{display:none}div#commandLine{display:none}div#commandLine input#command{font-size:100%;font-family:Courier New,Courier}div#commandLine input#evaluateButton{}*.greyedout{color:gray !important;border-color:gray !important}*.greyedout *.alwaysenabled{color:black}*.unselectable{-khtml-user-select:none;-moz-user-select:none;user-select:none}div#log{font-family:Courier New,Courier;font-size:75%;width:100%;overflow:auto;clear:both;position:relative}div.group{border-color:#cccccc;border-style:solid;border-width:1px 0 1px 1px;overflow:visible}div.oldIe div.group,div.oldIe div.group *,div.oldIe *.logentry{height:1%}div.group div.groupheading span.expander{border:solid black 1px;font-family:Courier New,Courier;font-size:0.833em;background-color:#eeeeee;position:relative;top:-1px;color:black;padding:0 2px;cursor:pointer;cursor:hand;height:1%}div.group div.groupcontent{margin-left:10px;padding-bottom:2px;overflow:visible}div.group div.expanded{display:block}div.group div.collapsed{display:none}*.logentry{overflow:visible;display:none;white-space:pre}span.pre{white-space:pre}pre.unwrapped{display:inline !important}pre.unwrapped pre.pre,div.wrapped pre.pre{display:inline}div.wrapped pre.pre{white-space:normal}div.wrapped{display:none}body.searching *.logentry span.currentmatch{color:white !important;background-color:green !important}body.searching div.searchhighlight *.logentry span.searchterm{color:black;background-color:yellow}div.wrap *.logentry{white-space:normal !important;border-width:0 0 1px 0;border-color:#dddddd;border-style:dotted}div.wrap #log_wrapped,#log_unwrapped{display:block}div.wrap #log_unwrapped,#log_wrapped{display:none}div.wrap *.logentry span.pre{overflow:visible;white-space:normal}div.wrap *.logentry pre.unwrapped{display:none}div.wrap *.logentry span.wrapped{display:inline}div.searchfilter *.searchnonmatch{display:none !important}div#log *.TRACE,label#label_TRACE{color:#666666}div#log *.DEBUG,label#label_DEBUG{color:green}div#log *.INFO,label#label_INFO{color:#000099}div#log *.WARN,label#label_WARN{color:#999900}div#log *.ERROR,label#label_ERROR{color:red}div#log *.FATAL,label#label_FATAL{color:#660066}div.TRACE#log *.TRACE,div.DEBUG#log *.DEBUG,div.INFO#log *.INFO,div.WARN#log *.WARN,div.ERROR#log *.ERROR,div.FATAL#log *.FATAL{display:block}div#log div.separator{background-color:#cccccc;margin:5px 0;line-height:1px}','</style>','</head>','<body id="body">','<div id="switchesContainer">','<div id="switches">','<div id="levels" class="toolbar">','Filters:','<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>','<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>','<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>','<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>','<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>','<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>','<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>','</div>','<div id="search" class="toolbar">','<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />','<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />','<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>','<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>','<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>','<div id="searchNav">','<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />','<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />','<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>','<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>','</div>','</div>','<div id="options" class="toolbar">','Options:','<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>','<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>','<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>','<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>','<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />','<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />','<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />','</div>','</div>','</div>','<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>','<div id="commandLine" class="toolbar">','<div id="commandLineContainer">','<input type="text" id="command" title="Enter a JavaScript command here and hit return or press \'Evaluate\'" />','<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />','</div>','</div>','</body>','</html>',''];};var defaultCommandLineFunctions=[];ConsoleAppender=function(){};var consoleAppenderIdCounter=1;ConsoleAppender.prototype=new Appender();ConsoleAppender.prototype.create=function(inPage,container,lazyInit,initiallyMinimized,useDocumentWrite,width,height,focusConsoleWindow){var appender=this;var initialized=false;var consoleWindowCreated=false;var consoleWindowLoaded=false;var consoleClosed=false;var queuedLoggingEvents=[];var isSupported=true;var consoleAppenderId=consoleAppenderIdCounter++;initiallyMinimized=extractBooleanFromParam(initiallyMinimized,this.defaults.initiallyMinimized);lazyInit=extractBooleanFromParam(lazyInit,this.defaults.lazyInit);useDocumentWrite=extractBooleanFromParam(useDocumentWrite,this.defaults.useDocumentWrite);var newestMessageAtTop=this.defaults.newestMessageAtTop;var scrollToLatestMessage=this.defaults.scrollToLatestMessage;width=width?width:this.defaults.width;height=height?height:this.defaults.height;var maxMessages=this.defaults.maxMessages;var showCommandLine=this.defaults.showCommandLine;var commandLineObjectExpansionDepth=this.defaults.commandLineObjectExpansionDepth;var showHideButton=this.defaults.showHideButton;var showCloseButton=this.defaults.showCloseButton;var showLogEntryDeleteButtons=this.defaults.showLogEntryDeleteButtons;this.setLayout(this.defaults.layout);var init,createWindow,safeToAppend,getConsoleWindow,open;var appenderName=inPage?"InPageAppender":"PopUpAppender";var checkCanConfigure=function(configOptionName){if(consoleWindowCreated){handleError(appenderName+": configuration option '"+configOptionName+"' may not be set after the appender has been initialized");return false;}

+return true;};var consoleWindowExists=function(){return(consoleWindowLoaded&&isSupported&&!consoleClosed);};this.isNewestMessageAtTop=function(){return newestMessageAtTop;};this.setNewestMessageAtTop=function(newestMessageAtTopParam){newestMessageAtTop=bool(newestMessageAtTopParam);if(consoleWindowExists()){getConsoleWindow().setNewestAtTop(newestMessageAtTop);}};this.isScrollToLatestMessage=function(){return scrollToLatestMessage;};this.setScrollToLatestMessage=function(scrollToLatestMessageParam){scrollToLatestMessage=bool(scrollToLatestMessageParam);if(consoleWindowExists()){getConsoleWindow().setScrollToLatest(scrollToLatestMessage);}};this.getWidth=function(){return width;};this.setWidth=function(widthParam){if(checkCanConfigure("width")){width=extractStringFromParam(widthParam,width);}};this.getHeight=function(){return height;};this.setHeight=function(heightParam){if(checkCanConfigure("height")){height=extractStringFromParam(heightParam,height);}};this.getMaxMessages=function(){return maxMessages;};this.setMaxMessages=function(maxMessagesParam){maxMessages=extractIntFromParam(maxMessagesParam,maxMessages);if(consoleWindowExists()){getConsoleWindow().setMaxMessages(maxMessages);}};this.isShowCommandLine=function(){return showCommandLine;};this.setShowCommandLine=function(showCommandLineParam){showCommandLine=bool(showCommandLineParam);if(consoleWindowExists()){getConsoleWindow().setShowCommandLine(showCommandLine);}};this.isShowHideButton=function(){return showHideButton;};this.setShowHideButton=function(showHideButtonParam){showHideButton=bool(showHideButtonParam);if(consoleWindowExists()){getConsoleWindow().setShowHideButton(showHideButton);}};this.isShowCloseButton=function(){return showCloseButton;};this.setShowCloseButton=function(showCloseButtonParam){showCloseButton=bool(showCloseButtonParam);if(consoleWindowExists()){getConsoleWindow().setShowCloseButton(showCloseButton);}};this.getCommandLineObjectExpansionDepth=function(){return commandLineObjectExpansionDepth;};this.setCommandLineObjectExpansionDepth=function(commandLineObjectExpansionDepthParam){commandLineObjectExpansionDepth=extractIntFromParam(commandLineObjectExpansionDepthParam,commandLineObjectExpansionDepth);};var minimized=initiallyMinimized;this.isInitiallyMinimized=function(){return initiallyMinimized;};this.setInitiallyMinimized=function(initiallyMinimizedParam){if(checkCanConfigure("initiallyMinimized")){initiallyMinimized=bool(initiallyMinimizedParam);minimized=initiallyMinimized;}};this.isUseDocumentWrite=function(){return useDocumentWrite;};this.setUseDocumentWrite=function(useDocumentWriteParam){if(checkCanConfigure("useDocumentWrite")){useDocumentWrite=bool(useDocumentWriteParam);}};function QueuedLoggingEvent(loggingEvent,formattedMessage){this.loggingEvent=loggingEvent;this.levelName=loggingEvent.level.name;this.formattedMessage=formattedMessage;}

+QueuedLoggingEvent.prototype.append=function(){getConsoleWindow().log(this.levelName,this.formattedMessage);};function QueuedGroup(name,initiallyExpanded){this.name=name;this.initiallyExpanded=initiallyExpanded;}

+QueuedGroup.prototype.append=function(){getConsoleWindow().group(this.name,this.initiallyExpanded);};function QueuedGroupEnd(){}

+QueuedGroupEnd.prototype.append=function(){getConsoleWindow().groupEnd();};var checkAndAppend=function(){safeToAppend();if(!initialized){init();}else if(consoleClosed&&reopenWhenClosed){createWindow();}

+if(safeToAppend()){appendQueuedLoggingEvents();}};this.append=function(loggingEvent){if(isSupported){var formattedMessage=appender.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();}

+queuedLoggingEvents.push(new QueuedLoggingEvent(loggingEvent,formattedMessage));checkAndAppend();}};this.group=function(name,initiallyExpanded){if(isSupported){queuedLoggingEvents.push(new QueuedGroup(name,initiallyExpanded));checkAndAppend();}};this.groupEnd=function(){if(isSupported){queuedLoggingEvents.push(new QueuedGroupEnd());checkAndAppend();}};var appendQueuedLoggingEvents=function(){var currentLoggingEvent;while(queuedLoggingEvents.length>0){queuedLoggingEvents.shift().append();}

+if(focusConsoleWindow){getConsoleWindow().focus();}};this.setAddedToLogger=function(logger){this.loggers.push(logger);if(enabled&&!lazyInit){init();}};this.clear=function(){if(consoleWindowExists()){getConsoleWindow().clearLog();}

+queuedLoggingEvents.length=0;};this.focus=function(){if(consoleWindowExists()){getConsoleWindow().focus();}};this.focusCommandLine=function(){if(consoleWindowExists()){getConsoleWindow().focusCommandLine();}};this.focusSearch=function(){if(consoleWindowExists()){getConsoleWindow().focusSearch();}};var commandWindow=window;this.getCommandWindow=function(){return commandWindow;};this.setCommandWindow=function(commandWindowParam){commandWindow=commandWindowParam;};this.executeLastCommand=function(){if(consoleWindowExists()){getConsoleWindow().evalLastCommand();}};var commandLayout=new PatternLayout("%m");this.getCommandLayout=function(){return commandLayout;};this.setCommandLayout=function(commandLayoutParam){commandLayout=commandLayoutParam;};this.evalCommandAndAppend=function(expr){var commandReturnValue={appendResult:true,isError:false};var commandOutput="";try{var result,i;if(!commandWindow.eval&&commandWindow.execScript){commandWindow.execScript("null");}

+var commandLineFunctionsHash={};for(i=0,len=commandLineFunctions.length;i<len;i++){commandLineFunctionsHash[commandLineFunctions[i][0]]=commandLineFunctions[i][1];}

+var objectsToRestore=[];var addObjectToRestore=function(name){objectsToRestore.push([name,commandWindow[name]]);};addObjectToRestore("appender");commandWindow.appender=appender;addObjectToRestore("commandReturnValue");commandWindow.commandReturnValue=commandReturnValue;addObjectToRestore("commandLineFunctionsHash");commandWindow.commandLineFunctionsHash=commandLineFunctionsHash;var addFunctionToWindow=function(name){addObjectToRestore(name);commandWindow[name]=function(){return this.commandLineFunctionsHash[name](appender,arguments,commandReturnValue);};};for(i=0,len=commandLineFunctions.length;i<len;i++){addFunctionToWindow(commandLineFunctions[i][0]);}

+if(commandWindow===window&&commandWindow.execScript){addObjectToRestore("evalExpr");addObjectToRestore("result");window.evalExpr=expr;commandWindow.execScript("window.result=eval(window.evalExpr);");result=window.result;}else{result=commandWindow.eval(expr);}

+commandOutput=isUndefined(result)?result:formatObjectExpansion(result,commandLineObjectExpansionDepth);for(i=0,len=objectsToRestore.length;i<len;i++){commandWindow[objectsToRestore[i][0]]=objectsToRestore[i][1];}}catch(ex){commandOutput="Error evaluating command: "+getExceptionStringRep(ex);commandReturnValue.isError=true;}

+if(commandReturnValue.appendResult){var message=">>> "+expr;if(!isUndefined(commandOutput)){message+=newLine+commandOutput;}

+var level=commandReturnValue.isError?Level.ERROR:Level.INFO;var loggingEvent=new LoggingEvent(null,new Date(),level,[message],null);var mainLayout=this.getLayout();this.setLayout(commandLayout);this.append(loggingEvent);this.setLayout(mainLayout);}};var commandLineFunctions=defaultCommandLineFunctions.concat([]);this.addCommandLineFunction=function(functionName,commandLineFunction){commandLineFunctions.push([functionName,commandLineFunction]);};var commandHistoryCookieName="log4javascriptCommandHistory";this.storeCommandHistory=function(commandHistory){setCookie(commandHistoryCookieName,commandHistory.join(","));};var writeHtml=function(doc){var lines=getConsoleHtmlLines();doc.open();for(var i=0,len=lines.length;i<len;i++){doc.writeln(lines[i]);}

+doc.close();};this.setEventTypes(["load","unload"]);var consoleWindowLoadHandler=function(){var win=getConsoleWindow();win.setAppender(appender);win.setNewestAtTop(newestMessageAtTop);win.setScrollToLatest(scrollToLatestMessage);win.setMaxMessages(maxMessages);win.setShowCommandLine(showCommandLine);win.setShowHideButton(showHideButton);win.setShowCloseButton(showCloseButton);win.setMainWindow(window);var storedValue=getCookie(commandHistoryCookieName);if(storedValue){win.commandHistory=storedValue.split(",");win.currentCommandIndex=win.commandHistory.length;}

+appender.dispatchEvent("load",{"win":win});};this.unload=function(){logLog.debug("unload "+this+", caller: "+this.unload.caller);if(!consoleClosed){logLog.debug("really doing unload "+this);consoleClosed=true;consoleWindowLoaded=false;consoleWindowCreated=false;appender.dispatchEvent("unload",{});}};var pollConsoleWindow=function(windowTest,interval,successCallback,errorMessage){function doPoll(){try{if(consoleClosed){clearInterval(poll);}

+if(windowTest(getConsoleWindow())){clearInterval(poll);successCallback();}}catch(ex){clearInterval(poll);isSupported=false;handleError(errorMessage,ex);}}

+var poll=setInterval(doPoll,interval);};var getConsoleUrl=function(){var documentDomainSet=(document.domain!=location.hostname);return useDocumentWrite?"":getBaseUrl()+"console.html"+

+(documentDomainSet?"?log4javascript_domain="+escape(document.domain):"");};if(inPage){var containerElement=null;var cssProperties=[];this.addCssProperty=function(name,value){if(checkCanConfigure("cssProperties")){cssProperties.push([name,value]);}};var windowCreationStarted=false;var iframeContainerDiv;var iframeId=uniqueId+"_InPageAppender_"+consoleAppenderId;this.hide=function(){if(initialized&&consoleWindowCreated){if(consoleWindowExists()){getConsoleWindow().$("command").blur();}

+iframeContainerDiv.style.display="none";minimized=true;}};this.show=function(){if(initialized){if(consoleWindowCreated){iframeContainerDiv.style.display="block";this.setShowCommandLine(showCommandLine);minimized=false;}else if(!windowCreationStarted){createWindow(true);}}};this.isVisible=function(){return!minimized&&!consoleClosed;};this.close=function(fromButton){if(!consoleClosed&&(!fromButton||confirm("This will permanently remove the console from the page. No more messages will be logged. Do you wish to continue?"))){iframeContainerDiv.parentNode.removeChild(iframeContainerDiv);this.unload();}};open=function(){var initErrorMessage="InPageAppender.open: unable to create console iframe";function finalInit(){try{if(!initiallyMinimized){appender.show();}

+consoleWindowLoadHandler();consoleWindowLoaded=true;appendQueuedLoggingEvents();}catch(ex){isSupported=false;handleError(initErrorMessage,ex);}}

+function writeToDocument(){try{var windowTest=function(win){return isLoaded(win);};if(useDocumentWrite){writeHtml(getConsoleWindow().document);}

+if(windowTest(getConsoleWindow())){finalInit();}else{pollConsoleWindow(windowTest,100,finalInit,initErrorMessage);}}catch(ex){isSupported=false;handleError(initErrorMessage,ex);}}

+minimized=false;iframeContainerDiv=containerElement.appendChild(document.createElement("div"));iframeContainerDiv.style.width=width;iframeContainerDiv.style.height=height;iframeContainerDiv.style.border="solid gray 1px";for(var i=0,len=cssProperties.length;i<len;i++){iframeContainerDiv.style[cssProperties[i][0]]=cssProperties[i][1];}

+var iframeSrc=useDocumentWrite?"":" src='"+getConsoleUrl()+"'";iframeContainerDiv.innerHTML="<iframe id='"+iframeId+"' name='"+iframeId+"' width='100%' height='100%' frameborder='0'"+iframeSrc+" scrolling='no'></iframe>";consoleClosed=false;var iframeDocumentExistsTest=function(win){try{return bool(win)&&bool(win.document);}catch(ex){return false;}};if(iframeDocumentExistsTest(getConsoleWindow())){writeToDocument();}else{pollConsoleWindow(iframeDocumentExistsTest,100,writeToDocument,initErrorMessage);}

+consoleWindowCreated=true;};createWindow=function(show){if(show||!initiallyMinimized){var pageLoadHandler=function(){if(!container){containerElement=document.createElement("div");containerElement.style.position="fixed";containerElement.style.left="0";containerElement.style.right="0";containerElement.style.bottom="0";document.body.appendChild(containerElement);appender.addCssProperty("borderWidth","1px 0 0 0");appender.addCssProperty("zIndex",1000000);open();}else{try{var el=document.getElementById(container);if(el.nodeType==1){containerElement=el;}

+open();}catch(ex){handleError("InPageAppender.init: invalid container element '"+container+"' supplied",ex);}}};if(pageLoaded&&container&&container.appendChild){containerElement=container;open();}else if(pageLoaded){pageLoadHandler();}else{log4javascript.addEventListener("load",pageLoadHandler);}

+windowCreationStarted=true;}};init=function(){createWindow();initialized=true;};getConsoleWindow=function(){var iframe=window.frames[iframeId];if(iframe){return iframe;}};safeToAppend=function(){if(isSupported&&!consoleClosed){if(consoleWindowCreated&&!consoleWindowLoaded&&getConsoleWindow()&&isLoaded(getConsoleWindow())){consoleWindowLoaded=true;}

+return consoleWindowLoaded;}

+return false;};}else{var useOldPopUp=appender.defaults.useOldPopUp;var complainAboutPopUpBlocking=appender.defaults.complainAboutPopUpBlocking;var reopenWhenClosed=this.defaults.reopenWhenClosed;this.isUseOldPopUp=function(){return useOldPopUp;};this.setUseOldPopUp=function(useOldPopUpParam){if(checkCanConfigure("useOldPopUp")){useOldPopUp=bool(useOldPopUpParam);}};this.isComplainAboutPopUpBlocking=function(){return complainAboutPopUpBlocking;};this.setComplainAboutPopUpBlocking=function(complainAboutPopUpBlockingParam){if(checkCanConfigure("complainAboutPopUpBlocking")){complainAboutPopUpBlocking=bool(complainAboutPopUpBlockingParam);}};this.isFocusPopUp=function(){return focusConsoleWindow;};this.setFocusPopUp=function(focusPopUpParam){focusConsoleWindow=bool(focusPopUpParam);};this.isReopenWhenClosed=function(){return reopenWhenClosed;};this.setReopenWhenClosed=function(reopenWhenClosedParam){reopenWhenClosed=bool(reopenWhenClosedParam);};this.close=function(){logLog.debug("close "+this);try{popUp.close();this.unload();}catch(ex){}};this.hide=function(){logLog.debug("hide "+this);if(consoleWindowExists()){this.close();}};this.show=function(){logLog.debug("show "+this);if(!consoleWindowCreated){open();}};this.isVisible=function(){return safeToAppend();};var popUp;open=function(){var windowProperties="width="+width+",height="+height+",status,resizable";var frameInfo="";try{var frameEl=window.frameElement;if(frameEl){frameInfo="_"+frameEl.tagName+"_"+(frameEl.name||frameEl.id||"");}}catch(e){frameInfo="_inaccessibleParentFrame";}

+var windowName="PopUp_"+location.host.replace(/[^a-z0-9]/gi,"_")+"_"+consoleAppenderId+frameInfo;if(!useOldPopUp||!useDocumentWrite){windowName=windowName+"_"+uniqueId;}

+var checkPopUpClosed=function(win){if(consoleClosed){return true;}else{try{return bool(win)&&win.closed;}catch(ex){}}

+return false;};var popUpClosedCallback=function(){if(!consoleClosed){appender.unload();}};function finalInit(){getConsoleWindow().setCloseIfOpenerCloses(!useOldPopUp||!useDocumentWrite);consoleWindowLoadHandler();consoleWindowLoaded=true;appendQueuedLoggingEvents();pollConsoleWindow(checkPopUpClosed,500,popUpClosedCallback,"PopUpAppender.checkPopUpClosed: error checking pop-up window");}

+try{popUp=window.open(getConsoleUrl(),windowName,windowProperties);consoleClosed=false;consoleWindowCreated=true;if(popUp&&popUp.document){if(useDocumentWrite&&useOldPopUp&&isLoaded(popUp)){popUp.mainPageReloaded();finalInit();}else{if(useDocumentWrite){writeHtml(popUp.document);}

+var popUpLoadedTest=function(win){return bool(win)&&isLoaded(win);};if(isLoaded(popUp)){finalInit();}else{pollConsoleWindow(popUpLoadedTest,100,finalInit,"PopUpAppender.init: unable to create console window");}}}else{isSupported=false;logLog.warn("PopUpAppender.init: pop-ups blocked, please unblock to use PopUpAppender");if(complainAboutPopUpBlocking){handleError("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");}}}catch(ex){handleError("PopUpAppender.init: error creating pop-up",ex);}};createWindow=function(){if(!initiallyMinimized){open();}};init=function(){createWindow();initialized=true;};getConsoleWindow=function(){return popUp;};safeToAppend=function(){if(isSupported&&!isUndefined(popUp)&&!consoleClosed){if(popUp.closed||(consoleWindowLoaded&&isUndefined(popUp.closed))){appender.unload();logLog.debug("PopUpAppender: pop-up closed");return false;}

+if(!consoleWindowLoaded&&isLoaded(popUp)){consoleWindowLoaded=true;}}

+return isSupported&&consoleWindowLoaded&&!consoleClosed;};}

+this.getConsoleWindow=getConsoleWindow;};ConsoleAppender.addGlobalCommandLineFunction=function(functionName,commandLineFunction){defaultCommandLineFunctions.push([functionName,commandLineFunction]);};function PopUpAppender(lazyInit,initiallyMinimized,useDocumentWrite,width,height){this.create(false,null,lazyInit,initiallyMinimized,useDocumentWrite,width,height,this.defaults.focusPopUp);}

+PopUpAppender.prototype=new ConsoleAppender();PopUpAppender.prototype.defaults={layout:new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),initiallyMinimized:false,focusPopUp:false,lazyInit:true,useOldPopUp:true,complainAboutPopUpBlocking:true,newestMessageAtTop:false,scrollToLatestMessage:true,width:"600",height:"400",reopenWhenClosed:false,maxMessages:null,showCommandLine:true,commandLineObjectExpansionDepth:1,showHideButton:false,showCloseButton:true,showLogEntryDeleteButtons:true,useDocumentWrite:true};PopUpAppender.prototype.toString=function(){return"PopUpAppender";};log4javascript.PopUpAppender=PopUpAppender;function InPageAppender(container,lazyInit,initiallyMinimized,useDocumentWrite,width,height){this.create(true,container,lazyInit,initiallyMinimized,useDocumentWrite,width,height,false);}

+InPageAppender.prototype=new ConsoleAppender();InPageAppender.prototype.defaults={layout:new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),initiallyMinimized:false,lazyInit:true,newestMessageAtTop:false,scrollToLatestMessage:true,width:"100%",height:"220px",maxMessages:null,showCommandLine:true,commandLineObjectExpansionDepth:1,showHideButton:false,showCloseButton:false,showLogEntryDeleteButtons:true,useDocumentWrite:true};InPageAppender.prototype.toString=function(){return"InPageAppender";};log4javascript.InPageAppender=InPageAppender;log4javascript.InlineAppender=InPageAppender;})();function padWithSpaces(str,len){if(str.length<len){var spaces=[];var numberOfSpaces=Math.max(0,len-str.length);for(var i=0;i<numberOfSpaces;i++){spaces[i]=" ";}

+str+=spaces.join("");}

+return str;}

+(function(){function dir(obj){var maxLen=0;for(var p in obj){maxLen=Math.max(toStr(p).length,maxLen);}

+var propList=[];for(p in obj){var propNameStr="  "+padWithSpaces(toStr(p),maxLen+2);var propVal;try{propVal=splitIntoLines(toStr(obj[p])).join(padWithSpaces(newLine,maxLen+6));}catch(ex){propVal="[Error obtaining property. Details: "+getExceptionMessage(ex)+"]";}

+propList.push(propNameStr+propVal);}

+return propList.join(newLine);}

+var nodeTypes={ELEMENT_NODE:1,ATTRIBUTE_NODE:2,TEXT_NODE:3,CDATA_SECTION_NODE:4,ENTITY_REFERENCE_NODE:5,ENTITY_NODE:6,PROCESSING_INSTRUCTION_NODE:7,COMMENT_NODE:8,DOCUMENT_NODE:9,DOCUMENT_TYPE_NODE:10,DOCUMENT_FRAGMENT_NODE:11,NOTATION_NODE:12};var preFormattedElements=["script","pre"];var emptyElements=["br","img","hr","param","link","area","input","col","base","meta"];var indentationUnit="  ";function getXhtml(rootNode,includeRootNode,indentation,startNewLine,preformatted){includeRootNode=(typeof includeRootNode=="undefined")?true:!!includeRootNode;if(typeof indentation!="string"){indentation="";}

+startNewLine=!!startNewLine;preformatted=!!preformatted;var xhtml;function isWhitespace(node){return((node.nodeType==nodeTypes.TEXT_NODE)&&/^[ \t\r\n]*$/.test(node.nodeValue));}

+function fixAttributeValue(attrValue){return attrValue.toString().replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/"/g,"&quot;");}

+function getStyleAttributeValue(el){var stylePairs=el.style.cssText.split(";");var styleValue="";var isFirst=true;for(var j=0,len=stylePairs.length;j<len;j++){var nameValueBits=stylePairs[j].split(":");var props=[];if(!/^\s*$/.test(nameValueBits[0])){props.push(trim(nameValueBits[0]).toLowerCase()+":"+trim(nameValueBits[1]));}

+styleValue=props.join(";");}

+return styleValue;}

+function getNamespace(el){if(el.prefix){return el.prefix;}else if(el.outerHTML){var regex=new RegExp("<([^:]+):"+el.tagName+"[^>]*>","i");if(regex.test(el.outerHTML)){return RegExp.$1.toLowerCase();}}

+return"";}

+var lt="<";var gt=">";if(includeRootNode&&rootNode.nodeType!=nodeTypes.DOCUMENT_FRAGMENT_NODE){switch(rootNode.nodeType){case nodeTypes.ELEMENT_NODE:var tagName=rootNode.tagName.toLowerCase();xhtml=startNewLine?newLine+indentation:"";xhtml+=lt;var prefix=getNamespace(rootNode);var hasPrefix=!!prefix;if(hasPrefix){xhtml+=prefix+":";}

+xhtml+=tagName;for(i=0,len=rootNode.attributes.length;i<len;i++){var currentAttr=rootNode.attributes[i];if(!currentAttr.specified||currentAttr.nodeValue===null||currentAttr.nodeName.toLowerCase()==="style"||typeof currentAttr.nodeValue!=="string"||currentAttr.nodeName.indexOf("_moz")===0){continue;}

+xhtml+=" "+currentAttr.nodeName.toLowerCase()+"=\"";xhtml+=fixAttributeValue(currentAttr.nodeValue);xhtml+="\"";}

+if(rootNode.style.cssText){var styleValue=getStyleAttributeValue(rootNode);if(styleValue!==""){xhtml+=" style=\""+getStyleAttributeValue(rootNode)+"\"";}}

+if(array_contains(emptyElements,tagName)||(hasPrefix&&!rootNode.hasChildNodes())){xhtml+="/"+gt;}else{xhtml+=gt;var childStartNewLine=!(rootNode.childNodes.length===1&&rootNode.childNodes[0].nodeType===nodeTypes.TEXT_NODE);var childPreformatted=array_contains(preFormattedElements,tagName);for(var i=0,len=rootNode.childNodes.length;i<len;i++){xhtml+=getXhtml(rootNode.childNodes[i],true,indentation+indentationUnit,childStartNewLine,childPreformatted);}

+var endTag=lt+"/"+tagName+gt;xhtml+=childStartNewLine?newLine+indentation+endTag:endTag;}

+return xhtml;case nodeTypes.TEXT_NODE:if(isWhitespace(rootNode)){xhtml="";}else{if(preformatted){xhtml=rootNode.nodeValue;}else{var lines=splitIntoLines(trim(rootNode.nodeValue));var trimmedLines=[];for(var i=0,len=lines.length;i<len;i++){trimmedLines[i]=trim(lines[i]);}

+xhtml=trimmedLines.join(newLine+indentation);}

+if(startNewLine){xhtml=newLine+indentation+xhtml;}}

+return xhtml;case nodeTypes.CDATA_SECTION_NODE:return"<![CDA"+"TA["+rootNode.nodeValue+"]"+"]>"+newLine;case nodeTypes.DOCUMENT_NODE:xhtml="";for(var i=0,len=rootNode.childNodes.length;i<len;i++){xhtml+=getXhtml(rootNode.childNodes[i],true,indentation);}

+return xhtml;default:return"";}}else{xhtml="";for(var i=0,len=rootNode.childNodes.length;i<len;i++){xhtml+=getXhtml(rootNode.childNodes[i],true,indentation+indentationUnit);}

+return xhtml;}}

+function createCommandLineFunctions(){ConsoleAppender.addGlobalCommandLineFunction("$",function(appender,args,returnValue){return document.getElementById(args[0]);});ConsoleAppender.addGlobalCommandLineFunction("dir",function(appender,args,returnValue){var lines=[];for(var i=0,len=args.length;i<len;i++){lines[i]=dir(args[i]);}

+return lines.join(newLine+newLine);});ConsoleAppender.addGlobalCommandLineFunction("dirxml",function(appender,args,returnValue){var lines=[];for(var i=0,len=args.length;i<len;i++){var win=appender.getCommandWindow();lines[i]=getXhtml(args[i]);}

+return lines.join(newLine+newLine);});ConsoleAppender.addGlobalCommandLineFunction("cd",function(appender,args,returnValue){var win,message;if(args.length===0||args[0]===""){win=window;message="Command line set to run in main window";}else{if(args[0].window==args[0]){win=args[0];message="Command line set to run in frame '"+args[0].name+"'";}else{win=window.frames[args[0]];if(win){message="Command line set to run in frame '"+args[0]+"'";}else{returnValue.isError=true;message="Frame '"+args[0]+"' does not exist";win=appender.getCommandWindow();}}}

+appender.setCommandWindow(win);return message;});ConsoleAppender.addGlobalCommandLineFunction("clear",function(appender,args,returnValue){returnValue.appendResult=false;appender.clear();});ConsoleAppender.addGlobalCommandLineFunction("keys",function(appender,args,returnValue){var keys=[];for(var k in args[0]){keys.push(k);}

+return keys;});ConsoleAppender.addGlobalCommandLineFunction("values",function(appender,args,returnValue){var values=[];for(var k in args[0]){try{values.push(args[0][k]);}catch(ex){logLog.warn("values(): Unable to obtain value for key "+k+". Details: "+getExceptionMessage(ex));}}

+return values;});ConsoleAppender.addGlobalCommandLineFunction("expansionDepth",function(appender,args,returnValue){var expansionDepth=parseInt(args[0],10);if(isNaN(expansionDepth)||expansionDepth<0){returnValue.isError=true;return""+args[0]+" is not a valid expansion depth";}else{appender.setCommandLineObjectExpansionDepth(expansionDepth);return"Object expansion depth set to "+expansionDepth;}});}

+function init(){createCommandLineFunctions();}

+init();})();log4javascript.setDocumentReady=function(){pageLoaded=true;log4javascript.dispatchEvent("load",{});};if(window.addEventListener){window.addEventListener("load",log4javascript.setDocumentReady,false);}else if(window.attachEvent){window.attachEvent("onload",log4javascript.setDocumentReady);}else{var oldOnload=window.onload;if(typeof window.onload!="function"){window.onload=log4javascript.setDocumentReady;}else{window.onload=function(evt){if(oldOnload){oldOnload(evt);}

+log4javascript.setDocumentReady();};}}

+window.log4javascript=log4javascript;return log4javascript;})();

diff --git a/planetstack/core/static/log4javascript-1.4.6/log4javascript_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/log4javascript_uncompressed.js
new file mode 100644
index 0000000..a644e3b
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/log4javascript_uncompressed.js
@@ -0,0 +1,5879 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+/**

+ * log4javascript

+ *

+ * log4javascript is a logging framework for JavaScript based on log4j

+ * for Java. This file contains all core log4javascript code and is the only

+ * file required to use log4javascript, unless you require support for

+ * document.domain, in which case you will also need console.html, which must be

+ * stored in the same directory as the main log4javascript.js file.

+ *

+ * Author: Tim Down <tim@log4javascript.org>

+ * Version: 1.4.6

+ * Edition: log4javascript

+ * Build date: 19 March 2013

+ * Website: http://log4javascript.org

+ */

+

+/* -------------------------------------------------------------------------- */

+// Array-related stuff

+

+// Next three methods are solely for IE5, which is missing them

+if (!Array.prototype.push) {

+	Array.prototype.push = function() {

+		for (var i = 0, len = arguments.length; i < len; i++){

+			this[this.length] = arguments[i];

+		}

+		return this.length;

+	};

+}

+

+if (!Array.prototype.shift) {

+	Array.prototype.shift = function() {

+		if (this.length > 0) {

+			var firstItem = this[0];

+			for (var i = 0, len = this.length - 1; i < len; i++) {

+				this[i] = this[i + 1];

+			}

+			this.length = this.length - 1;

+			return firstItem;

+		}

+	};

+}

+

+if (!Array.prototype.splice) {

+	Array.prototype.splice = function(startIndex, deleteCount) {

+		var itemsAfterDeleted = this.slice(startIndex + deleteCount);

+		var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);

+		this.length = startIndex;

+		// Copy the arguments into a proper Array object

+		var argumentsArray = [];

+		for (var i = 0, len = arguments.length; i < len; i++) {

+			argumentsArray[i] = arguments[i];

+		}

+		var itemsToAppend = (argumentsArray.length > 2) ?

+			itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;

+		for (i = 0, len = itemsToAppend.length; i < len; i++) {

+			this.push(itemsToAppend[i]);

+		}

+		return itemsDeleted;

+	};

+}

+

+/* -------------------------------------------------------------------------- */

+

+var log4javascript = (function() {

+

+	function isUndefined(obj) {

+		return typeof obj == "undefined";

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// Custom event support

+

+	function EventSupport() {}

+

+	EventSupport.prototype = {

+		eventTypes: [],

+		eventListeners: {},

+		setEventTypes: function(eventTypesParam) {

+			if (eventTypesParam instanceof Array) {

+				this.eventTypes = eventTypesParam;

+				this.eventListeners = {};

+				for (var i = 0, len = this.eventTypes.length; i < len; i++) {

+					this.eventListeners[this.eventTypes[i]] = [];

+				}

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: setEventTypes: eventTypes parameter must be an Array");

+			}

+		},

+

+		addEventListener: function(eventType, listener) {

+			if (typeof listener == "function") {

+				if (!array_contains(this.eventTypes, eventType)) {

+					handleError("log4javascript.EventSupport [" + this + "]: addEventListener: no event called '" + eventType + "'");

+				}

+				this.eventListeners[eventType].push(listener);

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: addEventListener: listener must be a function");

+			}

+		},

+

+		removeEventListener: function(eventType, listener) {

+			if (typeof listener == "function") {

+				if (!array_contains(this.eventTypes, eventType)) {

+					handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: no event called '" + eventType + "'");

+				}

+				array_remove(this.eventListeners[eventType], listener);

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: listener must be a function");

+			}

+		},

+

+		dispatchEvent: function(eventType, eventArgs) {

+			if (array_contains(this.eventTypes, eventType)) {

+				var listeners = this.eventListeners[eventType];

+				for (var i = 0, len = listeners.length; i < len; i++) {

+					listeners[i](this, eventType, eventArgs);

+				}

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: dispatchEvent: no event called '" + eventType + "'");

+			}

+		}

+	};

+

+	/* -------------------------------------------------------------------------- */

+

+	var applicationStartDate = new Date();

+	var uniqueId = "log4javascript_" + applicationStartDate.getTime() + "_" +

+		Math.floor(Math.random() * 100000000);

+	var emptyFunction = function() {};

+	var newLine = "\r\n";

+	var pageLoaded = false;

+

+	// Create main log4javascript object; this will be assigned public properties

+	function Log4JavaScript() {}

+	Log4JavaScript.prototype = new EventSupport();

+

+	log4javascript = new Log4JavaScript();

+	log4javascript.version = "1.4.6";

+	log4javascript.edition = "log4javascript";

+

+	/* -------------------------------------------------------------------------- */

+	// Utility functions

+

+	function toStr(obj) {

+		if (obj && obj.toString) {

+			return obj.toString();

+		} else {

+			return String(obj);

+		}

+	}

+

+	function getExceptionMessage(ex) {

+		if (ex.message) {

+			return ex.message;

+		} else if (ex.description) {

+			return ex.description;

+		} else {

+			return toStr(ex);

+		}

+	}

+

+	// Gets the portion of the URL after the last slash

+	function getUrlFileName(url) {

+		var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\"));

+		return url.substr(lastSlashIndex + 1);

+	}

+

+	// Returns a nicely formatted representation of an error

+	function getExceptionStringRep(ex) {

+		if (ex) {

+			var exStr = "Exception: " + getExceptionMessage(ex);

+			try {

+				if (ex.lineNumber) {

+					exStr += " on line number " + ex.lineNumber;

+				}

+				if (ex.fileName) {

+					exStr += " in file " + getUrlFileName(ex.fileName);

+				}

+			} catch (localEx) {

+				logLog.warn("Unable to obtain file and line information for error");

+			}

+			if (showStackTraces && ex.stack) {

+				exStr += newLine + "Stack trace:" + newLine + ex.stack;

+			}

+			return exStr;

+		}

+		return null;

+	}

+

+	function bool(obj) {

+		return Boolean(obj);

+	}

+

+	function trim(str) {

+		return str.replace(/^\s+/, "").replace(/\s+$/, "");

+	}

+

+	function splitIntoLines(text) {

+		// Ensure all line breaks are \n only

+		var text2 = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");

+		return text2.split("\n");

+	}

+

+	var urlEncode = (typeof window.encodeURIComponent != "undefined") ?

+		function(str) {

+			return encodeURIComponent(str);

+		}: 

+		function(str) {

+			return escape(str).replace(/\+/g, "%2B").replace(/"/g, "%22").replace(/'/g, "%27").replace(/\//g, "%2F").replace(/=/g, "%3D");

+		};

+

+	var urlDecode = (typeof window.decodeURIComponent != "undefined") ?

+		function(str) {

+			return decodeURIComponent(str);

+		}: 

+		function(str) {

+			return unescape(str).replace(/%2B/g, "+").replace(/%22/g, "\"").replace(/%27/g, "'").replace(/%2F/g, "/").replace(/%3D/g, "=");

+		};

+

+	function array_remove(arr, val) {

+		var index = -1;

+		for (var i = 0, len = arr.length; i < len; i++) {

+			if (arr[i] === val) {

+				index = i;

+				break;

+			}

+		}

+		if (index >= 0) {

+			arr.splice(index, 1);

+			return true;

+		} else {

+			return false;

+		}

+	}

+

+	function array_contains(arr, val) {

+		for(var i = 0, len = arr.length; i < len; i++) {

+			if (arr[i] == val) {

+				return true;

+			}

+		}

+		return false;

+	}

+

+	function extractBooleanFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			return bool(param);

+		}

+	}

+

+	function extractStringFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			return String(param);

+		}

+	}

+

+	function extractIntFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			try {

+				var value = parseInt(param, 10);

+				return isNaN(value) ? defaultValue : value;

+			} catch (ex) {

+				logLog.warn("Invalid int param " + param, ex);

+				return defaultValue;

+			}

+		}

+	}

+

+	function extractFunctionFromParam(param, defaultValue) {

+		if (typeof param == "function") {

+			return param;

+		} else {

+			return defaultValue;

+		}

+	}

+

+	function isError(err) {

+		return (err instanceof Error);

+	}

+

+	if (!Function.prototype.apply){

+		Function.prototype.apply = function(obj, args) {

+			var methodName = "__apply__";

+			if (typeof obj[methodName] != "undefined") {

+				methodName += String(Math.random()).substr(2);

+			}

+			obj[methodName] = this;

+

+			var argsStrings = [];

+			for (var i = 0, len = args.length; i < len; i++) {

+				argsStrings[i] = "args[" + i + "]";

+			}

+			var script = "obj." + methodName + "(" + argsStrings.join(",") + ")";

+			var returnValue = eval(script);

+			delete obj[methodName];

+			return returnValue;

+		};

+	}

+

+	if (!Function.prototype.call){

+		Function.prototype.call = function(obj) {

+			var args = [];

+			for (var i = 1, len = arguments.length; i < len; i++) {

+				args[i - 1] = arguments[i];

+			}

+			return this.apply(obj, args);

+		};

+	}

+

+	function getListenersPropertyName(eventName) {

+		return "__log4javascript_listeners__" + eventName;

+	}

+

+	function addEvent(node, eventName, listener, useCapture, win) {

+		win = win ? win : window;

+		if (node.addEventListener) {

+			node.addEventListener(eventName, listener, useCapture);

+		} else if (node.attachEvent) {

+			node.attachEvent("on" + eventName, listener);

+		} else {

+			var propertyName = getListenersPropertyName(eventName);

+			if (!node[propertyName]) {

+				node[propertyName] = [];

+				// Set event handler

+				node["on" + eventName] = function(evt) {

+					evt = getEvent(evt, win);

+					var listenersPropertyName = getListenersPropertyName(eventName);

+

+					// Clone the array of listeners to leave the original untouched

+					var listeners = this[listenersPropertyName].concat([]);

+					var currentListener;

+

+					// Call each listener in turn

+					while ((currentListener = listeners.shift())) {

+						currentListener.call(this, evt);

+					}

+				};

+			}

+			node[propertyName].push(listener);

+		}

+	}

+

+	function removeEvent(node, eventName, listener, useCapture) {

+		if (node.removeEventListener) {

+			node.removeEventListener(eventName, listener, useCapture);

+		} else if (node.detachEvent) {

+			node.detachEvent("on" + eventName, listener);

+		} else {

+			var propertyName = getListenersPropertyName(eventName);

+			if (node[propertyName]) {

+				array_remove(node[propertyName], listener);

+			}

+		}

+	}

+

+	function getEvent(evt, win) {

+		win = win ? win : window;

+		return evt ? evt : win.event;

+	}

+

+	function stopEventPropagation(evt) {

+		if (evt.stopPropagation) {

+			evt.stopPropagation();

+		} else if (typeof evt.cancelBubble != "undefined") {

+			evt.cancelBubble = true;

+		}

+		evt.returnValue = false;

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// Simple logging for log4javascript itself

+

+	var logLog = {

+		quietMode: false,

+

+		debugMessages: [],

+

+		setQuietMode: function(quietMode) {

+			this.quietMode = bool(quietMode);

+		},

+

+		numberOfErrors: 0,

+

+		alertAllErrors: false,

+

+		setAlertAllErrors: function(alertAllErrors) {

+			this.alertAllErrors = alertAllErrors;

+		},

+

+		debug: function(message) {

+			this.debugMessages.push(message);

+		},

+

+		displayDebug: function() {

+			alert(this.debugMessages.join(newLine));

+		},

+

+		warn: function(message, exception) {

+		},

+

+		error: function(message, exception) {

+			if (++this.numberOfErrors == 1 || this.alertAllErrors) {

+				if (!this.quietMode) {

+					var alertMessage = "log4javascript error: " + message;

+					if (exception) {

+						alertMessage += newLine + newLine + "Original error: " + getExceptionStringRep(exception);

+					}

+					alert(alertMessage);

+				}

+			}

+		}

+	};

+	log4javascript.logLog = logLog;

+

+	log4javascript.setEventTypes(["load", "error"]);

+

+	function handleError(message, exception) {

+		logLog.error(message, exception);

+		log4javascript.dispatchEvent("error", { "message": message, "exception": exception });

+	}

+

+	log4javascript.handleError = handleError;

+

+	/* ---------------------------------------------------------------------- */

+

+	var enabled = !((typeof log4javascript_disabled != "undefined") &&

+					log4javascript_disabled);

+

+	log4javascript.setEnabled = function(enable) {

+		enabled = bool(enable);

+	};

+

+	log4javascript.isEnabled = function() {

+		return enabled;

+	};

+

+	var useTimeStampsInMilliseconds = true;

+

+	log4javascript.setTimeStampsInMilliseconds = function(timeStampsInMilliseconds) {

+		useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);

+	};

+

+	log4javascript.isTimeStampsInMilliseconds = function() {

+		return useTimeStampsInMilliseconds;

+	};

+	

+

+	// This evaluates the given expression in the current scope, thus allowing

+	// scripts to access private variables. Particularly useful for testing

+	log4javascript.evalInScope = function(expr) {

+		return eval(expr);

+	};

+

+	var showStackTraces = false;

+

+	log4javascript.setShowStackTraces = function(show) {

+		showStackTraces = bool(show);

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Levels

+

+	var Level = function(level, name) {

+		this.level = level;

+		this.name = name;

+	};

+

+	Level.prototype = {

+		toString: function() {

+			return this.name;

+		},

+		equals: function(level) {

+			return this.level == level.level;

+		},

+		isGreaterOrEqual: function(level) {

+			return this.level >= level.level;

+		}

+	};

+

+	Level.ALL = new Level(Number.MIN_VALUE, "ALL");

+	Level.TRACE = new Level(10000, "TRACE");

+	Level.DEBUG = new Level(20000, "DEBUG");

+	Level.INFO = new Level(30000, "INFO");

+	Level.WARN = new Level(40000, "WARN");

+	Level.ERROR = new Level(50000, "ERROR");

+	Level.FATAL = new Level(60000, "FATAL");

+	Level.OFF = new Level(Number.MAX_VALUE, "OFF");

+

+	log4javascript.Level = Level;

+

+	/* ---------------------------------------------------------------------- */

+	// Timers

+

+	function Timer(name, level) {

+		this.name = name;

+		this.level = isUndefined(level) ? Level.INFO : level;

+		this.start = new Date();

+	}

+

+	Timer.prototype.getElapsedTime = function() {

+		return new Date().getTime() - this.start.getTime();

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Loggers

+

+	var anonymousLoggerName = "[anonymous]";

+	var defaultLoggerName = "[default]";

+	var nullLoggerName = "[null]";

+	var rootLoggerName = "root";

+

+	function Logger(name) {

+		this.name = name;

+		this.parent = null;

+		this.children = [];

+

+		var appenders = [];

+		var loggerLevel = null;

+		var isRoot = (this.name === rootLoggerName);

+		var isNull = (this.name === nullLoggerName);

+

+		var appenderCache = null;

+		var appenderCacheInvalidated = false;

+		

+		this.addChild = function(childLogger) {

+			this.children.push(childLogger);

+			childLogger.parent = this;

+			childLogger.invalidateAppenderCache();

+		};

+

+		// Additivity

+		var additive = true;

+		this.getAdditivity = function() {

+			return additive;

+		};

+

+		this.setAdditivity = function(additivity) {

+			var valueChanged = (additive != additivity);

+			additive = additivity;

+			if (valueChanged) {

+				this.invalidateAppenderCache();

+			}

+		};

+

+		// Create methods that use the appenders variable in this scope

+		this.addAppender = function(appender) {

+			if (isNull) {

+				handleError("Logger.addAppender: you may not add an appender to the null logger");

+			} else {

+				if (appender instanceof log4javascript.Appender) {

+					if (!array_contains(appenders, appender)) {

+						appenders.push(appender);

+						appender.setAddedToLogger(this);

+						this.invalidateAppenderCache();

+					}

+				} else {

+					handleError("Logger.addAppender: appender supplied ('" +

+						toStr(appender) + "') is not a subclass of Appender");

+				}

+			}

+		};

+

+		this.removeAppender = function(appender) {

+			array_remove(appenders, appender);

+			appender.setRemovedFromLogger(this);

+			this.invalidateAppenderCache();

+		};

+

+		this.removeAllAppenders = function() {

+			var appenderCount = appenders.length;

+			if (appenderCount > 0) {

+				for (var i = 0; i < appenderCount; i++) {

+					appenders[i].setRemovedFromLogger(this);

+				}

+				appenders.length = 0;

+				this.invalidateAppenderCache();

+			}

+		};

+

+		this.getEffectiveAppenders = function() {

+			if (appenderCache === null || appenderCacheInvalidated) {

+				// Build appender cache

+				var parentEffectiveAppenders = (isRoot || !this.getAdditivity()) ?

+					[] : this.parent.getEffectiveAppenders();

+				appenderCache = parentEffectiveAppenders.concat(appenders);

+				appenderCacheInvalidated = false;

+			}

+			return appenderCache;

+		};

+		

+		this.invalidateAppenderCache = function() {

+			appenderCacheInvalidated = true;

+			for (var i = 0, len = this.children.length; i < len; i++) {

+				this.children[i].invalidateAppenderCache();

+			}

+		};

+

+		this.log = function(level, params) {

+			if (enabled && level.isGreaterOrEqual(this.getEffectiveLevel())) {

+				// Check whether last param is an exception

+				var exception;

+				var finalParamIndex = params.length - 1;

+				var lastParam = params[finalParamIndex];

+				if (params.length > 1 && isError(lastParam)) {

+					exception = lastParam;

+					finalParamIndex--;

+				}

+

+				// Construct genuine array for the params

+				var messages = [];

+				for (var i = 0; i <= finalParamIndex; i++) {

+					messages[i] = params[i];

+				}

+

+				var loggingEvent = new LoggingEvent(

+					this, new Date(), level, messages, exception);

+

+				this.callAppenders(loggingEvent);

+			}

+		};

+

+		this.callAppenders = function(loggingEvent) {

+			var effectiveAppenders = this.getEffectiveAppenders();

+			for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+				effectiveAppenders[i].doAppend(loggingEvent);

+			}

+		};

+

+		this.setLevel = function(level) {

+			// Having a level of null on the root logger would be very bad.

+			if (isRoot && level === null) {

+				handleError("Logger.setLevel: you cannot set the level of the root logger to null");

+			} else if (level instanceof Level) {

+				loggerLevel = level;

+			} else {

+				handleError("Logger.setLevel: level supplied to logger " +

+					this.name + " is not an instance of log4javascript.Level");

+			}

+		};

+

+		this.getLevel = function() {

+			return loggerLevel;

+		};

+

+		this.getEffectiveLevel = function() {

+			for (var logger = this; logger !== null; logger = logger.parent) {

+				var level = logger.getLevel();

+				if (level !== null) {

+					return level;

+				}

+			}

+		};

+

+		this.group = function(name, initiallyExpanded) {

+			if (enabled) {

+				var effectiveAppenders = this.getEffectiveAppenders();

+				for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+					effectiveAppenders[i].group(name, initiallyExpanded);

+				}

+			}

+		};

+

+		this.groupEnd = function() {

+			if (enabled) {

+				var effectiveAppenders = this.getEffectiveAppenders();

+				for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+					effectiveAppenders[i].groupEnd();

+				}

+			}

+		};

+

+		var timers = {};

+

+		this.time = function(name, level) {

+			if (enabled) {

+				if (isUndefined(name)) {

+					handleError("Logger.time: a name for the timer must be supplied");

+				} else if (level && !(level instanceof Level)) {

+					handleError("Logger.time: level supplied to timer " +

+						name + " is not an instance of log4javascript.Level");

+				} else {

+					timers[name] = new Timer(name, level);

+				}

+			}

+		};

+

+		this.timeEnd = function(name) {

+			if (enabled) {

+				if (isUndefined(name)) {

+					handleError("Logger.timeEnd: a name for the timer must be supplied");

+				} else if (timers[name]) {

+					var timer = timers[name];

+					var milliseconds = timer.getElapsedTime();

+					this.log(timer.level, ["Timer " + toStr(name) + " completed in " + milliseconds + "ms"]);

+					delete timers[name];

+				} else {

+					logLog.warn("Logger.timeEnd: no timer found with name " + name);

+				}

+			}

+		};

+

+		this.assert = function(expr) {

+			if (enabled && !expr) {

+				var args = [];

+				for (var i = 1, len = arguments.length; i < len; i++) {

+					args.push(arguments[i]);

+				}

+				args = (args.length > 0) ? args : ["Assertion Failure"];

+				args.push(newLine);

+				args.push(expr);

+				this.log(Level.ERROR, args);

+			}

+		};

+

+		this.toString = function() {

+			return "Logger[" + this.name + "]";

+		};

+	}

+

+	Logger.prototype = {

+		trace: function() {

+			this.log(Level.TRACE, arguments);

+		},

+

+		debug: function() {

+			this.log(Level.DEBUG, arguments);

+		},

+

+		info: function() {

+			this.log(Level.INFO, arguments);

+		},

+

+		warn: function() {

+			this.log(Level.WARN, arguments);

+		},

+

+		error: function() {

+			this.log(Level.ERROR, arguments);

+		},

+

+		fatal: function() {

+			this.log(Level.FATAL, arguments);

+		},

+

+		isEnabledFor: function(level) {

+			return level.isGreaterOrEqual(this.getEffectiveLevel());

+		},

+

+		isTraceEnabled: function() {

+			return this.isEnabledFor(Level.TRACE);

+		},

+

+		isDebugEnabled: function() {

+			return this.isEnabledFor(Level.DEBUG);

+		},

+

+		isInfoEnabled: function() {

+			return this.isEnabledFor(Level.INFO);

+		},

+

+		isWarnEnabled: function() {

+			return this.isEnabledFor(Level.WARN);

+		},

+

+		isErrorEnabled: function() {

+			return this.isEnabledFor(Level.ERROR);

+		},

+

+		isFatalEnabled: function() {

+			return this.isEnabledFor(Level.FATAL);

+		}

+	};

+

+	Logger.prototype.trace.isEntryPoint = true;

+	Logger.prototype.debug.isEntryPoint = true;

+	Logger.prototype.info.isEntryPoint = true;

+	Logger.prototype.warn.isEntryPoint = true;

+	Logger.prototype.error.isEntryPoint = true;

+	Logger.prototype.fatal.isEntryPoint = true;

+

+	/* ---------------------------------------------------------------------- */

+	// Logger access methods

+

+	// Hashtable of loggers keyed by logger name

+	var loggers = {};

+	var loggerNames = [];

+

+	var ROOT_LOGGER_DEFAULT_LEVEL = Level.DEBUG;

+	var rootLogger = new Logger(rootLoggerName);

+	rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);

+

+	log4javascript.getRootLogger = function() {

+		return rootLogger;

+	};

+

+	log4javascript.getLogger = function(loggerName) {

+		// Use default logger if loggerName is not specified or invalid

+		if (!(typeof loggerName == "string")) {

+			loggerName = anonymousLoggerName;

+			logLog.warn("log4javascript.getLogger: non-string logger name "	+

+				toStr(loggerName) + " supplied, returning anonymous logger");

+		}

+

+		// Do not allow retrieval of the root logger by name

+		if (loggerName == rootLoggerName) {

+			handleError("log4javascript.getLogger: root logger may not be obtained by name");

+		}

+

+		// Create the logger for this name if it doesn't already exist

+		if (!loggers[loggerName]) {

+			var logger = new Logger(loggerName);

+			loggers[loggerName] = logger;

+			loggerNames.push(loggerName);

+

+			// Set up parent logger, if it doesn't exist

+			var lastDotIndex = loggerName.lastIndexOf(".");

+			var parentLogger;

+			if (lastDotIndex > -1) {

+				var parentLoggerName = loggerName.substring(0, lastDotIndex);

+				parentLogger = log4javascript.getLogger(parentLoggerName); // Recursively sets up grandparents etc.

+			} else {

+				parentLogger = rootLogger;

+			}

+			parentLogger.addChild(logger);

+		}

+		return loggers[loggerName];

+	};

+

+	var defaultLogger = null;

+	log4javascript.getDefaultLogger = function() {

+		if (!defaultLogger) {

+			defaultLogger = log4javascript.getLogger(defaultLoggerName);

+			var a = new log4javascript.PopUpAppender();

+			defaultLogger.addAppender(a);

+		}

+		return defaultLogger;

+	};

+

+	var nullLogger = null;

+	log4javascript.getNullLogger = function() {

+		if (!nullLogger) {

+			nullLogger = new Logger(nullLoggerName);

+			nullLogger.setLevel(Level.OFF);

+		}

+		return nullLogger;

+	};

+

+	// Destroys all loggers

+	log4javascript.resetConfiguration = function() {

+		rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);

+		loggers = {};

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Logging events

+

+	var LoggingEvent = function(logger, timeStamp, level, messages,

+			exception) {

+		this.logger = logger;

+		this.timeStamp = timeStamp;

+		this.timeStampInMilliseconds = timeStamp.getTime();

+		this.timeStampInSeconds = Math.floor(this.timeStampInMilliseconds / 1000);

+		this.milliseconds = this.timeStamp.getMilliseconds();

+		this.level = level;

+		this.messages = messages;

+		this.exception = exception;

+	};

+

+	LoggingEvent.prototype = {

+		getThrowableStrRep: function() {

+			return this.exception ?

+				getExceptionStringRep(this.exception) : "";

+		},

+		getCombinedMessages: function() {

+			return (this.messages.length == 1) ? this.messages[0] :

+				   this.messages.join(newLine);

+		},

+		toString: function() {

+			return "LoggingEvent[" + this.level + "]";

+		}

+	};

+

+	log4javascript.LoggingEvent = LoggingEvent;

+

+	/* ---------------------------------------------------------------------- */

+	// Layout prototype

+

+	var Layout = function() {

+	};

+

+	Layout.prototype = {

+		defaults: {

+			loggerKey: "logger",

+			timeStampKey: "timestamp",

+			millisecondsKey: "milliseconds",

+			levelKey: "level",

+			messageKey: "message",

+			exceptionKey: "exception",

+			urlKey: "url"

+		},

+		loggerKey: "logger",

+		timeStampKey: "timestamp",

+		millisecondsKey: "milliseconds",

+		levelKey: "level",

+		messageKey: "message",

+		exceptionKey: "exception",

+		urlKey: "url",

+		batchHeader: "",

+		batchFooter: "",

+		batchSeparator: "",

+		returnsPostData: false,

+		overrideTimeStampsSetting: false,

+		useTimeStampsInMilliseconds: null,

+

+		format: function() {

+			handleError("Layout.format: layout supplied has no format() method");

+		},

+

+		ignoresThrowable: function() {

+			handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");

+		},

+

+		getContentType: function() {

+			return "text/plain";

+		},

+

+		allowBatching: function() {

+			return true;

+		},

+

+		setTimeStampsInMilliseconds: function(timeStampsInMilliseconds) {

+			this.overrideTimeStampsSetting = true;

+			this.useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);

+		},

+

+		isTimeStampsInMilliseconds: function() {

+			return this.overrideTimeStampsSetting ?

+				this.useTimeStampsInMilliseconds : useTimeStampsInMilliseconds;

+		},

+

+		getTimeStampValue: function(loggingEvent) {

+			return this.isTimeStampsInMilliseconds() ?

+				loggingEvent.timeStampInMilliseconds : loggingEvent.timeStampInSeconds;

+		},

+

+		getDataValues: function(loggingEvent, combineMessages) {

+			var dataValues = [

+				[this.loggerKey, loggingEvent.logger.name],

+				[this.timeStampKey, this.getTimeStampValue(loggingEvent)],

+				[this.levelKey, loggingEvent.level.name],

+				[this.urlKey, window.location.href],

+				[this.messageKey, combineMessages ? loggingEvent.getCombinedMessages() : loggingEvent.messages]

+			];

+			if (!this.isTimeStampsInMilliseconds()) {

+				dataValues.push([this.millisecondsKey, loggingEvent.milliseconds]);

+			}

+			if (loggingEvent.exception) {

+				dataValues.push([this.exceptionKey, getExceptionStringRep(loggingEvent.exception)]);

+			}

+			if (this.hasCustomFields()) {

+				for (var i = 0, len = this.customFields.length; i < len; i++) {

+					var val = this.customFields[i].value;

+

+					// Check if the value is a function. If so, execute it, passing it the

+					// current layout and the logging event

+					if (typeof val === "function") {

+						val = val(this, loggingEvent);

+					}

+					dataValues.push([this.customFields[i].name, val]);

+				}

+			}

+			return dataValues;

+		},

+

+		setKeys: function(loggerKey, timeStampKey, levelKey, messageKey,

+				exceptionKey, urlKey, millisecondsKey) {

+			this.loggerKey = extractStringFromParam(loggerKey, this.defaults.loggerKey);

+			this.timeStampKey = extractStringFromParam(timeStampKey, this.defaults.timeStampKey);

+			this.levelKey = extractStringFromParam(levelKey, this.defaults.levelKey);

+			this.messageKey = extractStringFromParam(messageKey, this.defaults.messageKey);

+			this.exceptionKey = extractStringFromParam(exceptionKey, this.defaults.exceptionKey);

+			this.urlKey = extractStringFromParam(urlKey, this.defaults.urlKey);

+			this.millisecondsKey = extractStringFromParam(millisecondsKey, this.defaults.millisecondsKey);

+		},

+

+		setCustomField: function(name, value) {

+			var fieldUpdated = false;

+			for (var i = 0, len = this.customFields.length; i < len; i++) {

+				if (this.customFields[i].name === name) {

+					this.customFields[i].value = value;

+					fieldUpdated = true;

+				}

+			}

+			if (!fieldUpdated) {

+				this.customFields.push({"name": name, "value": value});

+			}

+		},

+

+		hasCustomFields: function() {

+			return (this.customFields.length > 0);

+		},

+

+		toString: function() {

+			handleError("Layout.toString: all layouts must override this method");

+		}

+	};

+

+	log4javascript.Layout = Layout;

+

+	/* ---------------------------------------------------------------------- */

+	// Appender prototype

+

+	var Appender = function() {};

+

+	Appender.prototype = new EventSupport();

+

+	Appender.prototype.layout = new PatternLayout();

+	Appender.prototype.threshold = Level.ALL;

+	Appender.prototype.loggers = [];

+

+	// Performs threshold checks before delegating actual logging to the

+	// subclass's specific append method.

+	Appender.prototype.doAppend = function(loggingEvent) {

+		if (enabled && loggingEvent.level.level >= this.threshold.level) {

+			this.append(loggingEvent);

+		}

+	};

+

+	Appender.prototype.append = function(loggingEvent) {};

+

+	Appender.prototype.setLayout = function(layout) {

+		if (layout instanceof Layout) {

+			this.layout = layout;

+		} else {

+			handleError("Appender.setLayout: layout supplied to " +

+				this.toString() + " is not a subclass of Layout");

+		}

+	};

+

+	Appender.prototype.getLayout = function() {

+		return this.layout;

+	};

+

+	Appender.prototype.setThreshold = function(threshold) {

+		if (threshold instanceof Level) {

+			this.threshold = threshold;

+		} else {

+			handleError("Appender.setThreshold: threshold supplied to " +

+				this.toString() + " is not a subclass of Level");

+		}

+	};

+

+	Appender.prototype.getThreshold = function() {

+		return this.threshold;

+	};

+

+	Appender.prototype.setAddedToLogger = function(logger) {

+		this.loggers.push(logger);

+	};

+

+	Appender.prototype.setRemovedFromLogger = function(logger) {

+		array_remove(this.loggers, logger);

+	};

+

+	Appender.prototype.group = emptyFunction;

+	Appender.prototype.groupEnd = emptyFunction;

+

+	Appender.prototype.toString = function() {

+		handleError("Appender.toString: all appenders must override this method");

+	};

+

+	log4javascript.Appender = Appender;

+

+	/* ---------------------------------------------------------------------- */

+	// SimpleLayout 

+

+	function SimpleLayout() {

+		this.customFields = [];

+	}

+

+	SimpleLayout.prototype = new Layout();

+

+	SimpleLayout.prototype.format = function(loggingEvent) {

+		return loggingEvent.level.name + " - " + loggingEvent.getCombinedMessages();

+	};

+

+	SimpleLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	SimpleLayout.prototype.toString = function() {

+	    return "SimpleLayout";

+	};

+

+	log4javascript.SimpleLayout = SimpleLayout;

+	/* ----------------------------------------------------------------------- */

+	// NullLayout 

+

+	function NullLayout() {

+		this.customFields = [];

+	}

+

+	NullLayout.prototype = new Layout();

+

+	NullLayout.prototype.format = function(loggingEvent) {

+		return loggingEvent.messages;

+	};

+

+	NullLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	NullLayout.prototype.toString = function() {

+	    return "NullLayout";

+	};

+

+	log4javascript.NullLayout = NullLayout;

+/* ---------------------------------------------------------------------- */

+	// XmlLayout

+

+	function XmlLayout(combineMessages) {

+		this.combineMessages = extractBooleanFromParam(combineMessages, true);

+		this.customFields = [];

+	}

+

+	XmlLayout.prototype = new Layout();

+

+	XmlLayout.prototype.isCombinedMessages = function() {

+		return this.combineMessages;

+	};

+

+	XmlLayout.prototype.getContentType = function() {

+		return "text/xml";

+	};

+

+	XmlLayout.prototype.escapeCdata = function(str) {

+		return str.replace(/\]\]>/, "]]>]]&gt;<![CDATA[");

+	};

+

+	XmlLayout.prototype.format = function(loggingEvent) {

+		var layout = this;

+		var i, len;

+		function formatMessage(message) {

+			message = (typeof message === "string") ? message : toStr(message);

+			return "<log4javascript:message><![CDATA[" +

+				layout.escapeCdata(message) + "]]></log4javascript:message>";

+		}

+

+		var str = "<log4javascript:event logger=\"" + loggingEvent.logger.name +

+			"\" timestamp=\"" + this.getTimeStampValue(loggingEvent) + "\"";

+		if (!this.isTimeStampsInMilliseconds()) {

+			str += " milliseconds=\"" + loggingEvent.milliseconds + "\"";

+		}

+		str += " level=\"" + loggingEvent.level.name + "\">" + newLine;

+		if (this.combineMessages) {

+			str += formatMessage(loggingEvent.getCombinedMessages());

+		} else {

+			str += "<log4javascript:messages>" + newLine;

+			for (i = 0, len = loggingEvent.messages.length; i < len; i++) {

+				str += formatMessage(loggingEvent.messages[i]) + newLine;

+			}

+			str += "</log4javascript:messages>" + newLine;

+		}

+		if (this.hasCustomFields()) {

+			for (i = 0, len = this.customFields.length; i < len; i++) {

+				str += "<log4javascript:customfield name=\"" +

+					this.customFields[i].name + "\"><![CDATA[" +

+					this.customFields[i].value.toString() +

+					"]]></log4javascript:customfield>" + newLine;

+			}

+		}

+		if (loggingEvent.exception) {

+			str += "<log4javascript:exception><![CDATA[" +

+				getExceptionStringRep(loggingEvent.exception) +

+				"]]></log4javascript:exception>" + newLine;

+		}

+		str += "</log4javascript:event>" + newLine + newLine;

+		return str;

+	};

+

+	XmlLayout.prototype.ignoresThrowable = function() {

+	    return false;

+	};

+

+	XmlLayout.prototype.toString = function() {

+	    return "XmlLayout";

+	};

+

+	log4javascript.XmlLayout = XmlLayout;

+	/* ---------------------------------------------------------------------- */

+	// JsonLayout related

+

+	function escapeNewLines(str) {

+		return str.replace(/\r\n|\r|\n/g, "\\r\\n");

+	}

+

+	function JsonLayout(readable, combineMessages) {

+		this.readable = extractBooleanFromParam(readable, false);

+		this.combineMessages = extractBooleanFromParam(combineMessages, true);

+		this.batchHeader = this.readable ? "[" + newLine : "[";

+		this.batchFooter = this.readable ? "]" + newLine : "]";

+		this.batchSeparator = this.readable ? "," + newLine : ",";

+		this.setKeys();

+		this.colon = this.readable ? ": " : ":";

+		this.tab = this.readable ? "\t" : "";

+		this.lineBreak = this.readable ? newLine : "";

+		this.customFields = [];

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// JsonLayout

+

+	JsonLayout.prototype = new Layout();

+

+	JsonLayout.prototype.isReadable = function() {

+		return this.readable;

+	};

+

+	JsonLayout.prototype.isCombinedMessages = function() {

+		return this.combineMessages;

+	};

+

+    JsonLayout.prototype.format = function(loggingEvent) {

+        var layout = this;

+        var dataValues = this.getDataValues(loggingEvent, this.combineMessages);

+        var str = "{" + this.lineBreak;

+        var i, len;

+

+        function formatValue(val, prefix, expand) {

+            // Check the type of the data value to decide whether quotation marks

+            // or expansion are required

+            var formattedValue;

+            var valType = typeof val;

+            if (val instanceof Date) {

+                formattedValue = String(val.getTime());

+            } else if (expand && (val instanceof Array)) {

+                formattedValue = "[" + layout.lineBreak;

+                for (var i = 0, len = val.length; i < len; i++) {

+                    var childPrefix = prefix + layout.tab;

+                    formattedValue += childPrefix + formatValue(val[i], childPrefix, false);

+                    if (i < val.length - 1) {

+                        formattedValue += ",";

+                    }

+                    formattedValue += layout.lineBreak;

+                }

+                formattedValue += prefix + "]";

+            } else if (valType !== "number" && valType !== "boolean") {

+                formattedValue = "\"" + escapeNewLines(toStr(val).replace(/\"/g, "\\\"")) + "\"";

+            } else {

+                formattedValue = val;

+            }

+            return formattedValue;

+        }

+

+        for (i = 0, len = dataValues.length - 1; i <= len; i++) {

+            str += this.tab + "\"" + dataValues[i][0] + "\"" + this.colon + formatValue(dataValues[i][1], this.tab, true);

+            if (i < len) {

+                str += ",";

+            }

+            str += this.lineBreak;

+        }

+

+        str += "}" + this.lineBreak;

+        return str;

+    };

+

+	JsonLayout.prototype.ignoresThrowable = function() {

+	    return false;

+	};

+

+	JsonLayout.prototype.toString = function() {

+	    return "JsonLayout";

+	};

+

+	JsonLayout.prototype.getContentType = function() {

+		return "application/json";

+	};

+

+	log4javascript.JsonLayout = JsonLayout;

+	/* ---------------------------------------------------------------------- */

+	// HttpPostDataLayout

+

+	function HttpPostDataLayout() {

+		this.setKeys();

+		this.customFields = [];

+		this.returnsPostData = true;

+	}

+

+	HttpPostDataLayout.prototype = new Layout();

+

+	// Disable batching

+	HttpPostDataLayout.prototype.allowBatching = function() {

+		return false;

+	};

+

+	HttpPostDataLayout.prototype.format = function(loggingEvent) {

+		var dataValues = this.getDataValues(loggingEvent);

+		var queryBits = [];

+		for (var i = 0, len = dataValues.length; i < len; i++) {

+			var val = (dataValues[i][1] instanceof Date) ?

+				String(dataValues[i][1].getTime()) : dataValues[i][1];

+			queryBits.push(urlEncode(dataValues[i][0]) + "=" + urlEncode(val));

+		}

+		return queryBits.join("&");

+	};

+

+	HttpPostDataLayout.prototype.ignoresThrowable = function(loggingEvent) {

+	    return false;

+	};

+

+	HttpPostDataLayout.prototype.toString = function() {

+	    return "HttpPostDataLayout";

+	};

+

+	log4javascript.HttpPostDataLayout = HttpPostDataLayout;

+	/* ---------------------------------------------------------------------- */

+	// formatObjectExpansion

+

+	function formatObjectExpansion(obj, depth, indentation) {

+		var objectsExpanded = [];

+

+		function doFormat(obj, depth, indentation) {

+			var i, j, len, childDepth, childIndentation, childLines, expansion,

+				childExpansion;

+

+			if (!indentation) {

+				indentation = "";

+			}

+

+			function formatString(text) {

+				var lines = splitIntoLines(text);

+				for (var j = 1, jLen = lines.length; j < jLen; j++) {

+					lines[j] = indentation + lines[j];

+				}

+				return lines.join(newLine);

+			}

+

+			if (obj === null) {

+				return "null";

+			} else if (typeof obj == "undefined") {

+				return "undefined";

+			} else if (typeof obj == "string") {

+				return formatString(obj);

+			} else if (typeof obj == "object" && array_contains(objectsExpanded, obj)) {

+				try {

+					expansion = toStr(obj);

+				} catch (ex) {

+					expansion = "Error formatting property. Details: " + getExceptionStringRep(ex);

+				}

+				return expansion + " [already expanded]";

+			} else if ((obj instanceof Array) && depth > 0) {

+				objectsExpanded.push(obj);

+				expansion = "[" + newLine;

+				childDepth = depth - 1;

+				childIndentation = indentation + "  ";

+				childLines = [];

+				for (i = 0, len = obj.length; i < len; i++) {

+					try {

+						childExpansion = doFormat(obj[i], childDepth, childIndentation);

+						childLines.push(childIndentation + childExpansion);

+					} catch (ex) {

+						childLines.push(childIndentation + "Error formatting array member. Details: " +

+							getExceptionStringRep(ex) + "");

+					}

+				}

+				expansion += childLines.join("," + newLine) + newLine + indentation + "]";

+				return expansion;

+            } else if (Object.prototype.toString.call(obj) == "[object Date]") {

+                return obj.toString();

+			} else if (typeof obj == "object" && depth > 0) {

+				objectsExpanded.push(obj);

+				expansion = "{" + newLine;

+				childDepth = depth - 1;

+				childIndentation = indentation + "  ";

+				childLines = [];

+				for (i in obj) {

+					try {

+						childExpansion = doFormat(obj[i], childDepth, childIndentation);

+						childLines.push(childIndentation + i + ": " + childExpansion);

+					} catch (ex) {

+						childLines.push(childIndentation + i + ": Error formatting property. Details: " +

+							getExceptionStringRep(ex));

+					}

+				}

+				expansion += childLines.join("," + newLine) + newLine + indentation + "}";

+				return expansion;

+			} else {

+				return formatString(toStr(obj));

+			}

+		}

+		return doFormat(obj, depth, indentation);

+	}

+	/* ---------------------------------------------------------------------- */

+	// Date-related stuff

+

+	var SimpleDateFormat;

+

+	(function() {

+		var regex = /('[^']*')|(G+|y+|M+|w+|W+|D+|d+|F+|E+|a+|H+|k+|K+|h+|m+|s+|S+|Z+)|([a-zA-Z]+)|([^a-zA-Z']+)/;

+		var monthNames = ["January", "February", "March", "April", "May", "June",

+			"July", "August", "September", "October", "November", "December"];

+		var dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

+		var TEXT2 = 0, TEXT3 = 1, NUMBER = 2, YEAR = 3, MONTH = 4, TIMEZONE = 5;

+		var types = {

+			G : TEXT2,

+			y : YEAR,

+			M : MONTH,

+			w : NUMBER,

+			W : NUMBER,

+			D : NUMBER,

+			d : NUMBER,

+			F : NUMBER,

+			E : TEXT3,

+			a : TEXT2,

+			H : NUMBER,

+			k : NUMBER,

+			K : NUMBER,

+			h : NUMBER,

+			m : NUMBER,

+			s : NUMBER,

+			S : NUMBER,

+			Z : TIMEZONE

+		};

+		var ONE_DAY = 24 * 60 * 60 * 1000;

+		var ONE_WEEK = 7 * ONE_DAY;

+		var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK = 1;

+

+		var newDateAtMidnight = function(year, month, day) {

+			var d = new Date(year, month, day, 0, 0, 0);

+			d.setMilliseconds(0);

+			return d;

+		};

+

+		Date.prototype.getDifference = function(date) {

+			return this.getTime() - date.getTime();

+		};

+

+		Date.prototype.isBefore = function(d) {

+			return this.getTime() < d.getTime();

+		};

+

+		Date.prototype.getUTCTime = function() {

+			return Date.UTC(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours(), this.getMinutes(),

+					this.getSeconds(), this.getMilliseconds());

+		};

+

+		Date.prototype.getTimeSince = function(d) {

+			return this.getUTCTime() - d.getUTCTime();

+		};

+

+		Date.prototype.getPreviousSunday = function() {

+			// Using midday avoids any possibility of DST messing things up

+			var midday = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 12, 0, 0);

+			var previousSunday = new Date(midday.getTime() - this.getDay() * ONE_DAY);

+			return newDateAtMidnight(previousSunday.getFullYear(), previousSunday.getMonth(),

+					previousSunday.getDate());

+		};

+

+		Date.prototype.getWeekInYear = function(minimalDaysInFirstWeek) {

+			if (isUndefined(this.minimalDaysInFirstWeek)) {

+				minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;

+			}

+			var previousSunday = this.getPreviousSunday();

+			var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);

+			var numberOfSundays = previousSunday.isBefore(startOfYear) ?

+				0 : 1 + Math.floor(previousSunday.getTimeSince(startOfYear) / ONE_WEEK);

+			var numberOfDaysInFirstWeek =  7 - startOfYear.getDay();

+			var weekInYear = numberOfSundays;

+			if (numberOfDaysInFirstWeek < minimalDaysInFirstWeek) {

+				weekInYear--;

+			}

+			return weekInYear;

+		};

+

+		Date.prototype.getWeekInMonth = function(minimalDaysInFirstWeek) {

+			if (isUndefined(this.minimalDaysInFirstWeek)) {

+				minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;

+			}

+			var previousSunday = this.getPreviousSunday();

+			var startOfMonth = newDateAtMidnight(this.getFullYear(), this.getMonth(), 1);

+			var numberOfSundays = previousSunday.isBefore(startOfMonth) ?

+				0 : 1 + Math.floor(previousSunday.getTimeSince(startOfMonth) / ONE_WEEK);

+			var numberOfDaysInFirstWeek =  7 - startOfMonth.getDay();

+			var weekInMonth = numberOfSundays;

+			if (numberOfDaysInFirstWeek >= minimalDaysInFirstWeek) {

+				weekInMonth++;

+			}

+			return weekInMonth;

+		};

+

+		Date.prototype.getDayInYear = function() {

+			var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);

+			return 1 + Math.floor(this.getTimeSince(startOfYear) / ONE_DAY);

+		};

+

+		/* ------------------------------------------------------------------ */

+

+		SimpleDateFormat = function(formatString) {

+			this.formatString = formatString;

+		};

+

+		/**

+		 * Sets the minimum number of days in a week in order for that week to

+		 * be considered as belonging to a particular month or year

+		 */

+		SimpleDateFormat.prototype.setMinimalDaysInFirstWeek = function(days) {

+			this.minimalDaysInFirstWeek = days;

+		};

+

+		SimpleDateFormat.prototype.getMinimalDaysInFirstWeek = function() {

+			return isUndefined(this.minimalDaysInFirstWeek)	?

+				DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK : this.minimalDaysInFirstWeek;

+		};

+

+		var padWithZeroes = function(str, len) {

+			while (str.length < len) {

+				str = "0" + str;

+			}

+			return str;

+		};

+

+		var formatText = function(data, numberOfLetters, minLength) {

+			return (numberOfLetters >= 4) ? data : data.substr(0, Math.max(minLength, numberOfLetters));

+		};

+

+		var formatNumber = function(data, numberOfLetters) {

+			var dataString = "" + data;

+			// Pad with 0s as necessary

+			return padWithZeroes(dataString, numberOfLetters);

+		};

+

+		SimpleDateFormat.prototype.format = function(date) {

+			var formattedString = "";

+			var result;

+			var searchString = this.formatString;

+			while ((result = regex.exec(searchString))) {

+				var quotedString = result[1];

+				var patternLetters = result[2];

+				var otherLetters = result[3];

+				var otherCharacters = result[4];

+

+				// If the pattern matched is quoted string, output the text between the quotes

+				if (quotedString) {

+					if (quotedString == "''") {

+						formattedString += "'";

+					} else {

+						formattedString += quotedString.substring(1, quotedString.length - 1);

+					}

+				} else if (otherLetters) {

+					// Swallow non-pattern letters by doing nothing here

+				} else if (otherCharacters) {

+					// Simply output other characters

+					formattedString += otherCharacters;

+				} else if (patternLetters) {

+					// Replace pattern letters

+					var patternLetter = patternLetters.charAt(0);

+					var numberOfLetters = patternLetters.length;

+					var rawData = "";

+					switch(patternLetter) {

+						case "G":

+							rawData = "AD";

+							break;

+						case "y":

+							rawData = date.getFullYear();

+							break;

+						case "M":

+							rawData = date.getMonth();

+							break;

+						case "w":

+							rawData = date.getWeekInYear(this.getMinimalDaysInFirstWeek());

+							break;

+						case "W":

+							rawData = date.getWeekInMonth(this.getMinimalDaysInFirstWeek());

+							break;

+						case "D":

+							rawData = date.getDayInYear();

+							break;

+						case "d":

+							rawData = date.getDate();

+							break;

+						case "F":

+							rawData = 1 + Math.floor((date.getDate() - 1) / 7);

+							break;

+						case "E":

+							rawData = dayNames[date.getDay()];

+							break;

+						case "a":

+							rawData = (date.getHours() >= 12) ? "PM" : "AM";

+							break;

+						case "H":

+							rawData = date.getHours();

+							break;

+						case "k":

+							rawData = date.getHours() || 24;

+							break;

+						case "K":

+							rawData = date.getHours() % 12;

+							break;

+						case "h":

+							rawData = (date.getHours() % 12) || 12;

+							break;

+						case "m":

+							rawData = date.getMinutes();

+							break;

+						case "s":

+							rawData = date.getSeconds();

+							break;

+						case "S":

+							rawData = date.getMilliseconds();

+							break;

+						case "Z":

+							rawData = date.getTimezoneOffset(); // This returns the number of minutes since GMT was this time.

+							break;

+					}

+					// Format the raw data depending on the type

+					switch(types[patternLetter]) {

+						case TEXT2:

+							formattedString += formatText(rawData, numberOfLetters, 2);

+							break;

+						case TEXT3:

+							formattedString += formatText(rawData, numberOfLetters, 3);

+							break;

+						case NUMBER:

+							formattedString += formatNumber(rawData, numberOfLetters);

+							break;

+						case YEAR:

+							if (numberOfLetters <= 3) {

+								// Output a 2-digit year

+								var dataString = "" + rawData;

+								formattedString += dataString.substr(2, 2);

+							} else {

+								formattedString += formatNumber(rawData, numberOfLetters);

+							}

+							break;

+						case MONTH:

+							if (numberOfLetters >= 3) {

+								formattedString += formatText(monthNames[rawData], numberOfLetters, numberOfLetters);

+							} else {

+								// NB. Months returned by getMonth are zero-based

+								formattedString += formatNumber(rawData + 1, numberOfLetters);

+							}

+							break;

+						case TIMEZONE:

+							var isPositive = (rawData > 0);

+							// The following line looks like a mistake but isn't

+							// because of the way getTimezoneOffset measures.

+							var prefix = isPositive ? "-" : "+";

+							var absData = Math.abs(rawData);

+

+							// Hours

+							var hours = "" + Math.floor(absData / 60);

+							hours = padWithZeroes(hours, 2);

+							// Minutes

+							var minutes = "" + (absData % 60);

+							minutes = padWithZeroes(minutes, 2);

+

+							formattedString += prefix + hours + minutes;

+							break;

+					}

+				}

+				searchString = searchString.substr(result.index + result[0].length);

+			}

+			return formattedString;

+		};

+	})();

+

+	log4javascript.SimpleDateFormat = SimpleDateFormat;

+

+	/* ---------------------------------------------------------------------- */

+	// PatternLayout

+

+	function PatternLayout(pattern) {

+		if (pattern) {

+			this.pattern = pattern;

+		} else {

+			this.pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;

+		}

+		this.customFields = [];

+	}

+

+	PatternLayout.TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n";

+	PatternLayout.DEFAULT_CONVERSION_PATTERN = "%m%n";

+	PatternLayout.ISO8601_DATEFORMAT = "yyyy-MM-dd HH:mm:ss,SSS";

+	PatternLayout.DATETIME_DATEFORMAT = "dd MMM yyyy HH:mm:ss,SSS";

+	PatternLayout.ABSOLUTETIME_DATEFORMAT = "HH:mm:ss,SSS";

+

+	PatternLayout.prototype = new Layout();

+

+	PatternLayout.prototype.format = function(loggingEvent) {

+		var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;

+		var formattedString = "";

+		var result;

+		var searchString = this.pattern;

+

+		// Cannot use regex global flag since it doesn't work with exec in IE5

+		while ((result = regex.exec(searchString))) {

+			var matchedString = result[0];

+			var padding = result[1];

+			var truncation = result[2];

+			var conversionCharacter = result[3];

+			var specifier = result[5];

+			var text = result[6];

+

+			// Check if the pattern matched was just normal text

+			if (text) {

+				formattedString += "" + text;

+			} else {

+				// Create a raw replacement string based on the conversion

+				// character and specifier

+				var replacement = "";

+				switch(conversionCharacter) {

+					case "a": // Array of messages

+					case "m": // Message

+						var depth = 0;

+						if (specifier) {

+							depth = parseInt(specifier, 10);

+							if (isNaN(depth)) {

+								handleError("PatternLayout.format: invalid specifier '" +

+									specifier + "' for conversion character '" + conversionCharacter +

+									"' - should be a number");

+								depth = 0;

+							}

+						}

+						var messages = (conversionCharacter === "a") ? loggingEvent.messages[0] : loggingEvent.messages;

+						for (var i = 0, len = messages.length; i < len; i++) {

+							if (i > 0 && (replacement.charAt(replacement.length - 1) !== " ")) {

+								replacement += " ";

+							}

+							if (depth === 0) {

+								replacement += messages[i];

+							} else {

+								replacement += formatObjectExpansion(messages[i], depth);

+							}

+						}

+						break;

+					case "c": // Logger name

+						var loggerName = loggingEvent.logger.name;

+						if (specifier) {

+							var precision = parseInt(specifier, 10);

+							var loggerNameBits = loggingEvent.logger.name.split(".");

+							if (precision >= loggerNameBits.length) {

+								replacement = loggerName;

+							} else {

+								replacement = loggerNameBits.slice(loggerNameBits.length - precision).join(".");

+							}

+						} else {

+							replacement = loggerName;

+						}

+						break;

+					case "d": // Date

+						var dateFormat = PatternLayout.ISO8601_DATEFORMAT;

+						if (specifier) {

+							dateFormat = specifier;

+							// Pick up special cases

+							if (dateFormat == "ISO8601") {

+								dateFormat = PatternLayout.ISO8601_DATEFORMAT;

+							} else if (dateFormat == "ABSOLUTE") {

+								dateFormat = PatternLayout.ABSOLUTETIME_DATEFORMAT;

+							} else if (dateFormat == "DATE") {

+								dateFormat = PatternLayout.DATETIME_DATEFORMAT;

+							}

+						}

+						// Format the date

+						replacement = (new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);

+						break;

+					case "f": // Custom field

+						if (this.hasCustomFields()) {

+							var fieldIndex = 0;

+							if (specifier) {

+								fieldIndex = parseInt(specifier, 10);

+								if (isNaN(fieldIndex)) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - should be a number");

+								} else if (fieldIndex === 0) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - must be greater than zero");

+								} else if (fieldIndex > this.customFields.length) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - there aren't that many custom fields");

+								} else {

+									fieldIndex = fieldIndex - 1;

+								}

+							}

+                            var val = this.customFields[fieldIndex].value;

+                            if (typeof val == "function") {

+                                val = val(this, loggingEvent);

+                            }

+                            replacement = val;

+						}

+						break;

+					case "n": // New line

+						replacement = newLine;

+						break;

+					case "p": // Level

+						replacement = loggingEvent.level.name;

+						break;

+					case "r": // Milliseconds since log4javascript startup

+						replacement = "" + loggingEvent.timeStamp.getDifference(applicationStartDate);

+						break;

+					case "%": // Literal % sign

+						replacement = "%";

+						break;

+					default:

+						replacement = matchedString;

+						break;

+				}

+				// Format the replacement according to any padding or

+				// truncation specified

+				var l;

+

+				// First, truncation

+				if (truncation) {

+					l = parseInt(truncation.substr(1), 10);

+					var strLen = replacement.length;

+					if (l < strLen) {

+						replacement = replacement.substring(strLen - l, strLen);

+					}

+				}

+				// Next, padding

+				if (padding) {

+					if (padding.charAt(0) == "-") {

+						l = parseInt(padding.substr(1), 10);

+						// Right pad with spaces

+						while (replacement.length < l) {

+							replacement += " ";

+						}

+					} else {

+						l = parseInt(padding, 10);

+						// Left pad with spaces

+						while (replacement.length < l) {

+							replacement = " " + replacement;

+						}

+					}

+				}

+				formattedString += replacement;

+			}

+			searchString = searchString.substr(result.index + result[0].length);

+		}

+		return formattedString;

+	};

+

+	PatternLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	PatternLayout.prototype.toString = function() {

+	    return "PatternLayout";

+	};

+

+	log4javascript.PatternLayout = PatternLayout;

+	/* ---------------------------------------------------------------------- */

+	// AlertAppender

+

+	function AlertAppender() {}

+

+	AlertAppender.prototype = new Appender();

+

+	AlertAppender.prototype.layout = new SimpleLayout();

+

+	AlertAppender.prototype.append = function(loggingEvent) {

+		var formattedMessage = this.getLayout().format(loggingEvent);

+		if (this.getLayout().ignoresThrowable()) {

+			formattedMessage += loggingEvent.getThrowableStrRep();

+		}

+		alert(formattedMessage);

+	};

+

+	AlertAppender.prototype.toString = function() {

+		return "AlertAppender";

+	};

+

+	log4javascript.AlertAppender = AlertAppender;

+	/* ---------------------------------------------------------------------- */

+	// BrowserConsoleAppender (only works in Opera and Safari and Firefox with

+	// Firebug extension)

+

+	function BrowserConsoleAppender() {}

+

+	BrowserConsoleAppender.prototype = new log4javascript.Appender();

+	BrowserConsoleAppender.prototype.layout = new NullLayout();

+	BrowserConsoleAppender.prototype.threshold = Level.DEBUG;

+

+	BrowserConsoleAppender.prototype.append = function(loggingEvent) {

+		var appender = this;

+

+		var getFormattedMessage = function() {

+			var layout = appender.getLayout();

+			var formattedMessage = layout.format(loggingEvent);

+			if (layout.ignoresThrowable() && loggingEvent.exception) {

+				formattedMessage += loggingEvent.getThrowableStrRep();

+			}

+			return formattedMessage;

+		};

+

+		if ((typeof opera != "undefined") && opera.postError) { // Opera

+			opera.postError(getFormattedMessage());

+		} else if (window.console && window.console.log) { // Safari and Firebug

+			var formattedMesage = getFormattedMessage();

+			// Log to Firebug using its logging methods or revert to the console.log

+			// method in Safari

+			if (window.console.debug && Level.DEBUG.isGreaterOrEqual(loggingEvent.level)) {

+				window.console.debug(formattedMesage);

+			} else if (window.console.info && Level.INFO.equals(loggingEvent.level)) {

+				window.console.info(formattedMesage);

+			} else if (window.console.warn && Level.WARN.equals(loggingEvent.level)) {

+				window.console.warn(formattedMesage);

+			} else if (window.console.error && loggingEvent.level.isGreaterOrEqual(Level.ERROR)) {

+				window.console.error(formattedMesage);

+			} else {

+				window.console.log(formattedMesage);

+			}

+		}

+	};

+

+	BrowserConsoleAppender.prototype.group = function(name) {

+		if (window.console && window.console.group) {

+			window.console.group(name);

+		}

+	};

+

+	BrowserConsoleAppender.prototype.groupEnd = function() {

+		if (window.console && window.console.groupEnd) {

+			window.console.groupEnd();

+		}

+	};

+

+	BrowserConsoleAppender.prototype.toString = function() {

+		return "BrowserConsoleAppender";

+	};

+

+	log4javascript.BrowserConsoleAppender = BrowserConsoleAppender;

+	/* ---------------------------------------------------------------------- */

+	// AjaxAppender related

+

+	var xmlHttpFactories = [

+		function() { return new XMLHttpRequest(); },

+		function() { return new ActiveXObject("Msxml2.XMLHTTP"); },

+		function() { return new ActiveXObject("Microsoft.XMLHTTP"); }

+	];

+

+	var getXmlHttp = function(errorHandler) {

+		// This is only run the first time; the value of getXmlHttp gets

+		// replaced with the factory that succeeds on the first run

+		var xmlHttp = null, factory;

+		for (var i = 0, len = xmlHttpFactories.length; i < len; i++) {

+			factory = xmlHttpFactories[i];

+			try {

+				xmlHttp = factory();

+				getXmlHttp = factory;

+				return xmlHttp;

+			} catch (e) {

+			}

+		}

+		// If we're here, all factories have failed, so throw an error

+		if (errorHandler) {

+			errorHandler();

+		} else {

+			handleError("getXmlHttp: unable to obtain XMLHttpRequest object");

+		}

+	};

+

+	function isHttpRequestSuccessful(xmlHttp) {

+		return isUndefined(xmlHttp.status) || xmlHttp.status === 0 ||

+			(xmlHttp.status >= 200 && xmlHttp.status < 300) ||

+			xmlHttp.status == 1223 /* Fix for IE */;

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// AjaxAppender

+

+	function AjaxAppender(url) {

+		var appender = this;

+		var isSupported = true;

+		if (!url) {

+			handleError("AjaxAppender: URL must be specified in constructor");

+			isSupported = false;

+		}

+

+		var timed = this.defaults.timed;

+		var waitForResponse = this.defaults.waitForResponse;

+		var batchSize = this.defaults.batchSize;

+		var timerInterval = this.defaults.timerInterval;

+		var requestSuccessCallback = this.defaults.requestSuccessCallback;

+		var failCallback = this.defaults.failCallback;

+		var postVarName = this.defaults.postVarName;

+		var sendAllOnUnload = this.defaults.sendAllOnUnload;

+		var contentType = this.defaults.contentType;

+		var sessionId = null;

+

+		var queuedLoggingEvents = [];

+		var queuedRequests = [];

+		var headers = [];

+		var sending = false;

+		var initialized = false;

+

+		// Configuration methods. The function scope is used to prevent

+		// direct alteration to the appender configuration properties.

+		function checkCanConfigure(configOptionName) {

+			if (initialized) {

+				handleError("AjaxAppender: configuration option '" +

+					configOptionName +

+					"' may not be set after the appender has been initialized");

+				return false;

+			}

+			return true;

+		}

+

+		this.getSessionId = function() { return sessionId; };

+		this.setSessionId = function(sessionIdParam) {

+			sessionId = extractStringFromParam(sessionIdParam, null);

+			this.layout.setCustomField("sessionid", sessionId);

+		};

+

+		this.setLayout = function(layoutParam) {

+			if (checkCanConfigure("layout")) {

+				this.layout = layoutParam;

+				// Set the session id as a custom field on the layout, if not already present

+				if (sessionId !== null) {

+					this.setSessionId(sessionId);

+				}

+			}

+		};

+

+		this.isTimed = function() { return timed; };

+		this.setTimed = function(timedParam) {

+			if (checkCanConfigure("timed")) {

+				timed = bool(timedParam);

+			}

+		};

+

+		this.getTimerInterval = function() { return timerInterval; };

+		this.setTimerInterval = function(timerIntervalParam) {

+			if (checkCanConfigure("timerInterval")) {

+				timerInterval = extractIntFromParam(timerIntervalParam, timerInterval);

+			}

+		};

+

+		this.isWaitForResponse = function() { return waitForResponse; };

+		this.setWaitForResponse = function(waitForResponseParam) {

+			if (checkCanConfigure("waitForResponse")) {

+				waitForResponse = bool(waitForResponseParam);

+			}

+		};

+

+		this.getBatchSize = function() { return batchSize; };

+		this.setBatchSize = function(batchSizeParam) {

+			if (checkCanConfigure("batchSize")) {

+				batchSize = extractIntFromParam(batchSizeParam, batchSize);

+			}

+		};

+

+		this.isSendAllOnUnload = function() { return sendAllOnUnload; };

+		this.setSendAllOnUnload = function(sendAllOnUnloadParam) {

+			if (checkCanConfigure("sendAllOnUnload")) {

+				sendAllOnUnload = extractBooleanFromParam(sendAllOnUnloadParam, sendAllOnUnload);

+			}

+		};

+

+		this.setRequestSuccessCallback = function(requestSuccessCallbackParam) {

+			requestSuccessCallback = extractFunctionFromParam(requestSuccessCallbackParam, requestSuccessCallback);

+		};

+

+		this.setFailCallback = function(failCallbackParam) {

+			failCallback = extractFunctionFromParam(failCallbackParam, failCallback);

+		};

+

+		this.getPostVarName = function() { return postVarName; };

+		this.setPostVarName = function(postVarNameParam) {

+			if (checkCanConfigure("postVarName")) {

+				postVarName = extractStringFromParam(postVarNameParam, postVarName);

+			}

+		};

+

+		this.getHeaders = function() { return headers; };

+		this.addHeader = function(name, value) {

+			if (name.toLowerCase() == "content-type") {

+				contentType = value;

+			} else {

+				headers.push( { name: name, value: value } );

+			}

+		};

+

+		// Internal functions

+		function sendAll() {

+			if (isSupported && enabled) {

+				sending = true;

+				var currentRequestBatch;

+				if (waitForResponse) {

+					// Send the first request then use this function as the callback once

+					// the response comes back

+					if (queuedRequests.length > 0) {

+						currentRequestBatch = queuedRequests.shift();

+						sendRequest(preparePostData(currentRequestBatch), sendAll);

+					} else {

+						sending = false;

+						if (timed) {

+							scheduleSending();

+						}

+					}

+				} else {

+					// Rattle off all the requests without waiting to see the response

+					while ((currentRequestBatch = queuedRequests.shift())) {

+						sendRequest(preparePostData(currentRequestBatch));

+					}

+					sending = false;

+					if (timed) {

+						scheduleSending();

+					}

+				}

+			}

+		}

+

+		this.sendAll = sendAll;

+

+		// Called when the window unloads. At this point we're past caring about

+		// waiting for responses or timers or incomplete batches - everything

+		// must go, now

+		function sendAllRemaining() {

+			var sendingAnything = false;

+			if (isSupported && enabled) {

+				// Create requests for everything left over, batched as normal

+				var actualBatchSize = appender.getLayout().allowBatching() ? batchSize : 1;

+				var currentLoggingEvent;

+				var batchedLoggingEvents = [];

+				while ((currentLoggingEvent = queuedLoggingEvents.shift())) {

+					batchedLoggingEvents.push(currentLoggingEvent);

+					if (queuedLoggingEvents.length >= actualBatchSize) {

+						// Queue this batch of log entries

+						queuedRequests.push(batchedLoggingEvents);

+						batchedLoggingEvents = [];

+					}

+				}

+				// If there's a partially completed batch, add it

+				if (batchedLoggingEvents.length > 0) {

+					queuedRequests.push(batchedLoggingEvents);

+				}

+				sendingAnything = (queuedRequests.length > 0);

+				waitForResponse = false;

+				timed = false;

+				sendAll();

+			}

+			return sendingAnything;

+		}

+

+		this.sendAllRemaining = sendAllRemaining;

+

+		function preparePostData(batchedLoggingEvents) {

+			// Format the logging events

+			var formattedMessages = [];

+			var currentLoggingEvent;

+			var postData = "";

+			while ((currentLoggingEvent = batchedLoggingEvents.shift())) {

+				var currentFormattedMessage = appender.getLayout().format(currentLoggingEvent);

+				if (appender.getLayout().ignoresThrowable()) {

+					currentFormattedMessage += currentLoggingEvent.getThrowableStrRep();

+				}

+				formattedMessages.push(currentFormattedMessage);

+			}

+			// Create the post data string

+			if (batchedLoggingEvents.length == 1) {

+				postData = formattedMessages.join("");

+			} else {

+				postData = appender.getLayout().batchHeader +

+					formattedMessages.join(appender.getLayout().batchSeparator) +

+					appender.getLayout().batchFooter;

+			}

+			if (contentType == appender.defaults.contentType) {

+				postData = appender.getLayout().returnsPostData ? postData :

+					urlEncode(postVarName) + "=" + urlEncode(postData);

+				// Add the layout name to the post data

+				if (postData.length > 0) {

+					postData += "&";

+				}

+				postData += "layout=" + urlEncode(appender.getLayout().toString());

+			}

+			return postData;

+		}

+

+		function scheduleSending() {

+			window.setTimeout(sendAll, timerInterval);

+		}

+

+		function xmlHttpErrorHandler() {

+			var msg = "AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";

+			handleError(msg);

+			isSupported = false;

+			if (failCallback) {

+				failCallback(msg);

+			}

+		}

+

+		function sendRequest(postData, successCallback) {

+			try {

+				var xmlHttp = getXmlHttp(xmlHttpErrorHandler);

+				if (isSupported) {

+					if (xmlHttp.overrideMimeType) {

+						xmlHttp.overrideMimeType(appender.getLayout().getContentType());

+					}

+					xmlHttp.onreadystatechange = function() {

+						if (xmlHttp.readyState == 4) {

+							if (isHttpRequestSuccessful(xmlHttp)) {

+								if (requestSuccessCallback) {

+									requestSuccessCallback(xmlHttp);

+								}

+								if (successCallback) {

+									successCallback(xmlHttp);

+								}

+							} else {

+								var msg = "AjaxAppender.append: XMLHttpRequest request to URL " +

+									url + " returned status code " + xmlHttp.status;

+								handleError(msg);

+								if (failCallback) {

+									failCallback(msg);

+								}

+							}

+							xmlHttp.onreadystatechange = emptyFunction;

+							xmlHttp = null;

+						}

+					};

+					xmlHttp.open("POST", url, true);

+					try {

+						for (var i = 0, header; header = headers[i++]; ) {

+							xmlHttp.setRequestHeader(header.name, header.value);

+						}

+						xmlHttp.setRequestHeader("Content-Type", contentType);

+					} catch (headerEx) {

+						var msg = "AjaxAppender.append: your browser's XMLHttpRequest implementation" +

+							" does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";

+						handleError(msg);

+						isSupported = false;

+						if (failCallback) {

+							failCallback(msg);

+						}

+						return;

+					}

+					xmlHttp.send(postData);

+				}

+			} catch (ex) {

+				var errMsg = "AjaxAppender.append: error sending log message to " + url;

+				handleError(errMsg, ex);

+				isSupported = false;

+				if (failCallback) {

+					failCallback(errMsg + ". Details: " + getExceptionStringRep(ex));

+				}

+			}

+		}

+

+		this.append = function(loggingEvent) {

+			if (isSupported) {

+				if (!initialized) {

+					init();

+				}

+				queuedLoggingEvents.push(loggingEvent);

+				var actualBatchSize = this.getLayout().allowBatching() ? batchSize : 1;

+

+				if (queuedLoggingEvents.length >= actualBatchSize) {

+					var currentLoggingEvent;

+					var batchedLoggingEvents = [];

+					while ((currentLoggingEvent = queuedLoggingEvents.shift())) {

+						batchedLoggingEvents.push(currentLoggingEvent);

+					}

+					// Queue this batch of log entries

+					queuedRequests.push(batchedLoggingEvents);

+

+					// If using a timer, the queue of requests will be processed by the

+					// timer function, so nothing needs to be done here.

+					if (!timed && (!waitForResponse || (waitForResponse && !sending))) {

+						sendAll();

+					}

+				}

+			}

+		};

+

+		function init() {

+			initialized = true;

+			// Add unload event to send outstanding messages

+			if (sendAllOnUnload) {

+				var oldBeforeUnload = window.onbeforeunload;

+				window.onbeforeunload = function() {

+					if (oldBeforeUnload) {

+						oldBeforeUnload();

+					}

+					if (sendAllRemaining()) {

+						return "Sending log messages";

+					}

+				};

+			}

+			// Start timer

+			if (timed) {

+				scheduleSending();

+			}

+		}

+	}

+

+	AjaxAppender.prototype = new Appender();

+

+	AjaxAppender.prototype.defaults = {

+		waitForResponse: false,

+		timed: false,

+		timerInterval: 1000,

+		batchSize: 1,

+		sendAllOnUnload: false,

+		requestSuccessCallback: null,

+		failCallback: null,

+		postVarName: "data",

+		contentType: "application/x-www-form-urlencoded"

+	};

+

+	AjaxAppender.prototype.layout = new HttpPostDataLayout();

+

+	AjaxAppender.prototype.toString = function() {

+		return "AjaxAppender";

+	};

+

+	log4javascript.AjaxAppender = AjaxAppender;

+	/* ---------------------------------------------------------------------- */

+	// PopUpAppender and InPageAppender related

+

+	function setCookie(name, value, days, path) {

+	    var expires;

+	    path = path ? "; path=" + path : "";

+		if (days) {

+			var date = new Date();

+			date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));

+			expires = "; expires=" + date.toGMTString();

+		} else {

+		    expires = "";

+	    }

+		document.cookie = escape(name) + "=" + escape(value) + expires + path;

+	}

+

+	function getCookie(name) {

+		var nameEquals = escape(name) + "=";

+		var ca = document.cookie.split(";");

+		for (var i = 0, len = ca.length; i < len; i++) {

+			var c = ca[i];

+			while (c.charAt(0) === " ") {

+			    c = c.substring(1, c.length);

+			}

+			if (c.indexOf(nameEquals) === 0) {

+			    return unescape(c.substring(nameEquals.length, c.length));

+	        }

+		}

+		return null;

+	}

+

+	// Gets the base URL of the location of the log4javascript script.

+	// This is far from infallible.

+	function getBaseUrl() {

+		var scripts = document.getElementsByTagName("script");

+		for (var i = 0, len = scripts.length; i < len; ++i) {

+			if (scripts[i].src.indexOf("log4javascript") != -1) {

+				var lastSlash = scripts[i].src.lastIndexOf("/");

+				return (lastSlash == -1) ? "" : scripts[i].src.substr(0, lastSlash + 1);

+			}

+		}

+        return null;

+    }

+

+	function isLoaded(win) {

+		try {

+			return bool(win.loaded);

+		} catch (ex) {

+			return false;

+		}

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// ConsoleAppender (prototype for PopUpAppender and InPageAppender)

+

+	var ConsoleAppender;

+

+	// Create an anonymous function to protect base console methods

+	(function() {

+		var getConsoleHtmlLines = function() {

+			return [

+'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',

+'<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">',

+'	<head>',

+'		<title>log4javascript</title>',

+'		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',

+'		<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->',

+'		<meta http-equiv="X-UA-Compatible" content="IE=7" />',

+'		<script type="text/javascript">var isIe = false, isIePre7 = false;</script>',

+'		<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->',

+'		<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->',

+'		<script type="text/javascript">',

+'			//<![CDATA[',

+'			var loggingEnabled = true;',

+'			var logQueuedEventsTimer = null;',

+'			var logEntries = [];',

+'			var logEntriesAndSeparators = [];',

+'			var logItems = [];',

+'			var renderDelay = 100;',

+'			var unrenderedLogItemsExist = false;',

+'			var rootGroup, currentGroup = null;',

+'			var loaded = false;',

+'			var currentLogItem = null;',

+'			var logMainContainer;',

+'',

+'			function copyProperties(obj, props) {',

+'				for (var i in props) {',

+'					obj[i] = props[i];',

+'				}',

+'			}',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItem() {',

+'			}',

+'',

+'			LogItem.prototype = {',

+'				mainContainer: null,',

+'				wrappedContainer: null,',

+'				unwrappedContainer: null,',

+'				group: null,',

+'',

+'				appendToLog: function() {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].appendToLog();',

+'					}',

+'					this.group.update();',

+'				},',

+'',

+'				doRemove: function(doUpdate, removeFromGroup) {',

+'					if (this.rendered) {',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].remove();',

+'						}',

+'						this.unwrappedElementContainer = null;',

+'						this.wrappedElementContainer = null;',

+'						this.mainElementContainer = null;',

+'					}',

+'					if (this.group && removeFromGroup) {',

+'						this.group.removeChild(this, doUpdate);',

+'					}',

+'					if (this === currentLogItem) {',

+'						currentLogItem = null;',

+'					}',

+'				},',

+'',

+'				remove: function(doUpdate, removeFromGroup) {',

+'					this.doRemove(doUpdate, removeFromGroup);',

+'				},',

+'',

+'				render: function() {},',

+'',

+'				accept: function(visitor) {',

+'					visitor.visit(this);',

+'				},',

+'',

+'				getUnwrappedDomContainer: function() {',

+'					return this.group.unwrappedElementContainer.contentDiv;',

+'				},',

+'',

+'				getWrappedDomContainer: function() {',

+'					return this.group.wrappedElementContainer.contentDiv;',

+'				},',

+'',

+'				getMainDomContainer: function() {',

+'					return this.group.mainElementContainer.contentDiv;',

+'				}',

+'			};',

+'',

+'			LogItem.serializedItemKeys = {LOG_ENTRY: 0, GROUP_START: 1, GROUP_END: 2};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItemContainerElement() {',

+'			}',

+'',

+'			LogItemContainerElement.prototype = {',

+'				appendToLog: function() {',

+'					var insertBeforeFirst = (newestAtTop && this.containerDomNode.hasChildNodes());',

+'					if (insertBeforeFirst) {',

+'						this.containerDomNode.insertBefore(this.mainDiv, this.containerDomNode.firstChild);',

+'					} else {',

+'						this.containerDomNode.appendChild(this.mainDiv);',

+'					}',

+'				}',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function SeparatorElementContainer(containerDomNode) {',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.className = "separator";',

+'				this.mainDiv.innerHTML = "&nbsp;";',

+'			}',

+'',

+'			SeparatorElementContainer.prototype = new LogItemContainerElement();',

+'',

+'			SeparatorElementContainer.prototype.remove = function() {',

+'				this.mainDiv.parentNode.removeChild(this.mainDiv);',

+'				this.mainDiv = null;',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function Separator() {',

+'				this.rendered = false;',

+'			}',

+'',

+'			Separator.prototype = new LogItem();',

+'',

+'			copyProperties(Separator.prototype, {',

+'				render: function() {',

+'					var containerDomNode = this.group.contentDiv;',

+'					if (isIe) {',

+'						this.unwrappedElementContainer = new SeparatorElementContainer(this.getUnwrappedDomContainer());',

+'						this.wrappedElementContainer = new SeparatorElementContainer(this.getWrappedDomContainer());',

+'						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',

+'					} else {',

+'						this.mainElementContainer = new SeparatorElementContainer(this.getMainDomContainer());',

+'						this.elementContainers = [this.mainElementContainer];',

+'					}',

+'					this.content = this.formattedMessage;',

+'					this.rendered = true;',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function GroupElementContainer(group, containerDomNode, isRoot, isWrapped) {',

+'				this.group = group;',

+'				this.containerDomNode = containerDomNode;',

+'				this.isRoot = isRoot;',

+'				this.isWrapped = isWrapped;',

+'				this.expandable = false;',

+'',

+'				if (this.isRoot) {',

+'					if (isIe) {',

+'						this.contentDiv = logMainContainer.appendChild(document.createElement("div"));',

+'						this.contentDiv.id = this.isWrapped ? "log_wrapped" : "log_unwrapped";',

+'					} else {',

+'						this.contentDiv = logMainContainer;',

+'					}',

+'				} else {',

+'					var groupElementContainer = this;',

+'					',

+'					this.mainDiv = document.createElement("div");',

+'					this.mainDiv.className = "group";',

+'',

+'					this.headingDiv = this.mainDiv.appendChild(document.createElement("div"));',

+'					this.headingDiv.className = "groupheading";',

+'',

+'					this.expander = this.headingDiv.appendChild(document.createElement("span"));',

+'					this.expander.className = "expander unselectable greyedout";',

+'					this.expander.unselectable = true;',

+'					var expanderText = this.group.expanded ? "-" : "+";',

+'					this.expanderTextNode = this.expander.appendChild(document.createTextNode(expanderText));',

+'					',

+'					this.headingDiv.appendChild(document.createTextNode(" " + this.group.name));',

+'',

+'					this.contentDiv = this.mainDiv.appendChild(document.createElement("div"));',

+'					var contentCssClass = this.group.expanded ? "expanded" : "collapsed";',

+'					this.contentDiv.className = "groupcontent " + contentCssClass;',

+'',

+'					this.expander.onclick = function() {',

+'						if (groupElementContainer.group.expandable) {',

+'							groupElementContainer.group.toggleExpanded();',

+'						}',

+'					};',

+'				}',

+'			}',

+'',

+'			GroupElementContainer.prototype = new LogItemContainerElement();',

+'',

+'			copyProperties(GroupElementContainer.prototype, {',

+'				toggleExpanded: function() {',

+'					if (!this.isRoot) {',

+'						var oldCssClass, newCssClass, expanderText;',

+'						if (this.group.expanded) {',

+'							newCssClass = "expanded";',

+'							oldCssClass = "collapsed";',

+'							expanderText = "-";',

+'						} else {',

+'							newCssClass = "collapsed";',

+'							oldCssClass = "expanded";',

+'							expanderText = "+";',

+'						}',

+'						replaceClass(this.contentDiv, newCssClass, oldCssClass);',

+'						this.expanderTextNode.nodeValue = expanderText;',

+'					}',

+'				},',

+'',

+'				remove: function() {',

+'					if (!this.isRoot) {',

+'						this.headingDiv = null;',

+'						this.expander.onclick = null;',

+'						this.expander = null;',

+'						this.expanderTextNode = null;',

+'						this.contentDiv = null;',

+'						this.containerDomNode = null;',

+'						this.mainDiv.parentNode.removeChild(this.mainDiv);',

+'						this.mainDiv = null;',

+'					}',

+'				},',

+'',

+'				reverseChildren: function() {',

+'					// Invert the order of the log entries',

+'					var node = null;',

+'',

+'					// Remove all the log container nodes',

+'					var childDomNodes = [];',

+'					while ((node = this.contentDiv.firstChild)) {',

+'						this.contentDiv.removeChild(node);',

+'						childDomNodes.push(node);',

+'					}',

+'',

+'					// Put them all back in reverse order',

+'					while ((node = childDomNodes.pop())) {',

+'						this.contentDiv.appendChild(node);',

+'					}',

+'				},',

+'',

+'				update: function() {',

+'					if (!this.isRoot) {',

+'						if (this.group.expandable) {',

+'							removeClass(this.expander, "greyedout");',

+'						} else {',

+'							addClass(this.expander, "greyedout");',

+'						}',

+'					}',

+'				},',

+'',

+'				clear: function() {',

+'					if (this.isRoot) {',

+'						this.contentDiv.innerHTML = "";',

+'					}',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function Group(name, isRoot, initiallyExpanded) {',

+'				this.name = name;',

+'				this.group = null;',

+'				this.isRoot = isRoot;',

+'				this.initiallyExpanded = initiallyExpanded;',

+'				this.elementContainers = [];',

+'				this.children = [];',

+'				this.expanded = initiallyExpanded;',

+'				this.rendered = false;',

+'				this.expandable = false;',

+'			}',

+'',

+'			Group.prototype = new LogItem();',

+'',

+'			copyProperties(Group.prototype, {',

+'				addChild: function(logItem) {',

+'					this.children.push(logItem);',

+'					logItem.group = this;',

+'				},',

+'',

+'				render: function() {',

+'					if (isIe) {',

+'						var unwrappedDomContainer, wrappedDomContainer;',

+'						if (this.isRoot) {',

+'							unwrappedDomContainer = logMainContainer;',

+'							wrappedDomContainer = logMainContainer;',

+'						} else {',

+'							unwrappedDomContainer = this.getUnwrappedDomContainer();',

+'							wrappedDomContainer = this.getWrappedDomContainer();',

+'						}',

+'						this.unwrappedElementContainer = new GroupElementContainer(this, unwrappedDomContainer, this.isRoot, false);',

+'						this.wrappedElementContainer = new GroupElementContainer(this, wrappedDomContainer, this.isRoot, true);',

+'						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',

+'					} else {',

+'						var mainDomContainer = this.isRoot ? logMainContainer : this.getMainDomContainer();',

+'						this.mainElementContainer = new GroupElementContainer(this, mainDomContainer, this.isRoot, false);',

+'						this.elementContainers = [this.mainElementContainer];',

+'					}',

+'					this.rendered = true;',

+'				},',

+'',

+'				toggleExpanded: function() {',

+'					this.expanded = !this.expanded;',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].toggleExpanded();',

+'					}',

+'				},',

+'',

+'				expand: function() {',

+'					if (!this.expanded) {',

+'						this.toggleExpanded();',

+'					}',

+'				},',

+'',

+'				accept: function(visitor) {',

+'					visitor.visitGroup(this);',

+'				},',

+'',

+'				reverseChildren: function() {',

+'					if (this.rendered) {',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].reverseChildren();',

+'						}',

+'					}',

+'				},',

+'',

+'				update: function() {',

+'					var previouslyExpandable = this.expandable;',

+'					this.expandable = (this.children.length !== 0);',

+'					if (this.expandable !== previouslyExpandable) {',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].update();',

+'						}',

+'					}',

+'				},',

+'',

+'				flatten: function() {',

+'					var visitor = new GroupFlattener();',

+'					this.accept(visitor);',

+'					return visitor.logEntriesAndSeparators;',

+'				},',

+'',

+'				removeChild: function(child, doUpdate) {',

+'					array_remove(this.children, child);',

+'					child.group = null;',

+'					if (doUpdate) {',

+'						this.update();',

+'					}',

+'				},',

+'',

+'				remove: function(doUpdate, removeFromGroup) {',

+'					for (var i = 0, len = this.children.length; i < len; i++) {',

+'						this.children[i].remove(false, false);',

+'					}',

+'					this.children = [];',

+'					this.update();',

+'					if (this === currentGroup) {',

+'						currentGroup = this.group;',

+'					}',

+'					this.doRemove(doUpdate, removeFromGroup);',

+'				},',

+'',

+'				serialize: function(items) {',

+'					items.push([LogItem.serializedItemKeys.GROUP_START, this.name]);',

+'					for (var i = 0, len = this.children.length; i < len; i++) {',

+'						this.children[i].serialize(items);',

+'					}',

+'					if (this !== currentGroup) {',

+'						items.push([LogItem.serializedItemKeys.GROUP_END]);',

+'					}',

+'				},',

+'',

+'				clear: function() {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].clear();',

+'					}',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryElementContainer() {',

+'			}',

+'',

+'			LogEntryElementContainer.prototype = new LogItemContainerElement();',

+'',

+'			copyProperties(LogEntryElementContainer.prototype, {',

+'				remove: function() {',

+'					this.doRemove();',

+'				},',

+'',

+'				doRemove: function() {',

+'					this.mainDiv.parentNode.removeChild(this.mainDiv);',

+'					this.mainDiv = null;',

+'					this.contentElement = null;',

+'					this.containerDomNode = null;',

+'				},',

+'',

+'				setContent: function(content, wrappedContent) {',

+'					if (content === this.formattedMessage) {',

+'						this.contentElement.innerHTML = "";',

+'						this.contentElement.appendChild(document.createTextNode(this.formattedMessage));',

+'					} else {',

+'						this.contentElement.innerHTML = content;',

+'					}',

+'				},',

+'',

+'				setSearchMatch: function(isMatch) {',

+'					var oldCssClass = isMatch ? "searchnonmatch" : "searchmatch";',

+'					var newCssClass = isMatch ? "searchmatch" : "searchnonmatch";',

+'					replaceClass(this.mainDiv, newCssClass, oldCssClass);',

+'				},',

+'',

+'				clearSearch: function() {',

+'					removeClass(this.mainDiv, "searchmatch");',

+'					removeClass(this.mainDiv, "searchnonmatch");',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryWrappedElementContainer(logEntry, containerDomNode) {',

+'				this.logEntry = logEntry;',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));',

+'				this.mainDiv.className = "logentry wrapped " + this.logEntry.level;',

+'				this.contentElement = this.mainDiv;',

+'			}',

+'',

+'			LogEntryWrappedElementContainer.prototype = new LogEntryElementContainer();',

+'',

+'			LogEntryWrappedElementContainer.prototype.setContent = function(content, wrappedContent) {',

+'				if (content === this.formattedMessage) {',

+'					this.contentElement.innerHTML = "";',

+'					this.contentElement.appendChild(document.createTextNode(this.formattedMessage));',

+'				} else {',

+'					this.contentElement.innerHTML = wrappedContent;',

+'				}',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryUnwrappedElementContainer(logEntry, containerDomNode) {',

+'				this.logEntry = logEntry;',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.className = "logentry unwrapped " + this.logEntry.level;',

+'				this.pre = this.mainDiv.appendChild(document.createElement("pre"));',

+'				this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));',

+'				this.pre.className = "unwrapped";',

+'				this.contentElement = this.pre;',

+'			}',

+'',

+'			LogEntryUnwrappedElementContainer.prototype = new LogEntryElementContainer();',

+'',

+'			LogEntryUnwrappedElementContainer.prototype.remove = function() {',

+'				this.doRemove();',

+'				this.pre = null;',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryMainElementContainer(logEntry, containerDomNode) {',

+'				this.logEntry = logEntry;',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.className = "logentry nonielogentry " + this.logEntry.level;',

+'				this.contentElement = this.mainDiv.appendChild(document.createElement("span"));',

+'				this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));',

+'			}',

+'',

+'			LogEntryMainElementContainer.prototype = new LogEntryElementContainer();',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntry(level, formattedMessage) {',

+'				this.level = level;',

+'				this.formattedMessage = formattedMessage;',

+'				this.rendered = false;',

+'			}',

+'',

+'			LogEntry.prototype = new LogItem();',

+'',

+'			copyProperties(LogEntry.prototype, {',

+'				render: function() {',

+'					var logEntry = this;',

+'					var containerDomNode = this.group.contentDiv;',

+'',

+'					// Support for the CSS attribute white-space in IE for Windows is',

+'					// non-existent pre version 6 and slightly odd in 6, so instead',

+'					// use two different HTML elements',

+'					if (isIe) {',

+'						this.formattedMessage = this.formattedMessage.replace(/\\r\\n/g, "\\r"); // Workaround for IE\'s treatment of white space',

+'						this.unwrappedElementContainer = new LogEntryUnwrappedElementContainer(this, this.getUnwrappedDomContainer());',

+'						this.wrappedElementContainer = new LogEntryWrappedElementContainer(this, this.getWrappedDomContainer());',

+'						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',

+'					} else {',

+'						this.mainElementContainer = new LogEntryMainElementContainer(this, this.getMainDomContainer());',

+'						this.elementContainers = [this.mainElementContainer];',

+'					}',

+'					this.content = this.formattedMessage;',

+'					this.rendered = true;',

+'				},',

+'',

+'				setContent: function(content, wrappedContent) {',

+'					if (content != this.content) {',

+'						if (isIe && (content !== this.formattedMessage)) {',

+'							content = content.replace(/\\r\\n/g, "\\r"); // Workaround for IE\'s treatment of white space',

+'						}',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].setContent(content, wrappedContent);',

+'						}',

+'						this.content = content;',

+'					}',

+'				},',

+'',

+'				getSearchMatches: function() {',

+'					var matches = [];',

+'					var i, len;',

+'					if (isIe) {',

+'						var unwrappedEls = getElementsByClass(this.unwrappedElementContainer.mainDiv, "searchterm", "span");',

+'						var wrappedEls = getElementsByClass(this.wrappedElementContainer.mainDiv, "searchterm", "span");',

+'						for (i = 0, len = unwrappedEls.length; i < len; i++) {',

+'							matches[i] = new Match(this.level, null, unwrappedEls[i], wrappedEls[i]);',

+'						}',

+'					} else {',

+'						var els = getElementsByClass(this.mainElementContainer.mainDiv, "searchterm", "span");',

+'						for (i = 0, len = els.length; i < len; i++) {',

+'							matches[i] = new Match(this.level, els[i]);',

+'						}',

+'					}',

+'					return matches;',

+'				},',

+'',

+'				setSearchMatch: function(isMatch) {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].setSearchMatch(isMatch);',

+'					}',

+'				},',

+'',

+'				clearSearch: function() {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].clearSearch();',

+'					}',

+'				},',

+'',

+'				accept: function(visitor) {',

+'					visitor.visitLogEntry(this);',

+'				},',

+'',

+'				serialize: function(items) {',

+'					items.push([LogItem.serializedItemKeys.LOG_ENTRY, this.level, this.formattedMessage]);',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItemVisitor() {',

+'			}',

+'',

+'			LogItemVisitor.prototype = {',

+'				visit: function(logItem) {',

+'				},',

+'',

+'				visitParent: function(logItem) {',

+'					if (logItem.group) {',

+'						logItem.group.accept(this);',

+'					}',

+'				},',

+'',

+'				visitChildren: function(logItem) {',

+'					for (var i = 0, len = logItem.children.length; i < len; i++) {',

+'						logItem.children[i].accept(this);',

+'					}',

+'				},',

+'',

+'				visitLogEntry: function(logEntry) {',

+'					this.visit(logEntry);',

+'				},',

+'',

+'				visitSeparator: function(separator) {',

+'					this.visit(separator);',

+'				},',

+'',

+'				visitGroup: function(group) {',

+'					this.visit(group);',

+'				}',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function GroupFlattener() {',

+'				this.logEntriesAndSeparators = [];',

+'			}',

+'',

+'			GroupFlattener.prototype = new LogItemVisitor();',

+'',

+'			GroupFlattener.prototype.visitGroup = function(group) {',

+'				this.visitChildren(group);',

+'			};',

+'',

+'			GroupFlattener.prototype.visitLogEntry = function(logEntry) {',

+'				this.logEntriesAndSeparators.push(logEntry);',

+'			};',

+'',

+'			GroupFlattener.prototype.visitSeparator = function(separator) {',

+'				this.logEntriesAndSeparators.push(separator);',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			window.onload = function() {',

+'				// Sort out document.domain',

+'				if (location.search) {',

+'					var queryBits = unescape(location.search).substr(1).split("&"), nameValueBits;',

+'					for (var i = 0, len = queryBits.length; i < len; i++) {',

+'						nameValueBits = queryBits[i].split("=");',

+'						if (nameValueBits[0] == "log4javascript_domain") {',

+'							document.domain = nameValueBits[1];',

+'							break;',

+'						}',

+'					}',

+'				}',

+'',

+'				// Create DOM objects',

+'				logMainContainer = $("log");',

+'				if (isIePre7) {',

+'					addClass(logMainContainer, "oldIe");',

+'				}',

+'',

+'				rootGroup = new Group("root", true);',

+'				rootGroup.render();',

+'				currentGroup = rootGroup;',

+'				',

+'				setCommandInputWidth();',

+'				setLogContainerHeight();',

+'				toggleLoggingEnabled();',

+'				toggleSearchEnabled();',

+'				toggleSearchFilter();',

+'				toggleSearchHighlight();',

+'				applyFilters();',

+'				checkAllLevels();',

+'				toggleWrap();',

+'				toggleNewestAtTop();',

+'				toggleScrollToLatest();',

+'				renderQueuedLogItems();',

+'				loaded = true;',

+'				$("command").value = "";',

+'				$("command").autocomplete = "off";',

+'				$("command").onkeydown = function(evt) {',

+'					evt = getEvent(evt);',

+'					if (evt.keyCode == 10 || evt.keyCode == 13) { // Return/Enter',

+'						evalCommandLine();',

+'						stopPropagation(evt);',

+'					} else if (evt.keyCode == 27) { // Escape',

+'						this.value = "";',

+'						this.focus();',

+'					} else if (evt.keyCode == 38 && commandHistory.length > 0) { // Up',

+'						currentCommandIndex = Math.max(0, currentCommandIndex - 1);',

+'						this.value = commandHistory[currentCommandIndex];',

+'						moveCaretToEnd(this);',

+'					} else if (evt.keyCode == 40 && commandHistory.length > 0) { // Down',

+'						currentCommandIndex = Math.min(commandHistory.length - 1, currentCommandIndex + 1);',

+'						this.value = commandHistory[currentCommandIndex];',

+'						moveCaretToEnd(this);',

+'					}',

+'				};',

+'',

+'				// Prevent the keypress moving the caret in Firefox',

+'				$("command").onkeypress = function(evt) {',

+'					evt = getEvent(evt);',

+'					if (evt.keyCode == 38 && commandHistory.length > 0 && evt.preventDefault) { // Up',

+'						evt.preventDefault();',

+'					}',

+'				};',

+'',

+'				// Prevent the keyup event blurring the input in Opera',

+'				$("command").onkeyup = function(evt) {',

+'					evt = getEvent(evt);',

+'					if (evt.keyCode == 27 && evt.preventDefault) { // Up',

+'						evt.preventDefault();',

+'						this.focus();',

+'					}',

+'				};',

+'',

+'				// Add document keyboard shortcuts',

+'				document.onkeydown = function keyEventHandler(evt) {',

+'					evt = getEvent(evt);',

+'					switch (evt.keyCode) {',

+'						case 69: // Ctrl + shift + E: re-execute last command',

+'							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',

+'								evalLastCommand();',

+'								cancelKeyEvent(evt);',

+'								return false;',

+'							}',

+'							break;',

+'						case 75: // Ctrl + shift + K: focus search',

+'							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',

+'								focusSearch();',

+'								cancelKeyEvent(evt);',

+'								return false;',

+'							}',

+'							break;',

+'						case 40: // Ctrl + shift + down arrow: focus command line',

+'						case 76: // Ctrl + shift + L: focus command line',

+'							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',

+'								focusCommandLine();',

+'								cancelKeyEvent(evt);',

+'								return false;',

+'							}',

+'							break;',

+'					}',

+'				};',

+'',

+'				// Workaround to make sure log div starts at the correct size',

+'				setTimeout(setLogContainerHeight, 20);',

+'',

+'				setShowCommandLine(showCommandLine);',

+'				doSearch();',

+'			};',

+'',

+'			window.onunload = function() {',

+'				if (mainWindowExists()) {',

+'					appender.unload();',

+'				}',

+'				appender = null;',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function toggleLoggingEnabled() {',

+'				setLoggingEnabled($("enableLogging").checked);',

+'			}',

+'',

+'			function setLoggingEnabled(enable) {',

+'				loggingEnabled = enable;',

+'			}',

+'',

+'			var appender = null;',

+'',

+'			function setAppender(appenderParam) {',

+'				appender = appenderParam;',

+'			}',

+'',

+'			function setShowCloseButton(showCloseButton) {',

+'				$("closeButton").style.display = showCloseButton ? "inline" : "none";',

+'			}',

+'',

+'			function setShowHideButton(showHideButton) {',

+'				$("hideButton").style.display = showHideButton ? "inline" : "none";',

+'			}',

+'',

+'			var newestAtTop = false;',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItemContentReverser() {',

+'			}',

+'			',

+'			LogItemContentReverser.prototype = new LogItemVisitor();',

+'			',

+'			LogItemContentReverser.prototype.visitGroup = function(group) {',

+'				group.reverseChildren();',

+'				this.visitChildren(group);',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function setNewestAtTop(isNewestAtTop) {',

+'				var oldNewestAtTop = newestAtTop;',

+'				var i, iLen, j, jLen;',

+'				newestAtTop = Boolean(isNewestAtTop);',

+'				if (oldNewestAtTop != newestAtTop) {',

+'					var visitor = new LogItemContentReverser();',

+'					rootGroup.accept(visitor);',

+'',

+'					// Reassemble the matches array',

+'					if (currentSearch) {',

+'						var currentMatch = currentSearch.matches[currentMatchIndex];',

+'						var matchIndex = 0;',

+'						var matches = [];',

+'						var actOnLogEntry = function(logEntry) {',

+'							var logEntryMatches = logEntry.getSearchMatches();',

+'							for (j = 0, jLen = logEntryMatches.length; j < jLen; j++) {',

+'								matches[matchIndex] = logEntryMatches[j];',

+'								if (currentMatch && logEntryMatches[j].equals(currentMatch)) {',

+'									currentMatchIndex = matchIndex;',

+'								}',

+'								matchIndex++;',

+'							}',

+'						};',

+'						if (newestAtTop) {',

+'							for (i = logEntries.length - 1; i >= 0; i--) {',

+'								actOnLogEntry(logEntries[i]);',

+'							}',

+'						} else {',

+'							for (i = 0, iLen = logEntries.length; i < iLen; i++) {',

+'								actOnLogEntry(logEntries[i]);',

+'							}',

+'						}',

+'						currentSearch.matches = matches;',

+'						if (currentMatch) {',

+'							currentMatch.setCurrent();',

+'						}',

+'					} else if (scrollToLatest) {',

+'						doScrollToLatest();',

+'					}',

+'				}',

+'				$("newestAtTop").checked = isNewestAtTop;',

+'			}',

+'',

+'			function toggleNewestAtTop() {',

+'				var isNewestAtTop = $("newestAtTop").checked;',

+'				setNewestAtTop(isNewestAtTop);',

+'			}',

+'',

+'			var scrollToLatest = true;',

+'',

+'			function setScrollToLatest(isScrollToLatest) {',

+'				scrollToLatest = isScrollToLatest;',

+'				if (scrollToLatest) {',

+'					doScrollToLatest();',

+'				}',

+'				$("scrollToLatest").checked = isScrollToLatest;',

+'			}',

+'',

+'			function toggleScrollToLatest() {',

+'				var isScrollToLatest = $("scrollToLatest").checked;',

+'				setScrollToLatest(isScrollToLatest);',

+'			}',

+'',

+'			function doScrollToLatest() {',

+'				var l = logMainContainer;',

+'				if (typeof l.scrollTop != "undefined") {',

+'					if (newestAtTop) {',

+'						l.scrollTop = 0;',

+'					} else {',

+'						var latestLogEntry = l.lastChild;',

+'						if (latestLogEntry) {',

+'							l.scrollTop = l.scrollHeight;',

+'						}',

+'					}',

+'				}',

+'			}',

+'',

+'			var closeIfOpenerCloses = true;',

+'',

+'			function setCloseIfOpenerCloses(isCloseIfOpenerCloses) {',

+'				closeIfOpenerCloses = isCloseIfOpenerCloses;',

+'			}',

+'',

+'			var maxMessages = null;',

+'',

+'			function setMaxMessages(max) {',

+'				maxMessages = max;',

+'				pruneLogEntries();',

+'			}',

+'',

+'			var showCommandLine = false;',

+'',

+'			function setShowCommandLine(isShowCommandLine) {',

+'				showCommandLine = isShowCommandLine;',

+'				if (loaded) {',

+'					$("commandLine").style.display = showCommandLine ? "block" : "none";',

+'					setCommandInputWidth();',

+'					setLogContainerHeight();',

+'				}',

+'			}',

+'',

+'			function focusCommandLine() {',

+'				if (loaded) {',

+'					$("command").focus();',

+'				}',

+'			}',

+'',

+'			function focusSearch() {',

+'				if (loaded) {',

+'					$("searchBox").focus();',

+'				}',

+'			}',

+'',

+'			function getLogItems() {',

+'				var items = [];',

+'				for (var i = 0, len = logItems.length; i < len; i++) {',

+'					logItems[i].serialize(items);',

+'				}',

+'				return items;',

+'			}',

+'',

+'			function setLogItems(items) {',

+'				var loggingReallyEnabled = loggingEnabled;',

+'				// Temporarily turn logging on',

+'				loggingEnabled = true;',

+'				for (var i = 0, len = items.length; i < len; i++) {',

+'					switch (items[i][0]) {',

+'						case LogItem.serializedItemKeys.LOG_ENTRY:',

+'							log(items[i][1], items[i][2]);',

+'							break;',

+'						case LogItem.serializedItemKeys.GROUP_START:',

+'							group(items[i][1]);',

+'							break;',

+'						case LogItem.serializedItemKeys.GROUP_END:',

+'							groupEnd();',

+'							break;',

+'					}',

+'				}',

+'				loggingEnabled = loggingReallyEnabled;',

+'			}',

+'',

+'			function log(logLevel, formattedMessage) {',

+'				if (loggingEnabled) {',

+'					var logEntry = new LogEntry(logLevel, formattedMessage);',

+'					logEntries.push(logEntry);',

+'					logEntriesAndSeparators.push(logEntry);',

+'					logItems.push(logEntry);',

+'					currentGroup.addChild(logEntry);',

+'					if (loaded) {',

+'						if (logQueuedEventsTimer !== null) {',

+'							clearTimeout(logQueuedEventsTimer);',

+'						}',

+'						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);',

+'						unrenderedLogItemsExist = true;',

+'					}',

+'				}',

+'			}',

+'',

+'			function renderQueuedLogItems() {',

+'				logQueuedEventsTimer = null;',

+'				var pruned = pruneLogEntries();',

+'',

+'				// Render any unrendered log entries and apply the current search to them',

+'				var initiallyHasMatches = currentSearch ? currentSearch.hasMatches() : false;',

+'				for (var i = 0, len = logItems.length; i < len; i++) {',

+'					if (!logItems[i].rendered) {',

+'						logItems[i].render();',

+'						logItems[i].appendToLog();',

+'						if (currentSearch && (logItems[i] instanceof LogEntry)) {',

+'							currentSearch.applyTo(logItems[i]);',

+'						}',

+'					}',

+'				}',

+'				if (currentSearch) {',

+'					if (pruned) {',

+'						if (currentSearch.hasVisibleMatches()) {',

+'							if (currentMatchIndex === null) {',

+'								setCurrentMatchIndex(0);',

+'							}',

+'							displayMatches();',

+'						} else {',

+'							displayNoMatches();',

+'						}',

+'					} else if (!initiallyHasMatches && currentSearch.hasVisibleMatches()) {',

+'						setCurrentMatchIndex(0);',

+'						displayMatches();',

+'					}',

+'				}',

+'				if (scrollToLatest) {',

+'					doScrollToLatest();',

+'				}',

+'				unrenderedLogItemsExist = false;',

+'			}',

+'',

+'			function pruneLogEntries() {',

+'				if ((maxMessages !== null) && (logEntriesAndSeparators.length > maxMessages)) {',

+'					var numberToDelete = logEntriesAndSeparators.length - maxMessages;',

+'					var prunedLogEntries = logEntriesAndSeparators.slice(0, numberToDelete);',

+'					if (currentSearch) {',

+'						currentSearch.removeMatches(prunedLogEntries);',

+'					}',

+'					var group;',

+'					for (var i = 0; i < numberToDelete; i++) {',

+'						group = logEntriesAndSeparators[i].group;',

+'						array_remove(logItems, logEntriesAndSeparators[i]);',

+'						array_remove(logEntries, logEntriesAndSeparators[i]);',

+'						logEntriesAndSeparators[i].remove(true, true);',

+'						if (group.children.length === 0 && group !== currentGroup && group !== rootGroup) {',

+'							array_remove(logItems, group);',

+'							group.remove(true, true);',

+'						}',

+'					}',

+'					logEntriesAndSeparators = array_removeFromStart(logEntriesAndSeparators, numberToDelete);',

+'					return true;',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function group(name, startExpanded) {',

+'				if (loggingEnabled) {',

+'					initiallyExpanded = (typeof startExpanded === "undefined") ? true : Boolean(startExpanded);',

+'					var newGroup = new Group(name, false, initiallyExpanded);',

+'					currentGroup.addChild(newGroup);',

+'					currentGroup = newGroup;',

+'					logItems.push(newGroup);',

+'					if (loaded) {',

+'						if (logQueuedEventsTimer !== null) {',

+'							clearTimeout(logQueuedEventsTimer);',

+'						}',

+'						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);',

+'						unrenderedLogItemsExist = true;',

+'					}',

+'				}',

+'			}',

+'',

+'			function groupEnd() {',

+'				currentGroup = (currentGroup === rootGroup) ? rootGroup : currentGroup.group;',

+'			}',

+'',

+'			function mainPageReloaded() {',

+'				currentGroup = rootGroup;',

+'				var separator = new Separator();',

+'				logEntriesAndSeparators.push(separator);',

+'				logItems.push(separator);',

+'				currentGroup.addChild(separator);',

+'			}',

+'',

+'			function closeWindow() {',

+'				if (appender && mainWindowExists()) {',

+'					appender.close(true);',

+'				} else {',

+'					window.close();',

+'				}',

+'			}',

+'',

+'			function hide() {',

+'				if (appender && mainWindowExists()) {',

+'					appender.hide();',

+'				}',

+'			}',

+'',

+'			var mainWindow = window;',

+'			var windowId = "log4javascriptConsoleWindow_" + new Date().getTime() + "_" + ("" + Math.random()).substr(2);',

+'',

+'			function setMainWindow(win) {',

+'				mainWindow = win;',

+'				mainWindow[windowId] = window;',

+'				// If this is a pop-up, poll the opener to see if it\'s closed',

+'				if (opener && closeIfOpenerCloses) {',

+'					pollOpener();',

+'				}',

+'			}',

+'',

+'			function pollOpener() {',

+'				if (closeIfOpenerCloses) {',

+'					if (mainWindowExists()) {',

+'						setTimeout(pollOpener, 500);',

+'					} else {',

+'						closeWindow();',

+'					}',

+'				}',

+'			}',

+'',

+'			function mainWindowExists() {',

+'				try {',

+'					return (mainWindow && !mainWindow.closed &&',

+'						mainWindow[windowId] == window);',

+'				} catch (ex) {}',

+'				return false;',

+'			}',

+'',

+'			var logLevels = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"];',

+'',

+'			function getCheckBox(logLevel) {',

+'				return $("switch_" + logLevel);',

+'			}',

+'',

+'			function getIeWrappedLogContainer() {',

+'				return $("log_wrapped");',

+'			}',

+'',

+'			function getIeUnwrappedLogContainer() {',

+'				return $("log_unwrapped");',

+'			}',

+'',

+'			function applyFilters() {',

+'				for (var i = 0; i < logLevels.length; i++) {',

+'					if (getCheckBox(logLevels[i]).checked) {',

+'						addClass(logMainContainer, logLevels[i]);',

+'					} else {',

+'						removeClass(logMainContainer, logLevels[i]);',

+'					}',

+'				}',

+'				updateSearchFromFilters();',

+'			}',

+'',

+'			function toggleAllLevels() {',

+'				var turnOn = $("switch_ALL").checked;',

+'				for (var i = 0; i < logLevels.length; i++) {',

+'					getCheckBox(logLevels[i]).checked = turnOn;',

+'					if (turnOn) {',

+'						addClass(logMainContainer, logLevels[i]);',

+'					} else {',

+'						removeClass(logMainContainer, logLevels[i]);',

+'					}',

+'				}',

+'			}',

+'',

+'			function checkAllLevels() {',

+'				for (var i = 0; i < logLevels.length; i++) {',

+'					if (!getCheckBox(logLevels[i]).checked) {',

+'						getCheckBox("ALL").checked = false;',

+'						return;',

+'					}',

+'				}',

+'				getCheckBox("ALL").checked = true;',

+'			}',

+'',

+'			function clearLog() {',

+'				rootGroup.clear();',

+'				currentGroup = rootGroup;',

+'				logEntries = [];',

+'				logItems = [];',

+'				logEntriesAndSeparators = [];',

+' 				doSearch();',

+'			}',

+'',

+'			function toggleWrap() {',

+'				var enable = $("wrap").checked;',

+'				if (enable) {',

+'					addClass(logMainContainer, "wrap");',

+'				} else {',

+'					removeClass(logMainContainer, "wrap");',

+'				}',

+'				refreshCurrentMatch();',

+'			}',

+'',

+'			/* ------------------------------------------------------------------- */',

+'',

+'			// Search',

+'',

+'			var searchTimer = null;',

+'',

+'			function scheduleSearch() {',

+'				try {',

+'					clearTimeout(searchTimer);',

+'				} catch (ex) {',

+'					// Do nothing',

+'				}',

+'				searchTimer = setTimeout(doSearch, 500);',

+'			}',

+'',

+'			function Search(searchTerm, isRegex, searchRegex, isCaseSensitive) {',

+'				this.searchTerm = searchTerm;',

+'				this.isRegex = isRegex;',

+'				this.searchRegex = searchRegex;',

+'				this.isCaseSensitive = isCaseSensitive;',

+'				this.matches = [];',

+'			}',

+'',

+'			Search.prototype = {',

+'				hasMatches: function() {',

+'					return this.matches.length > 0;',

+'				},',

+'',

+'				hasVisibleMatches: function() {',

+'					if (this.hasMatches()) {',

+'						for (var i = 0; i < this.matches.length; i++) {',

+'							if (this.matches[i].isVisible()) {',

+'								return true;',

+'							}',

+'						}',

+'					}',

+'					return false;',

+'				},',

+'',

+'				match: function(logEntry) {',

+'					var entryText = String(logEntry.formattedMessage);',

+'					var matchesSearch = false;',

+'					if (this.isRegex) {',

+'						matchesSearch = this.searchRegex.test(entryText);',

+'					} else if (this.isCaseSensitive) {',

+'						matchesSearch = (entryText.indexOf(this.searchTerm) > -1);',

+'					} else {',

+'						matchesSearch = (entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1);',

+'					}',

+'					return matchesSearch;',

+'				},',

+'',

+'				getNextVisibleMatchIndex: function() {',

+'					for (var i = currentMatchIndex + 1; i < this.matches.length; i++) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					// Start again from the first match',

+'					for (i = 0; i <= currentMatchIndex; i++) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					return -1;',

+'				},',

+'',

+'				getPreviousVisibleMatchIndex: function() {',

+'					for (var i = currentMatchIndex - 1; i >= 0; i--) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					// Start again from the last match',

+'					for (var i = this.matches.length - 1; i >= currentMatchIndex; i--) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					return -1;',

+'				},',

+'',

+'				applyTo: function(logEntry) {',

+'					var doesMatch = this.match(logEntry);',

+'					if (doesMatch) {',

+'						logEntry.group.expand();',

+'						logEntry.setSearchMatch(true);',

+'						var logEntryContent;',

+'						var wrappedLogEntryContent;',

+'						var searchTermReplacementStartTag = "<span class=\\\"searchterm\\\">";',

+'						var searchTermReplacementEndTag = "<" + "/span>";',

+'						var preTagName = isIe ? "pre" : "span";',

+'						var preStartTag = "<" + preTagName + " class=\\\"pre\\\">";',

+'						var preEndTag = "<" + "/" + preTagName + ">";',

+'						var startIndex = 0;',

+'						var searchIndex, matchedText, textBeforeMatch;',

+'						if (this.isRegex) {',

+'							var flags = this.isCaseSensitive ? "g" : "gi";',

+'							var capturingRegex = new RegExp("(" + this.searchRegex.source + ")", flags);',

+'',

+'							// Replace the search term with temporary tokens for the start and end tags',

+'							var rnd = ("" + Math.random()).substr(2);',

+'							var startToken = "%%s" + rnd + "%%";',

+'							var endToken = "%%e" + rnd + "%%";',

+'							logEntryContent = logEntry.formattedMessage.replace(capturingRegex, startToken + "$1" + endToken);',

+'',

+'							// Escape the HTML to get rid of angle brackets',

+'							logEntryContent = escapeHtml(logEntryContent);',

+'',

+'							// Substitute the proper HTML back in for the search match',

+'							var result;',

+'							var searchString = logEntryContent;',

+'							logEntryContent = "";',

+'							wrappedLogEntryContent = "";',

+'							while ((searchIndex = searchString.indexOf(startToken, startIndex)) > -1) {',

+'								var endTokenIndex = searchString.indexOf(endToken, searchIndex);',

+'								matchedText = searchString.substring(searchIndex + startToken.length, endTokenIndex);',

+'								textBeforeMatch = searchString.substring(startIndex, searchIndex);',

+'								logEntryContent += preStartTag + textBeforeMatch + preEndTag;',

+'								logEntryContent += searchTermReplacementStartTag + preStartTag + matchedText +',

+'									preEndTag + searchTermReplacementEndTag;',

+'								if (isIe) {',

+'									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +',

+'										matchedText + searchTermReplacementEndTag;',

+'								}',

+'								startIndex = endTokenIndex + endToken.length;',

+'							}',

+'							logEntryContent += preStartTag + searchString.substr(startIndex) + preEndTag;',

+'							if (isIe) {',

+'								wrappedLogEntryContent += searchString.substr(startIndex);',

+'							}',

+'						} else {',

+'							logEntryContent = "";',

+'							wrappedLogEntryContent = "";',

+'							var searchTermReplacementLength = searchTermReplacementStartTag.length +',

+'								this.searchTerm.length + searchTermReplacementEndTag.length;',

+'							var searchTermLength = this.searchTerm.length;',

+'							var searchTermLowerCase = this.searchTerm.toLowerCase();',

+'							var logTextLowerCase = logEntry.formattedMessage.toLowerCase();',

+'							while ((searchIndex = logTextLowerCase.indexOf(searchTermLowerCase, startIndex)) > -1) {',

+'								matchedText = escapeHtml(logEntry.formattedMessage.substr(searchIndex, this.searchTerm.length));',

+'								textBeforeMatch = escapeHtml(logEntry.formattedMessage.substring(startIndex, searchIndex));',

+'								var searchTermReplacement = searchTermReplacementStartTag +',

+'									preStartTag + matchedText + preEndTag + searchTermReplacementEndTag;',

+'								logEntryContent += preStartTag + textBeforeMatch + preEndTag + searchTermReplacement;',

+'								if (isIe) {',

+'									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +',

+'										matchedText + searchTermReplacementEndTag;',

+'								}',

+'								startIndex = searchIndex + searchTermLength;',

+'							}',

+'							var textAfterLastMatch = escapeHtml(logEntry.formattedMessage.substr(startIndex));',

+'							logEntryContent += preStartTag + textAfterLastMatch + preEndTag;',

+'							if (isIe) {',

+'								wrappedLogEntryContent += textAfterLastMatch;',

+'							}',

+'						}',

+'						logEntry.setContent(logEntryContent, wrappedLogEntryContent);',

+'						var logEntryMatches = logEntry.getSearchMatches();',

+'						this.matches = this.matches.concat(logEntryMatches);',

+'					} else {',

+'						logEntry.setSearchMatch(false);',

+'						logEntry.setContent(logEntry.formattedMessage, logEntry.formattedMessage);',

+'					}',

+'					return doesMatch;',

+'				},',

+'',

+'				removeMatches: function(logEntries) {',

+'					var matchesToRemoveCount = 0;',

+'					var currentMatchRemoved = false;',

+'					var matchesToRemove = [];',

+'					var i, iLen, j, jLen;',

+'',

+'					// Establish the list of matches to be removed',

+'					for (i = 0, iLen = this.matches.length; i < iLen; i++) {',

+'						for (j = 0, jLen = logEntries.length; j < jLen; j++) {',

+'							if (this.matches[i].belongsTo(logEntries[j])) {',

+'								matchesToRemove.push(this.matches[i]);',

+'								if (i === currentMatchIndex) {',

+'									currentMatchRemoved = true;',

+'								}',

+'							}',

+'						}',

+'					}',

+'',

+'					// Set the new current match index if the current match has been deleted',

+'					// This will be the first match that appears after the first log entry being',

+'					// deleted, if one exists; otherwise, it\'s the first match overall',

+'					var newMatch = currentMatchRemoved ? null : this.matches[currentMatchIndex];',

+'					if (currentMatchRemoved) {',

+'						for (i = currentMatchIndex, iLen = this.matches.length; i < iLen; i++) {',

+'							if (this.matches[i].isVisible() && !array_contains(matchesToRemove, this.matches[i])) {',

+'								newMatch = this.matches[i];',

+'								break;',

+'							}',

+'						}',

+'					}',

+'',

+'					// Remove the matches',

+'					for (i = 0, iLen = matchesToRemove.length; i < iLen; i++) {',

+'						array_remove(this.matches, matchesToRemove[i]);',

+'						matchesToRemove[i].remove();',

+'					}',

+'',

+'					// Set the new match, if one exists',

+'					if (this.hasVisibleMatches()) {',

+'						if (newMatch === null) {',

+'							setCurrentMatchIndex(0);',

+'						} else {',

+'							// Get the index of the new match',

+'							var newMatchIndex = 0;',

+'							for (i = 0, iLen = this.matches.length; i < iLen; i++) {',

+'								if (newMatch === this.matches[i]) {',

+'									newMatchIndex = i;',

+'									break;',

+'								}',

+'							}',

+'							setCurrentMatchIndex(newMatchIndex);',

+'						}',

+'					} else {',

+'						currentMatchIndex = null;',

+'						displayNoMatches();',

+'					}',

+'				}',

+'			};',

+'',

+'			function getPageOffsetTop(el, container) {',

+'				var currentEl = el;',

+'				var y = 0;',

+'				while (currentEl && currentEl != container) {',

+'					y += currentEl.offsetTop;',

+'					currentEl = currentEl.offsetParent;',

+'				}',

+'				return y;',

+'			}',

+'',

+'			function scrollIntoView(el) {',

+'				var logContainer = logMainContainer;',

+'				// Check if the whole width of the element is visible and centre if not',

+'				if (!$("wrap").checked) {',

+'					var logContainerLeft = logContainer.scrollLeft;',

+'					var logContainerRight = logContainerLeft  + logContainer.offsetWidth;',

+'					var elLeft = el.offsetLeft;',

+'					var elRight = elLeft + el.offsetWidth;',

+'					if (elLeft < logContainerLeft || elRight > logContainerRight) {',

+'						logContainer.scrollLeft = elLeft - (logContainer.offsetWidth - el.offsetWidth) / 2;',

+'					}',

+'				}',

+'				// Check if the whole height of the element is visible and centre if not',

+'				var logContainerTop = logContainer.scrollTop;',

+'				var logContainerBottom = logContainerTop  + logContainer.offsetHeight;',

+'				var elTop = getPageOffsetTop(el) - getToolBarsHeight();',

+'				var elBottom = elTop + el.offsetHeight;',

+'				if (elTop < logContainerTop || elBottom > logContainerBottom) {',

+'					logContainer.scrollTop = elTop - (logContainer.offsetHeight - el.offsetHeight) / 2;',

+'				}',

+'			}',

+'',

+'			function Match(logEntryLevel, spanInMainDiv, spanInUnwrappedPre, spanInWrappedDiv) {',

+'				this.logEntryLevel = logEntryLevel;',

+'				this.spanInMainDiv = spanInMainDiv;',

+'				if (isIe) {',

+'					this.spanInUnwrappedPre = spanInUnwrappedPre;',

+'					this.spanInWrappedDiv = spanInWrappedDiv;',

+'				}',

+'				this.mainSpan = isIe ? spanInUnwrappedPre : spanInMainDiv;',

+'			}',

+'',

+'			Match.prototype = {',

+'				equals: function(match) {',

+'					return this.mainSpan === match.mainSpan;',

+'				},',

+'',

+'				setCurrent: function() {',

+'					if (isIe) {',

+'						addClass(this.spanInUnwrappedPre, "currentmatch");',

+'						addClass(this.spanInWrappedDiv, "currentmatch");',

+'						// Scroll the visible one into view',

+'						var elementToScroll = $("wrap").checked ? this.spanInWrappedDiv : this.spanInUnwrappedPre;',

+'						scrollIntoView(elementToScroll);',

+'					} else {',

+'						addClass(this.spanInMainDiv, "currentmatch");',

+'						scrollIntoView(this.spanInMainDiv);',

+'					}',

+'				},',

+'',

+'				belongsTo: function(logEntry) {',

+'					if (isIe) {',

+'						return isDescendant(this.spanInUnwrappedPre, logEntry.unwrappedPre);',

+'					} else {',

+'						return isDescendant(this.spanInMainDiv, logEntry.mainDiv);',

+'					}',

+'				},',

+'',

+'				setNotCurrent: function() {',

+'					if (isIe) {',

+'						removeClass(this.spanInUnwrappedPre, "currentmatch");',

+'						removeClass(this.spanInWrappedDiv, "currentmatch");',

+'					} else {',

+'						removeClass(this.spanInMainDiv, "currentmatch");',

+'					}',

+'				},',

+'',

+'				isOrphan: function() {',

+'					return isOrphan(this.mainSpan);',

+'				},',

+'',

+'				isVisible: function() {',

+'					return getCheckBox(this.logEntryLevel).checked;',

+'				},',

+'',

+'				remove: function() {',

+'					if (isIe) {',

+'						this.spanInUnwrappedPre = null;',

+'						this.spanInWrappedDiv = null;',

+'					} else {',

+'						this.spanInMainDiv = null;',

+'					}',

+'				}',

+'			};',

+'',

+'			var currentSearch = null;',

+'			var currentMatchIndex = null;',

+'',

+'			function doSearch() {',

+'				var searchBox = $("searchBox");',

+'				var searchTerm = searchBox.value;',

+'				var isRegex = $("searchRegex").checked;',

+'				var isCaseSensitive = $("searchCaseSensitive").checked;',

+'				var i;',

+'',

+'				if (searchTerm === "") {',

+'					$("searchReset").disabled = true;',

+'					$("searchNav").style.display = "none";',

+'					removeClass(document.body, "searching");',

+'					removeClass(searchBox, "hasmatches");',

+'					removeClass(searchBox, "nomatches");',

+'					for (i = 0; i < logEntries.length; i++) {',

+'						logEntries[i].clearSearch();',

+'						logEntries[i].setContent(logEntries[i].formattedMessage, logEntries[i].formattedMessage);',

+'					}',

+'					currentSearch = null;',

+'					setLogContainerHeight();',

+'				} else {',

+'					$("searchReset").disabled = false;',

+'					$("searchNav").style.display = "block";',

+'					var searchRegex;',

+'					var regexValid;',

+'					if (isRegex) {',

+'						try {',

+'							searchRegex = isCaseSensitive ? new RegExp(searchTerm, "g") : new RegExp(searchTerm, "gi");',

+'							regexValid = true;',

+'							replaceClass(searchBox, "validregex", "invalidregex");',

+'							searchBox.title = "Valid regex";',

+'						} catch (ex) {',

+'							regexValid = false;',

+'							replaceClass(searchBox, "invalidregex", "validregex");',

+'							searchBox.title = "Invalid regex: " + (ex.message ? ex.message : (ex.description ? ex.description : "unknown error"));',

+'							return;',

+'						}',

+'					} else {',

+'						searchBox.title = "";',

+'						removeClass(searchBox, "validregex");',

+'						removeClass(searchBox, "invalidregex");',

+'					}',

+'					addClass(document.body, "searching");',

+'					currentSearch = new Search(searchTerm, isRegex, searchRegex, isCaseSensitive);',

+'					for (i = 0; i < logEntries.length; i++) {',

+'						currentSearch.applyTo(logEntries[i]);',

+'					}',

+'					setLogContainerHeight();',

+'',

+'					// Highlight the first search match',

+'					if (currentSearch.hasVisibleMatches()) {',

+'						setCurrentMatchIndex(0);',

+'						displayMatches();',

+'					} else {',

+'						displayNoMatches();',

+'					}',

+'				}',

+'			}',

+'',

+'			function updateSearchFromFilters() {',

+'				if (currentSearch) {',

+'					if (currentSearch.hasMatches()) {',

+'						if (currentMatchIndex === null) {',

+'							currentMatchIndex = 0;',

+'						}',

+'						var currentMatch = currentSearch.matches[currentMatchIndex];',

+'						if (currentMatch.isVisible()) {',

+'							displayMatches();',

+'							setCurrentMatchIndex(currentMatchIndex);',

+'						} else {',

+'							currentMatch.setNotCurrent();',

+'							// Find the next visible match, if one exists',

+'							var nextVisibleMatchIndex = currentSearch.getNextVisibleMatchIndex();',

+'							if (nextVisibleMatchIndex > -1) {',

+'								setCurrentMatchIndex(nextVisibleMatchIndex);',

+'								displayMatches();',

+'							} else {',

+'								displayNoMatches();',

+'							}',

+'						}',

+'					} else {',

+'						displayNoMatches();',

+'					}',

+'				}',

+'			}',

+'',

+'			function refreshCurrentMatch() {',

+'				if (currentSearch && currentSearch.hasVisibleMatches()) {',

+'					setCurrentMatchIndex(currentMatchIndex);',

+'				}',

+'			}',

+'',

+'			function displayMatches() {',

+'				replaceClass($("searchBox"), "hasmatches", "nomatches");',

+'				$("searchBox").title = "" + currentSearch.matches.length + " matches found";',

+'				$("searchNav").style.display = "block";',

+'				setLogContainerHeight();',

+'			}',

+'',

+'			function displayNoMatches() {',

+'				replaceClass($("searchBox"), "nomatches", "hasmatches");',

+'				$("searchBox").title = "No matches found";',

+'				$("searchNav").style.display = "none";',

+'				setLogContainerHeight();',

+'			}',

+'',

+'			function toggleSearchEnabled(enable) {',

+'				enable = (typeof enable == "undefined") ? !$("searchDisable").checked : enable;',

+'				$("searchBox").disabled = !enable;',

+'				$("searchReset").disabled = !enable;',

+'				$("searchRegex").disabled = !enable;',

+'				$("searchNext").disabled = !enable;',

+'				$("searchPrevious").disabled = !enable;',

+'				$("searchCaseSensitive").disabled = !enable;',

+'				$("searchNav").style.display = (enable && ($("searchBox").value !== "") &&',

+'						currentSearch && currentSearch.hasVisibleMatches()) ?',

+'					"block" : "none";',

+'				if (enable) {',

+'					removeClass($("search"), "greyedout");',

+'					addClass(document.body, "searching");',

+'					if ($("searchHighlight").checked) {',

+'						addClass(logMainContainer, "searchhighlight");',

+'					} else {',

+'						removeClass(logMainContainer, "searchhighlight");',

+'					}',

+'					if ($("searchFilter").checked) {',

+'						addClass(logMainContainer, "searchfilter");',

+'					} else {',

+'						removeClass(logMainContainer, "searchfilter");',

+'					}',

+'					$("searchDisable").checked = !enable;',

+'				} else {',

+'					addClass($("search"), "greyedout");',

+'					removeClass(document.body, "searching");',

+'					removeClass(logMainContainer, "searchhighlight");',

+'					removeClass(logMainContainer, "searchfilter");',

+'				}',

+'				setLogContainerHeight();',

+'			}',

+'',

+'			function toggleSearchFilter() {',

+'				var enable = $("searchFilter").checked;',

+'				if (enable) {',

+'					addClass(logMainContainer, "searchfilter");',

+'				} else {',

+'					removeClass(logMainContainer, "searchfilter");',

+'				}',

+'				refreshCurrentMatch();',

+'			}',

+'',

+'			function toggleSearchHighlight() {',

+'				var enable = $("searchHighlight").checked;',

+'				if (enable) {',

+'					addClass(logMainContainer, "searchhighlight");',

+'				} else {',

+'					removeClass(logMainContainer, "searchhighlight");',

+'				}',

+'			}',

+'',

+'			function clearSearch() {',

+'				$("searchBox").value = "";',

+'				doSearch();',

+'			}',

+'',

+'			function searchNext() {',

+'				if (currentSearch !== null && currentMatchIndex !== null) {',

+'					currentSearch.matches[currentMatchIndex].setNotCurrent();',

+'					var nextMatchIndex = currentSearch.getNextVisibleMatchIndex();',

+'					if (nextMatchIndex > currentMatchIndex || confirm("Reached the end of the page. Start from the top?")) {',

+'						setCurrentMatchIndex(nextMatchIndex);',

+'					}',

+'				}',

+'			}',

+'',

+'			function searchPrevious() {',

+'				if (currentSearch !== null && currentMatchIndex !== null) {',

+'					currentSearch.matches[currentMatchIndex].setNotCurrent();',

+'					var previousMatchIndex = currentSearch.getPreviousVisibleMatchIndex();',

+'					if (previousMatchIndex < currentMatchIndex || confirm("Reached the start of the page. Continue from the bottom?")) {',

+'						setCurrentMatchIndex(previousMatchIndex);',

+'					}',

+'				}',

+'			}',

+'',

+'			function setCurrentMatchIndex(index) {',

+'				currentMatchIndex = index;',

+'				currentSearch.matches[currentMatchIndex].setCurrent();',

+'			}',

+'',

+'			/* ------------------------------------------------------------------------- */',

+'',

+'			// CSS Utilities',

+'',

+'			function addClass(el, cssClass) {',

+'				if (!hasClass(el, cssClass)) {',

+'					if (el.className) {',

+'						el.className += " " + cssClass;',

+'					} else {',

+'						el.className = cssClass;',

+'					}',

+'				}',

+'			}',

+'',

+'			function hasClass(el, cssClass) {',

+'				if (el.className) {',

+'					var classNames = el.className.split(" ");',

+'					return array_contains(classNames, cssClass);',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function removeClass(el, cssClass) {',

+'				if (hasClass(el, cssClass)) {',

+'					// Rebuild the className property',

+'					var existingClasses = el.className.split(" ");',

+'					var newClasses = [];',

+'					for (var i = 0, len = existingClasses.length; i < len; i++) {',

+'						if (existingClasses[i] != cssClass) {',

+'							newClasses[newClasses.length] = existingClasses[i];',

+'						}',

+'					}',

+'					el.className = newClasses.join(" ");',

+'				}',

+'			}',

+'',

+'			function replaceClass(el, newCssClass, oldCssClass) {',

+'				removeClass(el, oldCssClass);',

+'				addClass(el, newCssClass);',

+'			}',

+'',

+'			/* ------------------------------------------------------------------------- */',

+'',

+'			// Other utility functions',

+'',

+'			function getElementsByClass(el, cssClass, tagName) {',

+'				var elements = el.getElementsByTagName(tagName);',

+'				var matches = [];',

+'				for (var i = 0, len = elements.length; i < len; i++) {',

+'					if (hasClass(elements[i], cssClass)) {',

+'						matches.push(elements[i]);',

+'					}',

+'				}',

+'				return matches;',

+'			}',

+'',

+'			// Syntax borrowed from Prototype library',

+'			function $(id) {',

+'				return document.getElementById(id);',

+'			}',

+'',

+'			function isDescendant(node, ancestorNode) {',

+'				while (node != null) {',

+'					if (node === ancestorNode) {',

+'						return true;',

+'					}',

+'					node = node.parentNode;',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function isOrphan(node) {',

+'				var currentNode = node;',

+'				while (currentNode) {',

+'					if (currentNode == document.body) {',

+'						return false;',

+'					}',

+'					currentNode = currentNode.parentNode;',

+'				}',

+'				return true;',

+'			}',

+'',

+'			function escapeHtml(str) {',

+'				return str.replace(/&/g, "&amp;").replace(/[<]/g, "&lt;").replace(/>/g, "&gt;");',

+'			}',

+'',

+'			function getWindowWidth() {',

+'				if (window.innerWidth) {',

+'					return window.innerWidth;',

+'				} else if (document.documentElement && document.documentElement.clientWidth) {',

+'					return document.documentElement.clientWidth;',

+'				} else if (document.body) {',

+'					return document.body.clientWidth;',

+'				}',

+'				return 0;',

+'			}',

+'',

+'			function getWindowHeight() {',

+'				if (window.innerHeight) {',

+'					return window.innerHeight;',

+'				} else if (document.documentElement && document.documentElement.clientHeight) {',

+'					return document.documentElement.clientHeight;',

+'				} else if (document.body) {',

+'					return document.body.clientHeight;',

+'				}',

+'				return 0;',

+'			}',

+'',

+'			function getToolBarsHeight() {',

+'				return $("switches").offsetHeight;',

+'			}',

+'',

+'			function getChromeHeight() {',

+'				var height = getToolBarsHeight();',

+'				if (showCommandLine) {',

+'					height += $("commandLine").offsetHeight;',

+'				}',

+'				return height;',

+'			}',

+'',

+'			function setLogContainerHeight() {',

+'				if (logMainContainer) {',

+'					var windowHeight = getWindowHeight();',

+'					$("body").style.height = getWindowHeight() + "px";',

+'					logMainContainer.style.height = "" +',

+'						Math.max(0, windowHeight - getChromeHeight()) + "px";',

+'				}',

+'			}',

+'',

+'			function setCommandInputWidth() {',

+'				if (showCommandLine) {',

+'					$("command").style.width = "" + Math.max(0, $("commandLineContainer").offsetWidth -',

+'						($("evaluateButton").offsetWidth + 13)) + "px";',

+'				}',

+'			}',

+'',

+'			window.onresize = function() {',

+'				setCommandInputWidth();',

+'				setLogContainerHeight();',

+'			};',

+'',

+'			if (!Array.prototype.push) {',

+'				Array.prototype.push = function() {',

+'			        for (var i = 0, len = arguments.length; i < len; i++){',

+'			            this[this.length] = arguments[i];',

+'			        }',

+'			        return this.length;',

+'				};',

+'			}',

+'',

+'			if (!Array.prototype.pop) {',

+'				Array.prototype.pop = function() {',

+'					if (this.length > 0) {',

+'						var val = this[this.length - 1];',

+'						this.length = this.length - 1;',

+'						return val;',

+'					}',

+'				};',

+'			}',

+'',

+'			if (!Array.prototype.shift) {',

+'				Array.prototype.shift = function() {',

+'					if (this.length > 0) {',

+'						var firstItem = this[0];',

+'						for (var i = 0, len = this.length - 1; i < len; i++) {',

+'							this[i] = this[i + 1];',

+'						}',

+'						this.length = this.length - 1;',

+'						return firstItem;',

+'					}',

+'				};',

+'			}',

+'',

+'			if (!Array.prototype.splice) {',

+'				Array.prototype.splice = function(startIndex, deleteCount) {',

+'					var itemsAfterDeleted = this.slice(startIndex + deleteCount);',

+'					var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);',

+'					this.length = startIndex;',

+'					// Copy the arguments into a proper Array object',

+'					var argumentsArray = [];',

+'					for (var i = 0, len = arguments.length; i < len; i++) {',

+'						argumentsArray[i] = arguments[i];',

+'					}',

+'					var itemsToAppend = (argumentsArray.length > 2) ?',

+'						itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;',

+'					for (i = 0, len = itemsToAppend.length; i < len; i++) {',

+'						this.push(itemsToAppend[i]);',

+'					}',

+'					return itemsDeleted;',

+'				};',

+'			}',

+'',

+'			function array_remove(arr, val) {',

+'				var index = -1;',

+'				for (var i = 0, len = arr.length; i < len; i++) {',

+'					if (arr[i] === val) {',

+'						index = i;',

+'						break;',

+'					}',

+'				}',

+'				if (index >= 0) {',

+'					arr.splice(index, 1);',

+'					return index;',

+'				} else {',

+'					return false;',

+'				}',

+'			}',

+'',

+'			function array_removeFromStart(array, numberToRemove) {',

+'				if (Array.prototype.splice) {',

+'					array.splice(0, numberToRemove);',

+'				} else {',

+'					for (var i = numberToRemove, len = array.length; i < len; i++) {',

+'						array[i - numberToRemove] = array[i];',

+'					}',

+'					array.length = array.length - numberToRemove;',

+'				}',

+'				return array;',

+'			}',

+'',

+'			function array_contains(arr, val) {',

+'				for (var i = 0, len = arr.length; i < len; i++) {',

+'					if (arr[i] == val) {',

+'						return true;',

+'					}',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function getErrorMessage(ex) {',

+'				if (ex.message) {',

+'					return ex.message;',

+'				} else if (ex.description) {',

+'					return ex.description;',

+'				}',

+'				return "" + ex;',

+'			}',

+'',

+'			function moveCaretToEnd(input) {',

+'				if (input.setSelectionRange) {',

+'					input.focus();',

+'					var length = input.value.length;',

+'					input.setSelectionRange(length, length);',

+'				} else if (input.createTextRange) {',

+'					var range = input.createTextRange();',

+'					range.collapse(false);',

+'					range.select();',

+'				}',

+'				input.focus();',

+'			}',

+'',

+'			function stopPropagation(evt) {',

+'				if (evt.stopPropagation) {',

+'					evt.stopPropagation();',

+'				} else if (typeof evt.cancelBubble != "undefined") {',

+'					evt.cancelBubble = true;',

+'				}',

+'			}',

+'',

+'			function getEvent(evt) {',

+'				return evt ? evt : event;',

+'			}',

+'',

+'			function getTarget(evt) {',

+'				return evt.target ? evt.target : evt.srcElement;',

+'			}',

+'',

+'			function getRelatedTarget(evt) {',

+'				if (evt.relatedTarget) {',

+'					return evt.relatedTarget;',

+'				} else if (evt.srcElement) {',

+'					switch(evt.type) {',

+'						case "mouseover":',

+'							return evt.fromElement;',

+'						case "mouseout":',

+'							return evt.toElement;',

+'						default:',

+'							return evt.srcElement;',

+'					}',

+'				}',

+'			}',

+'',

+'			function cancelKeyEvent(evt) {',

+'				evt.returnValue = false;',

+'				stopPropagation(evt);',

+'			}',

+'',

+'			function evalCommandLine() {',

+'				var expr = $("command").value;',

+'				evalCommand(expr);',

+'				$("command").value = "";',

+'			}',

+'',

+'			function evalLastCommand() {',

+'				if (lastCommand != null) {',

+'					evalCommand(lastCommand);',

+'				}',

+'			}',

+'',

+'			var lastCommand = null;',

+'			var commandHistory = [];',

+'			var currentCommandIndex = 0;',

+'',

+'			function evalCommand(expr) {',

+'				if (appender) {',

+'					appender.evalCommandAndAppend(expr);',

+'				} else {',

+'					var prefix = ">>> " + expr + "\\r\\n";',

+'					try {',

+'						log("INFO", prefix + eval(expr));',

+'					} catch (ex) {',

+'						log("ERROR", prefix + "Error: " + getErrorMessage(ex));',

+'					}',

+'				}',

+'				// Update command history',

+'				if (expr != commandHistory[commandHistory.length - 1]) {',

+'					commandHistory.push(expr);',

+'					// Update the appender',

+'					if (appender) {',

+'						appender.storeCommandHistory(commandHistory);',

+'					}',

+'				}',

+'				currentCommandIndex = (expr == commandHistory[currentCommandIndex]) ? currentCommandIndex + 1 : commandHistory.length;',

+'				lastCommand = expr;',

+'			}',

+'			//]]>',

+'		</script>',

+'		<style type="text/css">',

+'			body {',

+'				background-color: white;',

+'				color: black;',

+'				padding: 0;',

+'				margin: 0;',

+'				font-family: tahoma, verdana, arial, helvetica, sans-serif;',

+'				overflow: hidden;',

+'			}',

+'',

+'			div#switchesContainer input {',

+'				margin-bottom: 0;',

+'			}',

+'',

+'			div.toolbar {',

+'				border-top: solid #ffffff 1px;',

+'				border-bottom: solid #aca899 1px;',

+'				background-color: #f1efe7;',

+'				padding: 3px 5px;',

+'				font-size: 68.75%;',

+'			}',

+'',

+'			div.toolbar, div#search input {',

+'				font-family: tahoma, verdana, arial, helvetica, sans-serif;',

+'			}',

+'',

+'			div.toolbar input.button {',

+'				padding: 0 5px;',

+'				font-size: 100%;',

+'			}',

+'',

+'			div.toolbar input.hidden {',

+'				display: none;',

+'			}',

+'',

+'			div#switches input#clearButton {',

+'				margin-left: 20px;',

+'			}',

+'',

+'			div#levels label {',

+'				font-weight: bold;',

+'			}',

+'',

+'			div#levels label, div#options label {',

+'				margin-right: 5px;',

+'			}',

+'',

+'			div#levels label#wrapLabel {',

+'				font-weight: normal;',

+'			}',

+'',

+'			div#search label {',

+'				margin-right: 10px;',

+'			}',

+'',

+'			div#search label.searchboxlabel {',

+'				margin-right: 0;',

+'			}',

+'',

+'			div#search input {',

+'				font-size: 100%;',

+'			}',

+'',

+'			div#search input.validregex {',

+'				color: green;',

+'			}',

+'',

+'			div#search input.invalidregex {',

+'				color: red;',

+'			}',

+'',

+'			div#search input.nomatches {',

+'				color: white;',

+'				background-color: #ff6666;',

+'			}',

+'',

+'			div#search input.nomatches {',

+'				color: white;',

+'				background-color: #ff6666;',

+'			}',

+'',

+'			div#searchNav {',

+'				display: none;',

+'			}',

+'',

+'			div#commandLine {',

+'				display: none;',

+'			}',

+'',

+'			div#commandLine input#command {',

+'				font-size: 100%;',

+'				font-family: Courier New, Courier;',

+'			}',

+'',

+'			div#commandLine input#evaluateButton {',

+'			}',

+'',

+'			*.greyedout {',

+'				color: gray !important;',

+'				border-color: gray !important;',

+'			}',

+'',

+'			*.greyedout *.alwaysenabled { color: black; }',

+'',

+'			*.unselectable {',

+'				-khtml-user-select: none;',

+'				-moz-user-select: none;',

+'				user-select: none;',

+'			}',

+'',

+'			div#log {',

+'				font-family: Courier New, Courier;',

+'				font-size: 75%;',

+'				width: 100%;',

+'				overflow: auto;',

+'				clear: both;',

+'				position: relative;',

+'			}',

+'',

+'			div.group {',

+'				border-color: #cccccc;',

+'				border-style: solid;',

+'				border-width: 1px 0 1px 1px;',

+'				overflow: visible;',

+'			}',

+'',

+'			div.oldIe div.group, div.oldIe div.group *, div.oldIe *.logentry {',

+'				height: 1%;',

+'			}',

+'',

+'			div.group div.groupheading span.expander {',

+'				border: solid black 1px;',

+'				font-family: Courier New, Courier;',

+'				font-size: 0.833em;',

+'				background-color: #eeeeee;',

+'				position: relative;',

+'				top: -1px;',

+'				color: black;',

+'				padding: 0 2px;',

+'				cursor: pointer;',

+'				cursor: hand;',

+'				height: 1%;',

+'			}',

+'',

+'			div.group div.groupcontent {',

+'				margin-left: 10px;',

+'				padding-bottom: 2px;',

+'				overflow: visible;',

+'			}',

+'',

+'			div.group div.expanded {',

+'				display: block;',

+'			}',

+'',

+'			div.group div.collapsed {',

+'				display: none;',

+'			}',

+'',

+'			*.logentry {',

+'				overflow: visible;',

+'				display: none;',

+'				white-space: pre;',

+'			}',

+'',

+'			span.pre {',

+'				white-space: pre;',

+'			}',

+'			',

+'			pre.unwrapped {',

+'				display: inline !important;',

+'			}',

+'',

+'			pre.unwrapped pre.pre, div.wrapped pre.pre {',

+'				display: inline;',

+'			}',

+'',

+'			div.wrapped pre.pre {',

+'				white-space: normal;',

+'			}',

+'',

+'			div.wrapped {',

+'				display: none;',

+'			}',

+'',

+'			body.searching *.logentry span.currentmatch {',

+'				color: white !important;',

+'				background-color: green !important;',

+'			}',

+'',

+'			body.searching div.searchhighlight *.logentry span.searchterm {',

+'				color: black;',

+'				background-color: yellow;',

+'			}',

+'',

+'			div.wrap *.logentry {',

+'				white-space: normal !important;',

+'				border-width: 0 0 1px 0;',

+'				border-color: #dddddd;',

+'				border-style: dotted;',

+'			}',

+'',

+'			div.wrap #log_wrapped, #log_unwrapped {',

+'				display: block;',

+'			}',

+'',

+'			div.wrap #log_unwrapped, #log_wrapped {',

+'				display: none;',

+'			}',

+'',

+'			div.wrap *.logentry span.pre {',

+'				overflow: visible;',

+'				white-space: normal;',

+'			}',

+'',

+'			div.wrap *.logentry pre.unwrapped {',

+'				display: none;',

+'			}',

+'',

+'			div.wrap *.logentry span.wrapped {',

+'				display: inline;',

+'			}',

+'',

+'			div.searchfilter *.searchnonmatch {',

+'				display: none !important;',

+'			}',

+'',

+'			div#log *.TRACE, label#label_TRACE {',

+'				color: #666666;',

+'			}',

+'',

+'			div#log *.DEBUG, label#label_DEBUG {',

+'				color: green;',

+'			}',

+'',

+'			div#log *.INFO, label#label_INFO {',

+'				color: #000099;',

+'			}',

+'',

+'			div#log *.WARN, label#label_WARN {',

+'				color: #999900;',

+'			}',

+'',

+'			div#log *.ERROR, label#label_ERROR {',

+'				color: red;',

+'			}',

+'',

+'			div#log *.FATAL, label#label_FATAL {',

+'				color: #660066;',

+'			}',

+'',

+'			div.TRACE#log *.TRACE,',

+'			div.DEBUG#log *.DEBUG,',

+'			div.INFO#log *.INFO,',

+'			div.WARN#log *.WARN,',

+'			div.ERROR#log *.ERROR,',

+'			div.FATAL#log *.FATAL {',

+'				display: block;',

+'			}',

+'',

+'			div#log div.separator {',

+'				background-color: #cccccc;',

+'				margin: 5px 0;',

+'				line-height: 1px;',

+'			}',

+'		</style>',

+'	</head>',

+'',

+'	<body id="body">',

+'		<div id="switchesContainer">',

+'			<div id="switches">',

+'				<div id="levels" class="toolbar">',

+'					Filters:',

+'					<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>',

+'					<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>',

+'					<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>',

+'					<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>',

+'					<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>',

+'					<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>',

+'					<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>',

+'				</div>',

+'				<div id="search" class="toolbar">',

+'					<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />',

+'					<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />',

+'					<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>',

+'					<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>',

+'					<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>',

+'					<div id="searchNav">',

+'						<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />',

+'						<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />',

+'						<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>',

+'						<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>',

+'					</div>',

+'				</div>',

+'				<div id="options" class="toolbar">',

+'					Options:',

+'					<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>',

+'					<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>',

+'					<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>',

+'					<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>',

+'					<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />',

+'					<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />',

+'					<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />',

+'				</div>',

+'			</div>',

+'		</div>',

+'		<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>',

+'		<div id="commandLine" class="toolbar">',

+'			<div id="commandLineContainer">',

+'				<input type="text" id="command" title="Enter a JavaScript command here and hit return or press \'Evaluate\'" />',

+'				<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />',

+'			</div>',

+'		</div>',

+'	</body>',

+'</html>',

+''

+];

+		};

+

+		var defaultCommandLineFunctions = [];

+

+		ConsoleAppender = function() {};

+

+		var consoleAppenderIdCounter = 1;

+		ConsoleAppender.prototype = new Appender();

+

+		ConsoleAppender.prototype.create = function(inPage, container,

+				lazyInit, initiallyMinimized, useDocumentWrite, width, height, focusConsoleWindow) {

+			var appender = this;

+

+			// Common properties

+			var initialized = false;

+			var consoleWindowCreated = false;

+			var consoleWindowLoaded = false;

+			var consoleClosed = false;

+

+			var queuedLoggingEvents = [];

+			var isSupported = true;

+			var consoleAppenderId = consoleAppenderIdCounter++;

+

+			// Local variables

+			initiallyMinimized = extractBooleanFromParam(initiallyMinimized, this.defaults.initiallyMinimized);

+			lazyInit = extractBooleanFromParam(lazyInit, this.defaults.lazyInit);

+			useDocumentWrite = extractBooleanFromParam(useDocumentWrite, this.defaults.useDocumentWrite);

+			var newestMessageAtTop = this.defaults.newestMessageAtTop;

+			var scrollToLatestMessage = this.defaults.scrollToLatestMessage;

+			width = width ? width : this.defaults.width;

+			height = height ? height : this.defaults.height;

+			var maxMessages = this.defaults.maxMessages;

+			var showCommandLine = this.defaults.showCommandLine;

+			var commandLineObjectExpansionDepth = this.defaults.commandLineObjectExpansionDepth;

+			var showHideButton = this.defaults.showHideButton;

+            var showCloseButton = this.defaults.showCloseButton;

+            var showLogEntryDeleteButtons = this.defaults.showLogEntryDeleteButtons;

+

+			this.setLayout(this.defaults.layout);

+

+			// Functions whose implementations vary between subclasses

+			var init, createWindow, safeToAppend, getConsoleWindow, open;

+

+			// Configuration methods. The function scope is used to prevent

+			// direct alteration to the appender configuration properties.

+			var appenderName = inPage ? "InPageAppender" : "PopUpAppender";

+			var checkCanConfigure = function(configOptionName) {

+				if (consoleWindowCreated) {

+					handleError(appenderName + ": configuration option '" + configOptionName + "' may not be set after the appender has been initialized");

+					return false;

+				}

+				return true;

+			};

+

+			var consoleWindowExists = function() {

+				return (consoleWindowLoaded && isSupported && !consoleClosed);

+			};

+

+			this.isNewestMessageAtTop = function() { return newestMessageAtTop; };

+			this.setNewestMessageAtTop = function(newestMessageAtTopParam) {

+				newestMessageAtTop = bool(newestMessageAtTopParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setNewestAtTop(newestMessageAtTop);

+				}

+			};

+

+			this.isScrollToLatestMessage = function() { return scrollToLatestMessage; };

+			this.setScrollToLatestMessage = function(scrollToLatestMessageParam) {

+				scrollToLatestMessage = bool(scrollToLatestMessageParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setScrollToLatest(scrollToLatestMessage);

+				}

+			};

+

+			this.getWidth = function() { return width; };

+			this.setWidth = function(widthParam) {

+				if (checkCanConfigure("width")) {

+					width = extractStringFromParam(widthParam, width);

+				}

+			};

+

+			this.getHeight = function() { return height; };

+			this.setHeight = function(heightParam) {

+				if (checkCanConfigure("height")) {

+					height = extractStringFromParam(heightParam, height);

+				}

+			};

+

+			this.getMaxMessages = function() { return maxMessages; };

+			this.setMaxMessages = function(maxMessagesParam) {

+				maxMessages = extractIntFromParam(maxMessagesParam, maxMessages);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setMaxMessages(maxMessages);

+				}

+			};

+

+			this.isShowCommandLine = function() { return showCommandLine; };

+			this.setShowCommandLine = function(showCommandLineParam) {

+				showCommandLine = bool(showCommandLineParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setShowCommandLine(showCommandLine);

+				}

+			};

+

+			this.isShowHideButton = function() { return showHideButton; };

+			this.setShowHideButton = function(showHideButtonParam) {

+				showHideButton = bool(showHideButtonParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setShowHideButton(showHideButton);

+				}

+			};

+

+			this.isShowCloseButton = function() { return showCloseButton; };

+			this.setShowCloseButton = function(showCloseButtonParam) {

+				showCloseButton = bool(showCloseButtonParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setShowCloseButton(showCloseButton);

+				}

+			};

+

+			this.getCommandLineObjectExpansionDepth = function() { return commandLineObjectExpansionDepth; };

+			this.setCommandLineObjectExpansionDepth = function(commandLineObjectExpansionDepthParam) {

+				commandLineObjectExpansionDepth = extractIntFromParam(commandLineObjectExpansionDepthParam, commandLineObjectExpansionDepth);

+			};

+

+			var minimized = initiallyMinimized;

+			this.isInitiallyMinimized = function() { return initiallyMinimized; };

+			this.setInitiallyMinimized = function(initiallyMinimizedParam) {

+				if (checkCanConfigure("initiallyMinimized")) {

+					initiallyMinimized = bool(initiallyMinimizedParam);

+					minimized = initiallyMinimized;

+				}

+			};

+

+			this.isUseDocumentWrite = function() { return useDocumentWrite; };

+			this.setUseDocumentWrite = function(useDocumentWriteParam) {

+				if (checkCanConfigure("useDocumentWrite")) {

+					useDocumentWrite = bool(useDocumentWriteParam);

+				}

+			};

+

+			// Common methods

+			function QueuedLoggingEvent(loggingEvent, formattedMessage) {

+				this.loggingEvent = loggingEvent;

+				this.levelName = loggingEvent.level.name;

+				this.formattedMessage = formattedMessage;

+			}

+

+			QueuedLoggingEvent.prototype.append = function() {

+				getConsoleWindow().log(this.levelName, this.formattedMessage);

+			};

+

+			function QueuedGroup(name, initiallyExpanded) {

+				this.name = name;

+				this.initiallyExpanded = initiallyExpanded;

+			}

+

+			QueuedGroup.prototype.append = function() {

+				getConsoleWindow().group(this.name, this.initiallyExpanded);

+			};

+

+			function QueuedGroupEnd() {}

+

+			QueuedGroupEnd.prototype.append = function() {

+				getConsoleWindow().groupEnd();

+			};

+

+			var checkAndAppend = function() {

+				// Next line forces a check of whether the window has been closed

+				safeToAppend();

+				if (!initialized) {

+					init();

+				} else if (consoleClosed && reopenWhenClosed) {

+					createWindow();

+				}

+				if (safeToAppend()) {

+					appendQueuedLoggingEvents();

+				}

+			};

+

+			this.append = function(loggingEvent) {

+				if (isSupported) {

+					// Format the message

+					var formattedMessage = appender.getLayout().format(loggingEvent);

+					if (this.getLayout().ignoresThrowable()) {

+						formattedMessage += loggingEvent.getThrowableStrRep();

+					}

+					queuedLoggingEvents.push(new QueuedLoggingEvent(loggingEvent, formattedMessage));

+					checkAndAppend();

+				}

+			};

+

+            this.group = function(name, initiallyExpanded) {

+				if (isSupported) {

+					queuedLoggingEvents.push(new QueuedGroup(name, initiallyExpanded));

+					checkAndAppend();

+				}

+			};

+

+            this.groupEnd = function() {

+				if (isSupported) {

+					queuedLoggingEvents.push(new QueuedGroupEnd());

+					checkAndAppend();

+				}

+			};

+

+			var appendQueuedLoggingEvents = function() {

+				var currentLoggingEvent;

+				while (queuedLoggingEvents.length > 0) {

+					queuedLoggingEvents.shift().append();

+				}

+				if (focusConsoleWindow) {

+					getConsoleWindow().focus();

+				}

+			};

+

+			this.setAddedToLogger = function(logger) {

+				this.loggers.push(logger);

+				if (enabled && !lazyInit) {

+					init();

+				}

+			};

+

+			this.clear = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().clearLog();

+				}

+				queuedLoggingEvents.length = 0;

+			};

+

+			this.focus = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().focus();

+				}

+			};

+

+			this.focusCommandLine = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().focusCommandLine();

+				}

+			};

+

+			this.focusSearch = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().focusSearch();

+				}

+			};

+

+			var commandWindow = window;

+

+			this.getCommandWindow = function() { return commandWindow; };

+			this.setCommandWindow = function(commandWindowParam) {

+				commandWindow = commandWindowParam;

+			};

+

+			this.executeLastCommand = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().evalLastCommand();

+				}

+			};

+

+			var commandLayout = new PatternLayout("%m");

+			this.getCommandLayout = function() { return commandLayout; };

+			this.setCommandLayout = function(commandLayoutParam) {

+				commandLayout = commandLayoutParam;

+			};

+

+			this.evalCommandAndAppend = function(expr) {

+				var commandReturnValue = { appendResult: true, isError: false };

+				var commandOutput = "";

+				// Evaluate the command

+				try {

+					var result, i;

+					// The next three lines constitute a workaround for IE. Bizarrely, iframes seem to have no

+					// eval method on the window object initially, but once execScript has been called on

+					// it once then the eval method magically appears. See http://www.thismuchiknow.co.uk/?p=25

+					if (!commandWindow.eval && commandWindow.execScript) {

+						commandWindow.execScript("null");

+					}

+

+					var commandLineFunctionsHash = {};

+					for (i = 0, len = commandLineFunctions.length; i < len; i++) {

+						commandLineFunctionsHash[commandLineFunctions[i][0]] = commandLineFunctions[i][1];

+					}

+

+					// Keep an array of variables that are being changed in the command window so that they

+					// can be restored to their original values afterwards

+					var objectsToRestore = [];

+					var addObjectToRestore = function(name) {

+						objectsToRestore.push([name, commandWindow[name]]);

+					};

+

+					addObjectToRestore("appender");

+					commandWindow.appender = appender;

+

+					addObjectToRestore("commandReturnValue");

+					commandWindow.commandReturnValue = commandReturnValue;

+

+					addObjectToRestore("commandLineFunctionsHash");

+					commandWindow.commandLineFunctionsHash = commandLineFunctionsHash;

+

+					var addFunctionToWindow = function(name) {

+						addObjectToRestore(name);

+						commandWindow[name] = function() {

+							return this.commandLineFunctionsHash[name](appender, arguments, commandReturnValue);

+						};

+					};

+

+					for (i = 0, len = commandLineFunctions.length; i < len; i++) {

+						addFunctionToWindow(commandLineFunctions[i][0]);

+					}

+

+					// Another bizarre workaround to get IE to eval in the global scope

+					if (commandWindow === window && commandWindow.execScript) {

+						addObjectToRestore("evalExpr");

+						addObjectToRestore("result");

+						window.evalExpr = expr;

+						commandWindow.execScript("window.result=eval(window.evalExpr);");

+						result = window.result;

+ 					} else {

+ 						result = commandWindow.eval(expr);

+ 					}

+					commandOutput = isUndefined(result) ? result : formatObjectExpansion(result, commandLineObjectExpansionDepth);

+

+					// Restore variables in the command window to their original state

+					for (i = 0, len = objectsToRestore.length; i < len; i++) {

+						commandWindow[objectsToRestore[i][0]] = objectsToRestore[i][1];

+					}

+				} catch (ex) {

+					commandOutput = "Error evaluating command: " + getExceptionStringRep(ex);

+					commandReturnValue.isError = true;

+				}

+				// Append command output

+				if (commandReturnValue.appendResult) {

+					var message = ">>> " + expr;

+					if (!isUndefined(commandOutput)) {

+						message += newLine + commandOutput;

+					}

+					var level = commandReturnValue.isError ? Level.ERROR : Level.INFO;

+					var loggingEvent = new LoggingEvent(null, new Date(), level, [message], null);

+					var mainLayout = this.getLayout();

+					this.setLayout(commandLayout);

+					this.append(loggingEvent);

+					this.setLayout(mainLayout);

+				}

+			};

+

+			var commandLineFunctions = defaultCommandLineFunctions.concat([]);

+

+			this.addCommandLineFunction = function(functionName, commandLineFunction) {

+				commandLineFunctions.push([functionName, commandLineFunction]);

+			};

+

+			var commandHistoryCookieName = "log4javascriptCommandHistory";

+			this.storeCommandHistory = function(commandHistory) {

+				setCookie(commandHistoryCookieName, commandHistory.join(","));

+			};

+

+			var writeHtml = function(doc) {

+				var lines = getConsoleHtmlLines();

+				doc.open();

+				for (var i = 0, len = lines.length; i < len; i++) {

+					doc.writeln(lines[i]);

+				}

+				doc.close();

+			};

+

+			// Set up event listeners

+			this.setEventTypes(["load", "unload"]);

+

+			var consoleWindowLoadHandler = function() {

+				var win = getConsoleWindow();

+				win.setAppender(appender);

+				win.setNewestAtTop(newestMessageAtTop);

+				win.setScrollToLatest(scrollToLatestMessage);

+				win.setMaxMessages(maxMessages);

+				win.setShowCommandLine(showCommandLine);

+				win.setShowHideButton(showHideButton);

+				win.setShowCloseButton(showCloseButton);

+				win.setMainWindow(window);

+

+				// Restore command history stored in cookie

+				var storedValue = getCookie(commandHistoryCookieName);

+				if (storedValue) {

+					win.commandHistory = storedValue.split(",");

+					win.currentCommandIndex = win.commandHistory.length;

+				}

+

+				appender.dispatchEvent("load", { "win" : win });

+			};

+

+			this.unload = function() {

+				logLog.debug("unload " + this + ", caller: " + this.unload.caller);

+				if (!consoleClosed) {

+					logLog.debug("really doing unload " + this);

+					consoleClosed = true;

+					consoleWindowLoaded = false;

+					consoleWindowCreated = false;

+					appender.dispatchEvent("unload", {});

+				}

+			};

+

+			var pollConsoleWindow = function(windowTest, interval, successCallback, errorMessage) {

+				function doPoll() {

+					try {

+						// Test if the console has been closed while polling

+						if (consoleClosed) {

+							clearInterval(poll);

+						}

+						if (windowTest(getConsoleWindow())) {

+							clearInterval(poll);

+							successCallback();

+						}

+					} catch (ex) {

+						clearInterval(poll);

+						isSupported = false;

+						handleError(errorMessage, ex);

+					}

+				}

+

+				// Poll the pop-up since the onload event is not reliable

+				var poll = setInterval(doPoll, interval);

+			};

+

+			var getConsoleUrl = function() {

+				var documentDomainSet = (document.domain != location.hostname);

+				return useDocumentWrite ? "" : getBaseUrl() + "console_uncompressed.html" +

+											   (documentDomainSet ? "?log4javascript_domain=" + escape(document.domain) : "");

+			};

+

+			// Define methods and properties that vary between subclasses

+			if (inPage) {

+				// InPageAppender

+

+				var containerElement = null;

+

+				// Configuration methods. The function scope is used to prevent

+				// direct alteration to the appender configuration properties.

+				var cssProperties = [];

+				this.addCssProperty = function(name, value) {

+					if (checkCanConfigure("cssProperties")) {

+						cssProperties.push([name, value]);

+					}

+				};

+

+				// Define useful variables

+				var windowCreationStarted = false;

+				var iframeContainerDiv;

+				var iframeId = uniqueId + "_InPageAppender_" + consoleAppenderId;

+

+				this.hide = function() {

+					if (initialized && consoleWindowCreated) {

+						if (consoleWindowExists()) {

+							getConsoleWindow().$("command").blur();

+						}

+						iframeContainerDiv.style.display = "none";

+						minimized = true;

+					}

+				};

+

+				this.show = function() {

+					if (initialized) {

+						if (consoleWindowCreated) {

+							iframeContainerDiv.style.display = "block";

+							this.setShowCommandLine(showCommandLine); // Force IE to update

+							minimized = false;

+						} else if (!windowCreationStarted) {

+							createWindow(true);

+						}

+					}

+				};

+

+				this.isVisible = function() {

+					return !minimized && !consoleClosed;

+				};

+

+				this.close = function(fromButton) {

+					if (!consoleClosed && (!fromButton || confirm("This will permanently remove the console from the page. No more messages will be logged. Do you wish to continue?"))) {

+						iframeContainerDiv.parentNode.removeChild(iframeContainerDiv);

+						this.unload();

+					}

+				};

+

+				// Create open, init, getConsoleWindow and safeToAppend functions

+				open = function() {

+					var initErrorMessage = "InPageAppender.open: unable to create console iframe";

+

+					function finalInit() {

+						try {

+							if (!initiallyMinimized) {

+								appender.show();

+							}

+							consoleWindowLoadHandler();

+							consoleWindowLoaded = true;

+							appendQueuedLoggingEvents();

+						} catch (ex) {

+							isSupported = false;

+							handleError(initErrorMessage, ex);

+						}

+					}

+

+					function writeToDocument() {

+						try {

+							var windowTest = function(win) { return isLoaded(win); };

+							if (useDocumentWrite) {

+								writeHtml(getConsoleWindow().document);

+							}

+							if (windowTest(getConsoleWindow())) {

+								finalInit();

+							} else {

+								pollConsoleWindow(windowTest, 100, finalInit, initErrorMessage);

+							}

+						} catch (ex) {

+							isSupported = false;

+							handleError(initErrorMessage, ex);

+						}

+					}

+

+					minimized = false;

+					iframeContainerDiv = containerElement.appendChild(document.createElement("div"));

+

+					iframeContainerDiv.style.width = width;

+					iframeContainerDiv.style.height = height;

+					iframeContainerDiv.style.border = "solid gray 1px";

+

+					for (var i = 0, len = cssProperties.length; i < len; i++) {

+						iframeContainerDiv.style[cssProperties[i][0]] = cssProperties[i][1];

+					}

+

+					var iframeSrc = useDocumentWrite ? "" : " src='" + getConsoleUrl() + "'";

+

+					// Adding an iframe using the DOM would be preferable, but it doesn't work

+					// in IE5 on Windows, or in Konqueror prior to version 3.5 - in Konqueror

+					// it creates the iframe fine but I haven't been able to find a way to obtain

+					// the iframe's window object

+					iframeContainerDiv.innerHTML = "<iframe id='" + iframeId + "' name='" + iframeId +

+						"' width='100%' height='100%' frameborder='0'" + iframeSrc +

+						" scrolling='no'></iframe>";

+					consoleClosed = false;

+

+					// Write the console HTML to the iframe

+					var iframeDocumentExistsTest = function(win) {

+						try {

+							return bool(win) && bool(win.document);

+						} catch (ex) {

+							return false;

+						}

+					};

+					if (iframeDocumentExistsTest(getConsoleWindow())) {

+						writeToDocument();

+					} else {

+						pollConsoleWindow(iframeDocumentExistsTest, 100, writeToDocument, initErrorMessage);

+					}

+					consoleWindowCreated = true;

+				};

+

+				createWindow = function(show) {

+					if (show || !initiallyMinimized) {

+						var pageLoadHandler = function() {

+							if (!container) {

+								// Set up default container element

+								containerElement = document.createElement("div");

+								containerElement.style.position = "fixed";

+								containerElement.style.left = "0";

+								containerElement.style.right = "0";

+								containerElement.style.bottom = "0";

+								document.body.appendChild(containerElement);

+								appender.addCssProperty("borderWidth", "1px 0 0 0");

+								appender.addCssProperty("zIndex", 1000000); // Can't find anything authoritative that says how big z-index can be

+								open();

+							} else {

+								try {

+									var el = document.getElementById(container);

+									if (el.nodeType == 1) {

+										containerElement = el;

+									}

+									open();

+								} catch (ex) {

+									handleError("InPageAppender.init: invalid container element '" + container + "' supplied", ex);

+								}

+							}

+						};

+

+						// Test the type of the container supplied. First, check if it's an element

+						if (pageLoaded && container && container.appendChild) {

+							containerElement = container;

+							open();

+						} else if (pageLoaded) {

+							pageLoadHandler();

+						} else {

+							log4javascript.addEventListener("load", pageLoadHandler);

+						}

+						windowCreationStarted = true;

+					}

+				};

+

+				init = function() {

+					createWindow();

+					initialized = true;

+				};

+

+				getConsoleWindow = function() {

+					var iframe = window.frames[iframeId];

+					if (iframe) {

+						return iframe;

+					}

+				};

+

+				safeToAppend = function() {

+					if (isSupported && !consoleClosed) {

+						if (consoleWindowCreated && !consoleWindowLoaded && getConsoleWindow() && isLoaded(getConsoleWindow())) {

+							consoleWindowLoaded = true;

+						}

+						return consoleWindowLoaded;

+					}

+					return false;

+				};

+			} else {

+				// PopUpAppender

+

+				// Extract params

+				var useOldPopUp = appender.defaults.useOldPopUp;

+				var complainAboutPopUpBlocking = appender.defaults.complainAboutPopUpBlocking;

+				var reopenWhenClosed = this.defaults.reopenWhenClosed;

+

+				// Configuration methods. The function scope is used to prevent

+				// direct alteration to the appender configuration properties.

+				this.isUseOldPopUp = function() { return useOldPopUp; };

+				this.setUseOldPopUp = function(useOldPopUpParam) {

+					if (checkCanConfigure("useOldPopUp")) {

+						useOldPopUp = bool(useOldPopUpParam);

+					}

+				};

+

+				this.isComplainAboutPopUpBlocking = function() { return complainAboutPopUpBlocking; };

+				this.setComplainAboutPopUpBlocking = function(complainAboutPopUpBlockingParam) {

+					if (checkCanConfigure("complainAboutPopUpBlocking")) {

+						complainAboutPopUpBlocking = bool(complainAboutPopUpBlockingParam);

+					}

+				};

+

+				this.isFocusPopUp = function() { return focusConsoleWindow; };

+				this.setFocusPopUp = function(focusPopUpParam) {

+					// This property can be safely altered after logging has started

+					focusConsoleWindow = bool(focusPopUpParam);

+				};

+

+				this.isReopenWhenClosed = function() { return reopenWhenClosed; };

+				this.setReopenWhenClosed = function(reopenWhenClosedParam) {

+					// This property can be safely altered after logging has started

+					reopenWhenClosed = bool(reopenWhenClosedParam);

+				};

+

+				this.close = function() {

+					logLog.debug("close " + this);

+					try {

+						popUp.close();

+						this.unload();

+					} catch (ex) {

+						// Do nothing

+					}

+				};

+

+				this.hide = function() {

+					logLog.debug("hide " + this);

+					if (consoleWindowExists()) {

+						this.close();

+					}

+				};

+

+				this.show = function() {

+					logLog.debug("show " + this);

+					if (!consoleWindowCreated) {

+						open();

+					}

+				};

+

+				this.isVisible = function() {

+					return safeToAppend();

+				};

+

+				// Define useful variables

+				var popUp;

+

+				// Create open, init, getConsoleWindow and safeToAppend functions

+				open = function() {

+					var windowProperties = "width=" + width + ",height=" + height + ",status,resizable";

+					var frameInfo = "";

+					try {

+						var frameEl = window.frameElement;

+						if (frameEl) {

+							frameInfo = "_" + frameEl.tagName + "_" + (frameEl.name || frameEl.id || "");

+						}

+					} catch (e) {

+						frameInfo = "_inaccessibleParentFrame";

+					}

+					var windowName = "PopUp_" + location.host.replace(/[^a-z0-9]/gi, "_") + "_" + consoleAppenderId + frameInfo;

+					if (!useOldPopUp || !useDocumentWrite) {

+						// Ensure a previous window isn't used by using a unique name

+						windowName = windowName + "_" + uniqueId;

+					}

+

+					var checkPopUpClosed = function(win) {

+						if (consoleClosed) {

+							return true;

+						} else {

+							try {

+								return bool(win) && win.closed;

+							} catch(ex) {}

+						}

+						return false;

+					};

+

+					var popUpClosedCallback = function() {

+						if (!consoleClosed) {

+							appender.unload();

+						}

+					};

+

+					function finalInit() {

+						getConsoleWindow().setCloseIfOpenerCloses(!useOldPopUp || !useDocumentWrite);

+						consoleWindowLoadHandler();

+						consoleWindowLoaded = true;

+						appendQueuedLoggingEvents();

+						pollConsoleWindow(checkPopUpClosed, 500, popUpClosedCallback,

+								"PopUpAppender.checkPopUpClosed: error checking pop-up window");

+					}

+

+					try {

+						popUp = window.open(getConsoleUrl(), windowName, windowProperties);

+						consoleClosed = false;

+						consoleWindowCreated = true;

+						if (popUp && popUp.document) {

+							if (useDocumentWrite && useOldPopUp && isLoaded(popUp)) {

+								popUp.mainPageReloaded();

+								finalInit();

+							} else {

+								if (useDocumentWrite) {

+									writeHtml(popUp.document);

+								}

+								// Check if the pop-up window object is available

+								var popUpLoadedTest = function(win) { return bool(win) && isLoaded(win); };

+								if (isLoaded(popUp)) {

+									finalInit();

+								} else {

+									pollConsoleWindow(popUpLoadedTest, 100, finalInit,

+											"PopUpAppender.init: unable to create console window");

+								}

+							}

+						} else {

+							isSupported = false;

+							logLog.warn("PopUpAppender.init: pop-ups blocked, please unblock to use PopUpAppender");

+							if (complainAboutPopUpBlocking) {

+								handleError("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");

+							}

+						}

+					} catch (ex) {

+						handleError("PopUpAppender.init: error creating pop-up", ex);

+					}

+				};

+

+				createWindow = function() {

+					if (!initiallyMinimized) {

+						open();

+					}

+				};

+

+				init = function() {

+					createWindow();

+					initialized = true;

+				};

+

+				getConsoleWindow = function() {

+					return popUp;

+				};

+

+				safeToAppend = function() {

+					if (isSupported && !isUndefined(popUp) && !consoleClosed) {

+						if (popUp.closed ||

+								(consoleWindowLoaded && isUndefined(popUp.closed))) { // Extra check for Opera

+							appender.unload();

+							logLog.debug("PopUpAppender: pop-up closed");

+							return false;

+						}

+						if (!consoleWindowLoaded && isLoaded(popUp)) {

+							consoleWindowLoaded = true;

+						}

+					}

+					return isSupported && consoleWindowLoaded && !consoleClosed;

+				};

+			}

+

+			// Expose getConsoleWindow so that automated tests can check the DOM

+			this.getConsoleWindow = getConsoleWindow;

+		};

+

+		ConsoleAppender.addGlobalCommandLineFunction = function(functionName, commandLineFunction) {

+			defaultCommandLineFunctions.push([functionName, commandLineFunction]);

+		};

+

+		/* ------------------------------------------------------------------ */

+

+		function PopUpAppender(lazyInit, initiallyMinimized, useDocumentWrite,

+							   width, height) {

+			this.create(false, null, lazyInit, initiallyMinimized,

+					useDocumentWrite, width, height, this.defaults.focusPopUp);

+		}

+

+		PopUpAppender.prototype = new ConsoleAppender();

+

+		PopUpAppender.prototype.defaults = {

+			layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),

+			initiallyMinimized: false,

+			focusPopUp: false,

+			lazyInit: true,

+			useOldPopUp: true,

+			complainAboutPopUpBlocking: true,

+			newestMessageAtTop: false,

+			scrollToLatestMessage: true,

+			width: "600",

+			height: "400",

+			reopenWhenClosed: false,

+			maxMessages: null,

+			showCommandLine: true,

+			commandLineObjectExpansionDepth: 1,

+			showHideButton: false,

+			showCloseButton: true,

+            showLogEntryDeleteButtons: true,

+            useDocumentWrite: true

+		};

+

+		PopUpAppender.prototype.toString = function() {

+			return "PopUpAppender";

+		};

+

+		log4javascript.PopUpAppender = PopUpAppender;

+

+		/* ------------------------------------------------------------------ */

+

+		function InPageAppender(container, lazyInit, initiallyMinimized,

+								useDocumentWrite, width, height) {

+			this.create(true, container, lazyInit, initiallyMinimized,

+					useDocumentWrite, width, height, false);

+		}

+

+		InPageAppender.prototype = new ConsoleAppender();

+

+		InPageAppender.prototype.defaults = {

+			layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),

+			initiallyMinimized: false,

+			lazyInit: true,

+			newestMessageAtTop: false,

+			scrollToLatestMessage: true,

+			width: "100%",

+			height: "220px",

+			maxMessages: null,

+			showCommandLine: true,

+			commandLineObjectExpansionDepth: 1,

+			showHideButton: false,

+			showCloseButton: false,

+            showLogEntryDeleteButtons: true,

+            useDocumentWrite: true

+		};

+

+		InPageAppender.prototype.toString = function() {

+			return "InPageAppender";

+		};

+

+		log4javascript.InPageAppender = InPageAppender;

+

+		// Next line for backwards compatibility

+		log4javascript.InlineAppender = InPageAppender;

+	})();

+	/* ---------------------------------------------------------------------- */

+	// Console extension functions

+

+	function padWithSpaces(str, len) {

+		if (str.length < len) {

+			var spaces = [];

+			var numberOfSpaces = Math.max(0, len - str.length);

+			for (var i = 0; i < numberOfSpaces; i++) {

+				spaces[i] = " ";

+			}

+			str += spaces.join("");

+		}

+		return str;

+	}

+

+	(function() {

+		function dir(obj) {

+			var maxLen = 0;

+			// Obtain the length of the longest property name

+			for (var p in obj) {

+				maxLen = Math.max(toStr(p).length, maxLen);

+			}

+			// Create the nicely formatted property list

+			var propList = [];

+			for (p in obj) {

+				var propNameStr = "  " + padWithSpaces(toStr(p), maxLen + 2);

+				var propVal;

+				try {

+					propVal = splitIntoLines(toStr(obj[p])).join(padWithSpaces(newLine, maxLen + 6));

+				} catch (ex) {

+					propVal = "[Error obtaining property. Details: " + getExceptionMessage(ex) + "]";

+				}

+				propList.push(propNameStr + propVal);

+			}

+			return propList.join(newLine);

+		}

+

+		var nodeTypes = {

+			ELEMENT_NODE: 1,

+			ATTRIBUTE_NODE: 2,

+			TEXT_NODE: 3,

+			CDATA_SECTION_NODE: 4,

+			ENTITY_REFERENCE_NODE: 5,

+			ENTITY_NODE: 6,

+			PROCESSING_INSTRUCTION_NODE: 7,

+			COMMENT_NODE: 8,

+			DOCUMENT_NODE: 9,

+			DOCUMENT_TYPE_NODE: 10,

+			DOCUMENT_FRAGMENT_NODE: 11,

+			NOTATION_NODE: 12

+		};

+

+		var preFormattedElements = ["script", "pre"];

+

+		// This should be the definitive list, as specified by the XHTML 1.0 Transitional DTD

+		var emptyElements = ["br", "img", "hr", "param", "link", "area", "input", "col", "base", "meta"];

+		var indentationUnit = "  ";

+

+		// Create and return an XHTML string from the node specified

+		function getXhtml(rootNode, includeRootNode, indentation, startNewLine, preformatted) {

+			includeRootNode = (typeof includeRootNode == "undefined") ? true : !!includeRootNode;

+			if (typeof indentation != "string") {

+				indentation = "";

+			}

+			startNewLine = !!startNewLine;

+			preformatted = !!preformatted;

+			var xhtml;

+

+			function isWhitespace(node) {

+				return ((node.nodeType == nodeTypes.TEXT_NODE) && /^[ \t\r\n]*$/.test(node.nodeValue));

+			}

+

+			function fixAttributeValue(attrValue) {

+				return attrValue.toString().replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/"/g, "&quot;");

+			}

+

+			function getStyleAttributeValue(el) {

+				var stylePairs = el.style.cssText.split(";");

+				var styleValue = "";

+				var isFirst = true;

+				for (var j = 0, len = stylePairs.length; j < len; j++) {

+					var nameValueBits = stylePairs[j].split(":");

+					var props = [];

+					if (!/^\s*$/.test(nameValueBits[0])) {

+						props.push(trim(nameValueBits[0]).toLowerCase() + ":" + trim(nameValueBits[1]));

+					}

+					styleValue = props.join(";");

+				}

+				return styleValue;

+			}

+

+			function getNamespace(el) {

+				if (el.prefix) {

+					return el.prefix;

+				} else if (el.outerHTML) {

+					var regex = new RegExp("<([^:]+):" + el.tagName + "[^>]*>", "i");

+					if (regex.test(el.outerHTML)) {

+						return RegExp.$1.toLowerCase();

+					}

+				}

+                return "";

+			}

+

+			var lt = "<";

+			var gt = ">";

+

+			if (includeRootNode && rootNode.nodeType != nodeTypes.DOCUMENT_FRAGMENT_NODE) {

+				switch (rootNode.nodeType) {

+					case nodeTypes.ELEMENT_NODE:

+						var tagName = rootNode.tagName.toLowerCase();

+						xhtml = startNewLine ? newLine + indentation : "";

+						xhtml += lt;

+						// Allow for namespaces, where present

+						var prefix = getNamespace(rootNode);

+						var hasPrefix = !!prefix;

+						if (hasPrefix) {

+							xhtml += prefix + ":";

+						}

+						xhtml += tagName;

+						for (i = 0, len = rootNode.attributes.length; i < len; i++) {

+							var currentAttr = rootNode.attributes[i];

+							// Check the attribute is valid.

+							if (!	currentAttr.specified ||

+									currentAttr.nodeValue === null ||

+									currentAttr.nodeName.toLowerCase() === "style" ||

+									typeof currentAttr.nodeValue !== "string" ||

+									currentAttr.nodeName.indexOf("_moz") === 0) {

+								continue;

+							}

+							xhtml += " " + currentAttr.nodeName.toLowerCase() + "=\"";

+							xhtml += fixAttributeValue(currentAttr.nodeValue);

+							xhtml += "\"";

+						}

+						// Style needs to be done separately as it is not reported as an

+						// attribute in IE

+						if (rootNode.style.cssText) {

+							var styleValue = getStyleAttributeValue(rootNode);

+							if (styleValue !== "") {

+								xhtml += " style=\"" + getStyleAttributeValue(rootNode) + "\"";

+							}

+						}

+						if (array_contains(emptyElements, tagName) ||

+								(hasPrefix && !rootNode.hasChildNodes())) {

+							xhtml += "/" + gt;

+						} else {

+							xhtml += gt;

+							// Add output for childNodes collection (which doesn't include attribute nodes)

+							var childStartNewLine = !(rootNode.childNodes.length === 1 &&

+								rootNode.childNodes[0].nodeType === nodeTypes.TEXT_NODE);

+							var childPreformatted = array_contains(preFormattedElements, tagName);

+							for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {

+								xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit,

+									childStartNewLine, childPreformatted);

+							}

+							// Add the end tag

+							var endTag = lt + "/" + tagName + gt;

+							xhtml += childStartNewLine ? newLine + indentation + endTag : endTag;

+						}

+						return xhtml;

+					case nodeTypes.TEXT_NODE:

+						if (isWhitespace(rootNode)) {

+							xhtml = "";

+						} else {

+							if (preformatted) {

+								xhtml = rootNode.nodeValue;

+							} else {

+								// Trim whitespace from each line of the text node

+								var lines = splitIntoLines(trim(rootNode.nodeValue));

+								var trimmedLines = [];

+								for (var i = 0, len = lines.length; i < len; i++) {

+									trimmedLines[i] = trim(lines[i]);

+								}

+								xhtml = trimmedLines.join(newLine + indentation);

+							}

+							if (startNewLine) {

+								xhtml = newLine + indentation + xhtml;

+							}

+						}

+						return xhtml;

+					case nodeTypes.CDATA_SECTION_NODE:

+						return "<![CDA" + "TA[" + rootNode.nodeValue + "]" + "]>" + newLine;

+					case nodeTypes.DOCUMENT_NODE:

+						xhtml = "";

+						// Add output for childNodes collection (which doesn't include attribute nodes)

+						for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {

+							xhtml += getXhtml(rootNode.childNodes[i], true, indentation);

+						}

+						return xhtml;

+					default:

+						return "";

+				}

+			} else {

+				xhtml = "";

+				// Add output for childNodes collection (which doesn't include attribute nodes)

+				for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {

+					xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit);

+				}

+				return xhtml;

+			}

+		}

+

+		function createCommandLineFunctions() {

+			ConsoleAppender.addGlobalCommandLineFunction("$", function(appender, args, returnValue) {

+				return document.getElementById(args[0]);

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("dir", function(appender, args, returnValue) {

+				var lines = [];

+				for (var i = 0, len = args.length; i < len; i++) {

+					lines[i] = dir(args[i]);

+				}

+				return lines.join(newLine + newLine);

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("dirxml", function(appender, args, returnValue) {

+				var lines = [];

+				for (var i = 0, len = args.length; i < len; i++) {

+					var win = appender.getCommandWindow();

+					lines[i] = getXhtml(args[i]);

+				}

+				return lines.join(newLine + newLine);

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("cd", function(appender, args, returnValue) {

+				var win, message;

+				if (args.length === 0 || args[0] === "") {

+					win = window;

+					message = "Command line set to run in main window";

+				} else {

+					if (args[0].window == args[0]) {

+						win = args[0];

+						message = "Command line set to run in frame '" + args[0].name + "'";

+					} else {

+						win = window.frames[args[0]];

+						if (win) {

+							message = "Command line set to run in frame '" + args[0] + "'";

+						} else {

+							returnValue.isError = true;

+							message = "Frame '" + args[0] + "' does not exist";

+							win = appender.getCommandWindow();

+						}

+					}

+				}

+				appender.setCommandWindow(win);

+				return message;

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("clear", function(appender, args, returnValue) {

+				returnValue.appendResult = false;

+				appender.clear();

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("keys", function(appender, args, returnValue) {

+				var keys = [];

+				for (var k in args[0]) {

+					keys.push(k);

+				}

+				return keys;

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("values", function(appender, args, returnValue) {

+				var values = [];

+				for (var k in args[0]) {

+					try {

+						values.push(args[0][k]);

+					} catch (ex) {

+						logLog.warn("values(): Unable to obtain value for key " + k + ". Details: " + getExceptionMessage(ex));

+					}

+				}

+				return values;

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("expansionDepth", function(appender, args, returnValue) {

+				var expansionDepth = parseInt(args[0], 10);

+				if (isNaN(expansionDepth) || expansionDepth < 0) {

+					returnValue.isError = true;

+					return "" + args[0] + " is not a valid expansion depth";

+				} else {

+					appender.setCommandLineObjectExpansionDepth(expansionDepth);

+					return "Object expansion depth set to " + expansionDepth;

+				}

+			});

+		}

+

+		function init() {

+			// Add command line functions

+			createCommandLineFunctions();

+		}

+

+		/* ------------------------------------------------------------------ */

+

+		init();

+	})();

+

+	/* ---------------------------------------------------------------------- */

+	// Main load

+

+   log4javascript.setDocumentReady = function() {

+       pageLoaded = true;

+       log4javascript.dispatchEvent("load", {});

+   };

+

+    if (window.addEventListener) {

+        window.addEventListener("load", log4javascript.setDocumentReady, false);

+    } else if (window.attachEvent) {

+        window.attachEvent("onload", log4javascript.setDocumentReady);

+    } else {

+        var oldOnload = window.onload;

+        if (typeof window.onload != "function") {

+            window.onload = log4javascript.setDocumentReady;

+        } else {

+            window.onload = function(evt) {

+                if (oldOnload) {

+                    oldOnload(evt);

+                }

+                log4javascript.setDocumentReady();

+            };

+        }

+    }

+

+    // Ensure that the log4javascript object is available in the window. This

+    // is necessary for log4javascript to be available in IE if loaded using

+    // Dojo's module system

+    window.log4javascript = log4javascript;

+

+    return log4javascript;

+})();
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/main.css b/planetstack/core/static/log4javascript-1.4.6/main.css
new file mode 100644
index 0000000..5ac3df3
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/main.css
@@ -0,0 +1,300 @@
+body {

+	font-family: Verdana, Arial, Helvetica, Sans-serif;

+	font-size: 75%;

+	color: black;

+	background-color: #eeeeee;

+	text-align: center;

+	padding: 0px;

+	margin: 0px;

+}

+

+div#container {

+	width: 770px;

+	text-align: left;

+	line-height: 150%;

+	border-width: 0px 1px 1px 1px;

+	border-color: #cccccc;

+	border-style: solid;

+	background-color: white;

+	color: black;

+	padding: 10px;

+	margin: 0px auto 10px auto;

+}

+

+div#header {

+	margin: 0px;

+}

+

+div#header h1 {

+	font-family: Courier New, Courier, Monospace, Serif;

+	padding: 8px 0 15px 0;

+	margin: 0px;

+	font-size: 200%;

+	font-weight: bold;

+	text-align: right;

+}

+

+div#header h1 a {

+	color: black;

+}

+

+div#nav {

+	font-size: 91.66%;

+	font-weight: bold;

+	padding-top: 5px;

+	padding-bottom: 5px;

+	border-bottom: solid #cccccc 1px;

+	text-align: right;

+	background-color: #f0f0fa;

+}

+

+div#container.nonav div#content {

+	float: none;

+	width: auto;

+}

+

+*.externallinkinfo {

+	float: right;

+	font-style: italic;

+}

+

+div#content h1 {

+	padding: 10px 3px 5px 3px;

+	margin: 5px 0px;

+	font-size: 175%;

+	font-weight: normal;

+}

+

+div#content h2 {

+	background-color: darkgreen;

+	color: white;

+	padding: 0px 3px;

+	font-size: 116.66%;

+	font-weight: bold;

+}

+

+div#content h2 a {

+	color: white;

+}

+

+div#content h3 {

+	padding: 0px 3px;

+	font-size: 116.66%;

+	font-weight: bold;

+	border-style: solid;

+	border-color: #003399;

+	border-width: 1px 0px;

+}

+

+div#content h4 {

+	padding: 0px 3px;

+	font-size: 100%;

+	font-weight: bold;

+	border-top: solid #eeeeee 1px;

+}

+

+div#content h5 {

+	padding: 0px;

+	margin: 3px 0px;

+}

+

+div#footer {

+	margin-top: 20px;

+	padding: 2px;

+	border-top: solid #cccccc 1px;

+	font-size: 91.66%;

+}

+

+a {

+	color: #003399;

+	text-decoration: none;

+}

+

+a:hover {

+	text-decoration: underline;

+}

+

+a.bold {

+	font-weight: bold;

+}

+

+a.underlined {

+	text-decoration: underline;

+}

+

+a img {

+	border-width: 0px;

+}

+

+br.clear {

+	clear: both;

+}

+

+table {

+	font-size: 100%;

+}

+

+/* Code */

+pre, code {

+	font-family: Courier New, Courier;

+	font-size: 108.33%;

+}

+

+pre.code, pre.console {

+	border: solid 1px #cccccc;

+	padding: 3px;

+}

+

+pre.code {

+	background-color: #eeeeee;

+}

+

+*.trace {

+	color: #666666;

+}

+

+*.debug {

+	color: green;

+}

+

+*.info {

+	color: #000099;

+}

+

+*.warn {

+	color: #999900;

+}

+

+*.error {

+	color: red;

+}

+

+*.fatal {

+	color: #660066;

+}

+

+

+div.example, div.panel {

+	border: solid 1px #cccccc;

+	background-color: #f5f5f5;

+	padding: 3px;

+	margin-bottom: 10px;

+}

+

+div.panel h2 {

+	margin: 5px 0px;

+}

+

+div.padded {

+	padding: 10px;

+}

+

+div.hidden {

+	display: none;

+}

+

+div.active {

+	background-color: #fcfffc;

+	border-color: green;

+}

+

+label.rightofinput, input.rightoflabel {

+	margin-right: 20px;

+}

+

+/* 'Back to top' link */

+p.linktotop {

+	text-align: right;

+}

+

+ul.propertieslist li.method, ul.propertieslist li.property {

+	margin: 0;

+	padding: 0px 0px 15px 0px;

+}

+

+ul.propertieslist li *.name {

+	font-size: 116.66%;

+	font-weight: bold;

+}

+

+ul.propertieslist li.method div.methodsignature {

+	margin: 10px 0px;

+	font-size: 116.66%;

+	background-color: #eeeeee;

+}

+

+ul.propertieslist li.method *.paramsheading {

+	font-weight: bold;

+}

+

+ul.propertieslist li.method *.params {

+	padding-top: 5px;

+	padding-bottom: 5px;

+}

+

+ul.propertieslist li.method *.params li.param {

+	padding-bottom: 10px;

+}

+

+ul.propertieslist li.method *.params li.param *.paramname {

+	font-style: italic;

+}

+

+div.serverlog {

+	height: 200px;

+	/*border: solid 1px #cccccc;*/

+}

+

+div#inPageConsole {

+	margin-top: 10px;

+}

+

+div.iframecontainer {

+	background-color: white;

+	border: solid #cccccc 1px;

+	width: 100%;

+}

+

+div.veryprominent {

+	background-color: darkgreen;

+	color: white;

+	font-weight: bold;

+	padding: 10px;

+	font-size: 133.33%;

+	margin-bottom: 10px;

+}

+

+div.veryprominent a {

+	color: white;

+}

+

+*.largetext {

+	font-size: 116.66%;

+}

+

+div#leftcolumn {

+	float: left;

+	width: 160px;

+}

+

+div#rightcolumn {

+	float: right;

+	width: 580px;

+}

+

+td.fullsupport {

+	background-color: lightgreen;

+}

+

+td.partialsupport {

+	background-color: gold;

+}

+

+td.nosupport {

+	background-color: lightcoral;

+}

+

+p.editions {

+	text-align: right;

+	font-style: italic;

+}
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/test/index.html b/planetstack/core/static/log4javascript-1.4.6/test/index.html
new file mode 100644
index 0000000..e01f13c
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/test/index.html
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - Tests</title>

+	</head>

+	<body>

+		<ul>

+			<li><a href="log4javascript.html">Standard edition tests</a></li>

+			<li><a href="log4javascript_uncompressed.html">Standard edition uncompressed tests</a></li>

+			<li><a href="log4javascript_production.html">Production edition tests</a></li>

+			<li><a href="log4javascript_production_uncompressed.html">Production edition uncompressed tests</a></li>

+		</ul>

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/test/log4javascript.html b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript.html
new file mode 100644
index 0000000..8e426b9
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - log4javascript - Tests</title>

+		<script type="text/javascript" src="../js/log4javascript.js"></script>

+		<script type="text/javascript" src="../js/stubs/log4javascript.js"></script>

+		<script type="text/javascript" src="xntest.js"></script>

+		<script type="text/javascript" src="../js/tests/log4javascript.js"></script>

+		<link rel="stylesheet" type="text/css" href="tests.css"/>

+	</head>

+	<body>

+		<div id="messages"></div>

+		<div id="inlineAppenderContainer"></div>

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_lite.html b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_lite.html
new file mode 100644
index 0000000..508dc83
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_lite.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - log4javascript_lite - Tests</title>

+		<script type="text/javascript" src="../js/log4javascript_lite.js"></script>

+		<script type="text/javascript" src="../js/stubs/log4javascript_lite.js"></script>

+		<script type="text/javascript" src="xntest.js"></script>

+		<script type="text/javascript" src="../js/tests/log4javascript_lite.js"></script>

+		<link rel="stylesheet" type="text/css" href="tests.css"/>

+	</head>

+	<body>

+		<div id="messages"></div>

+		<div id="inlineAppenderContainer"></div>

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_lite_uncompressed.html b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_lite_uncompressed.html
new file mode 100644
index 0000000..968019c
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_lite_uncompressed.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - log4javascript_lite_uncompressed - Tests</title>

+		<script type="text/javascript" src="../js/log4javascript_lite_uncompressed.js"></script>

+		<script type="text/javascript" src="../js/stubs/log4javascript_lite_uncompressed.js"></script>

+		<script type="text/javascript" src="xntest.js"></script>

+		<script type="text/javascript" src="../js/tests/log4javascript_lite_uncompressed.js"></script>

+		<link rel="stylesheet" type="text/css" href="tests.css"/>

+	</head>

+	<body>

+		<div id="messages"></div>

+		<div id="inlineAppenderContainer"></div>

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_production.html b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_production.html
new file mode 100644
index 0000000..e5308b1
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_production.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - log4javascript_production - Tests</title>

+		<script type="text/javascript" src="../js/log4javascript_production.js"></script>

+		<script type="text/javascript" src="../js/stubs/log4javascript_production.js"></script>

+		<script type="text/javascript" src="xntest.js"></script>

+		<script type="text/javascript" src="../js/tests/log4javascript_production.js"></script>

+		<link rel="stylesheet" type="text/css" href="tests.css"/>

+	</head>

+	<body>

+		<div id="messages"></div>

+		<div id="inlineAppenderContainer"></div>

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_production_uncompressed.html b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_production_uncompressed.html
new file mode 100644
index 0000000..21f84d7
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_production_uncompressed.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - log4javascript_production_uncompressed - Tests</title>

+		<script type="text/javascript" src="../js/log4javascript_production_uncompressed.js"></script>

+		<script type="text/javascript" src="../js/stubs/log4javascript_production_uncompressed.js"></script>

+		<script type="text/javascript" src="xntest.js"></script>

+		<script type="text/javascript" src="../js/tests/log4javascript_production_uncompressed.js"></script>

+		<link rel="stylesheet" type="text/css" href="tests.css"/>

+	</head>

+	<body>

+		<div id="messages"></div>

+		<div id="inlineAppenderContainer"></div>

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_uncompressed.html b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_uncompressed.html
new file mode 100644
index 0000000..3db9241
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_uncompressed.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - log4javascript_uncompressed - Tests</title>

+		<script type="text/javascript" src="../js/log4javascript_uncompressed.js"></script>

+		<script type="text/javascript" src="../js/stubs/log4javascript_uncompressed.js"></script>

+		<script type="text/javascript" src="xntest.js"></script>

+		<script type="text/javascript" src="../js/tests/log4javascript_uncompressed.js"></script>

+		<link rel="stylesheet" type="text/css" href="tests.css"/>

+	</head>

+	<body>

+		<div id="messages"></div>

+		<div id="inlineAppenderContainer"></div>

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/test/main.html b/planetstack/core/static/log4javascript-1.4.6/test/main.html
new file mode 100644
index 0000000..176098f
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/test/main.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - %%build:edition%% - Tests</title>

+		<script type="text/javascript" src="../js/%%build:edition%%.js"></script>

+		<script type="text/javascript" src="../js/stubs/%%build:edition%%.js"></script>

+		<script type="text/javascript" src="xntest.js"></script>

+		<script type="text/javascript" src="../js/tests/%%build:edition%%.js"></script>

+		<link rel="stylesheet" type="text/css" href="tests.css"/>

+	</head>

+	<body>

+		<div id="messages"></div>

+		<div id="inlineAppenderContainer"></div>

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/test/tests.css b/planetstack/core/static/log4javascript-1.4.6/test/tests.css
new file mode 100644
index 0000000..9cddef8
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/test/tests.css
@@ -0,0 +1,88 @@
+body {

+	font-family: verdana, arial, helvetica, sans-serif;

+	font-size: 81.25%;

+}

+

+h2 {

+	font-size: 100%;

+	padding: 0;

+	margin: 0.1em 0 0.1em 0;

+}

+

+div.xn_test_suite_container {

+	border: solid #cccccc 1px;

+	padding: 2px 5px;

+	margin: 2px 0px;

+}

+

+div.xn_test_progressbar_container {

+	border: solid black 1px;

+}

+

+div.xn_test_progressbar_container *.success {

+	background-color: #00ff00;

+}

+

+div.xn_test_progressbar_container *.failure {

+	background-color: red;

+}

+

+div.xn_test_overallprogressbar_container {

+	position: relative;

+}

+

+div.xn_test_overallprogressbar_container h1 {

+	margin: 0;

+	padding: 2px;

+	font-size: 125%;

+	font-weight: bold;

+	white-space: nowrap;

+}

+

+dl *.success {

+	color: green;

+}

+

+dl *.failure {

+	color: red;

+}

+

+span.xn_test_expander {

+	padding: 0;

+	border: solid black 1px;

+	cursor: pointer;

+	cursor: hand;

+	line-height: 100%; 

+	font-weight: bold;

+	margin-right: 1em;

+	font-size: 11px;

+}

+

+dl.xn_test_expanded {

+	display: block;

+}

+

+dl.xn_test_collapsed {

+	display: none;

+}

+

+div.xn_test_suite_success {

+	border: solid 2px limegreen;

+}

+

+div.xn_test_suite_failure {

+	border: solid 2px red;

+}

+

+pre.xn_test_log_report {

+	background-color: #f5f5f5;

+	padding: 3px;

+	border: solid gray 1px;

+	font-size: 11px;

+	font-family: Courier New, Courier, monospace;

+}

+

+code.xn_test_stacktrace {

+	color: red;

+	overflow: 

+}
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/test/xntest.js b/planetstack/core/static/log4javascript-1.4.6/test/xntest.js
new file mode 100644
index 0000000..1b8f475
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/test/xntest.js
@@ -0,0 +1,739 @@
+// Next three methods are primarily for IE5, which is missing them
+if (!Array.prototype.push) {
+	Array.prototype.push = function() {
+		for (var i = 0; i < arguments.length; i++){
+				this[this.length] = arguments[i];
+		}
+		return this.length;
+	};
+}
+
+if (!Array.prototype.shift) {
+	Array.prototype.shift = function() {
+		if (this.length > 0) {
+			var firstItem = this[0];
+			for (var i = 0; i < this.length - 1; i++) {
+				this[i] = this[i + 1];
+			}
+			this.length = this.length - 1;
+			return firstItem;
+		}
+	};
+}
+
+if (!Function.prototype.apply) {
+	Function.prototype.apply = function(obj, args) {
+		var methodName = "__apply__";
+		if (typeof obj[methodName] != "undefined") {
+			methodName += (String(Math.random())).substr(2);
+		}
+		obj[methodName] = this;
+
+		var argsStrings = new Array(args.length);
+		for (var i = 0; i < args.length; i++) {
+			argsStrings[i] = "args[" + i + "]";
+		}
+		var script = "obj." + methodName + "(" + argsStrings.join(",") + ")";
+		var returnValue = eval(script);
+		delete obj[methodName];
+		return returnValue;
+	};
+}
+
+/* -------------------------------------------------------------------------- */
+
+var xn = new Object();
+
+(function() {
+	// Utility functions
+
+	// Event listeners
+	var getListenersPropertyName = function(eventName) {
+		return "__listeners__" + eventName;
+	};
+
+	var addEventListener = function(node, eventName, listener, useCapture) {
+		useCapture = Boolean(useCapture);
+		if (node.addEventListener) {
+			node.addEventListener(eventName, listener, useCapture);
+		} else if (node.attachEvent) {
+			node.attachEvent("on" + eventName, listener);
+		} else {
+			var propertyName = getListenersPropertyName(eventName);
+			if (!node[propertyName]) {
+				node[propertyName] = new Array();
+
+				// Set event handler
+				node["on" + eventName] = function(evt) {
+					evt = module.getEvent(evt);
+					var listenersPropertyName = getListenersPropertyName(eventName);
+
+					// Clone the array of listeners to leave the original untouched
+					var listeners = cloneArray(this[listenersPropertyName]);
+					var currentListener;
+
+					// Call each listener in turn
+					while (currentListener = listeners.shift()) {
+						currentListener.call(this, evt);
+					}
+				};
+			}
+			node[propertyName].push(listener);
+		}
+	};
+
+	// Clones an array
+	var cloneArray = function(arr) {
+		var clonedArray = [];
+		for (var i = 0; i < arr.length; i++) {
+			clonedArray[i] = arr[i];
+		}
+		return clonedArray;
+	}
+
+	var isFunction = function(f) {
+		if (!f){ return false; }
+		return (f instanceof Function || typeof f == "function");
+	};
+
+	// CSS Utilities
+	
+	function array_contains(arr, val) {
+		for (var i = 0, len = arr.length; i < len; i++) {
+			if (arr[i] === val) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	function addClass(el, cssClass) {
+		if (!hasClass(el, cssClass)) {
+			if (el.className) {
+				el.className += " " + cssClass;
+			} else {
+				el.className = cssClass;
+			}
+		}
+	}
+
+	function hasClass(el, cssClass) {
+		if (el.className) {
+			var classNames = el.className.split(" ");
+			return array_contains(classNames, cssClass);
+		}
+		return false;
+	}
+
+	function removeClass(el, cssClass) {
+		if (hasClass(el, cssClass)) {
+			// Rebuild the className property
+			var existingClasses = el.className.split(" ");
+			var newClasses = [];
+			for (var i = 0; i < existingClasses.length; i++) {
+				if (existingClasses[i] != cssClass) {
+					newClasses[newClasses.length] = existingClasses[i];
+				}
+			}
+			el.className = newClasses.join(" ");
+		}
+	}
+
+	function replaceClass(el, newCssClass, oldCssClass) {
+		removeClass(el, oldCssClass);
+		addClass(el, newCssClass);
+	}
+
+	function getExceptionStringRep(ex) {
+		if (ex) {
+			var exStr = "Exception: ";
+			if (ex.message) {
+				exStr += ex.message;
+			} else if (ex.description) {
+				exStr += ex.description;
+			}
+			if (ex.lineNumber) {
+				exStr += " on line number " + ex.lineNumber;
+			}
+			if (ex.fileName) {
+				exStr += " in file " + ex.fileName;
+			}
+			return exStr;
+		}
+		return null;
+	}
+
+
+	/* ---------------------------------------------------------------------- */
+
+	/* Configure the test logger try to use FireBug */
+	var log, error;
+	if (window["console"] && typeof console.log == "function") {
+		log = function() {
+			if (xn.test.enableTestDebug) {
+				console.log.apply(console, arguments);
+			}
+		};
+		error = function() {
+			if (xn.test.enableTestDebug) {
+				console.error.apply(console, arguments);
+			}
+		};
+	} else {
+		log = function() {};
+	}
+
+	/* Set up something to report to */
+
+	var initialized = false;
+	var container;
+	var progressBarContainer, progressBar, overallSummaryText;
+	var currentTest = null;
+	var suites = [];
+	var totalTestCount = 0;
+	var currentTestIndex = 0;
+	var testFailed = false;
+	var testsPassedCount = 0;
+	var startTime;
+	
+	var log4javascriptEnabled = false;
+	
+	var nextSuiteIndex = 0;
+	
+	function runNextSuite() {
+		if (nextSuiteIndex < suites.length) {
+			suites[nextSuiteIndex++].run();
+		}
+	}
+	
+	var init = function() {
+		if (initialized) { return true; }
+		
+		container = document.createElement("div");
+		
+		// Create the overall progress bar
+		progressBarContainer = container.appendChild(document.createElement("div"));
+		progressBarContainer.className = "xn_test_progressbar_container xn_test_overallprogressbar_container";
+		progressBar = progressBarContainer.appendChild(document.createElement("div"));
+		progressBar.className = "success";
+
+		document.body.appendChild(container);
+
+		var h1 = progressBar.appendChild(document.createElement("h1"));
+		overallSummaryText = h1.appendChild(document.createTextNode(""));
+
+		initialized = true;
+		
+		// Set up logging
+		log4javascriptEnabled = !!log4javascript && xn.test.enable_log4javascript;
+		
+		function TestLogAppender() {}
+		
+		if (log4javascriptEnabled) {
+			TestLogAppender.prototype = new log4javascript.Appender();
+			TestLogAppender.prototype.layout = new log4javascript.PatternLayout("%d{HH:mm:ss,SSS} %-5p %m");
+			TestLogAppender.prototype.append = function(loggingEvent) {
+				var formattedMessage = this.getLayout().format(loggingEvent);
+				if (this.getLayout().ignoresThrowable()) {
+					formattedMessage += loggingEvent.getThrowableStrRep();
+				}
+				currentTest.addLogMessage(formattedMessage);
+			};
+			
+			var appender = new TestLogAppender();
+			appender.setThreshold(log4javascript.Level.ALL);
+			log4javascript.getRootLogger().addAppender(appender);
+			log4javascript.getRootLogger().setLevel(log4javascript.Level.ALL);
+		}
+
+		startTime = new Date();
+
+		// First, build each suite
+		for (var i = 0; i < suites.length; i++) {
+			suites[i].build();
+			totalTestCount += suites[i].tests.length;
+		}
+		
+		// Now run each suite
+		runNextSuite();
+	};
+	
+	function updateProgressBar() {
+		progressBar.style.width = "" + parseInt(100 * (currentTestIndex) / totalTestCount) + "%";
+		var s = (totalTestCount === 1) ? "" : "s";
+		var timeTaken = new Date().getTime() - startTime.getTime();
+		overallSummaryText.nodeValue = "" + testsPassedCount + " of " + totalTestCount + " test" + s + " passed in " + timeTaken + "ms";
+	}
+
+	addEventListener(window, "load", init);
+
+	/* ---------------------------------------------------------------------- */
+
+	/* Test Suite */
+	var Suite = function(name, callback, hideSuccessful) {
+		this.name = name;
+		this.callback = callback;
+		this.hideSuccessful = hideSuccessful;
+		this.tests = [];
+		this.log = log;
+		this.error = error;
+		this.expanded = true;
+		suites.push(this);
+	}
+
+	Suite.prototype.test = function(name, callback, setUp, tearDown) {
+		this.log("adding a test named " + name)
+		var t = new Test(name, callback, this, setUp, tearDown);
+		this.tests.push(t);
+	};
+
+	Suite.prototype.build = function() {
+		// Build the elements used by the suite
+		var suite = this;
+		this.testFailed = false;
+		this.container = document.createElement("div");
+		this.container.className = "xn_test_suite_container";
+
+		var heading = document.createElement("h2");
+		this.expander = document.createElement("span");
+		this.expander.className = "xn_test_expander";
+		this.expander.onclick = function() {
+			if (suite.expanded) {
+				suite.collapse();
+			} else {
+				suite.expand();
+			}
+		};
+		heading.appendChild(this.expander);
+		
+		this.headingTextNode = document.createTextNode(this.name);
+		heading.appendChild(this.headingTextNode);
+		this.container.appendChild(heading);
+
+		this.reportContainer = document.createElement("dl");
+		this.container.appendChild(this.reportContainer);
+
+		this.progressBarContainer = document.createElement("div");
+		this.progressBarContainer.className = "xn_test_progressbar_container";
+		this.progressBar = document.createElement("div");
+		this.progressBar.className = "success";
+		this.progressBar.innerHTML = "&nbsp;";
+		this.progressBarContainer.appendChild(this.progressBar);
+		this.reportContainer.appendChild(this.progressBarContainer);
+
+		this.expand();
+
+		container.appendChild(this.container);
+
+		// invoke callback to build the tests
+		this.callback.apply(this, [this]);
+	};
+
+	Suite.prototype.run = function() {
+		this.log("running suite '%s'", this.name)
+		this.startTime = new Date();
+
+		// now run the first test
+		this._currentIndex = 0;
+		this.runNextTest();
+	};
+
+	Suite.prototype.updateProgressBar = function() {
+		// Update progress bar
+		this.progressBar.style.width = "" + parseInt(100 * (this._currentIndex) / this.tests.length) + "%";
+		//log(this._currentIndex + ", " + this.tests.length + ", " + progressBar.style.width + ", " + progressBar.className);
+	};
+
+	Suite.prototype.expand = function() {
+		this.expander.innerHTML = "-";
+		replaceClass(this.reportContainer, "xn_test_expanded", "xn_test_collapsed");
+		this.expanded = true;
+	};
+
+	Suite.prototype.collapse = function() {
+		this.expander.innerHTML = "+";
+		replaceClass(this.reportContainer, "xn_test_collapsed", "xn_test_expanded");
+		this.expanded = false;
+	};
+
+	Suite.prototype.finish = function(timeTaken) {
+		var newClass = this.testFailed ? "xn_test_suite_failure" : "xn_test_suite_success";
+		var oldClass = this.testFailed ? "xn_test_suite_success" : "xn_test_suite_failure";
+		replaceClass(this.container, newClass, oldClass);
+
+		this.headingTextNode.nodeValue += " (" + timeTaken + "ms)";
+
+		if (this.hideSuccessful && !this.testFailed) {
+			this.collapse();
+		}
+		runNextSuite();
+	};
+
+	/**
+	 * Works recursively with external state (the next index)
+	 * so that we can handle async tests differently
+	 */
+	Suite.prototype.runNextTest = function() {
+		if (this._currentIndex == this.tests.length) {
+			// finished!
+			var timeTaken = new Date().getTime() - this.startTime.getTime();
+
+			this.finish(timeTaken);
+			return;
+		}
+
+		var suite = this;
+		var t = this.tests[this._currentIndex++];
+		currentTestIndex++;
+
+		if (isFunction(suite.setUp)) {
+			suite.setUp.apply(suite, [t]);
+		}
+		if (isFunction(t.setUp)) {
+			t.setUp.apply(t, [t]);
+		}
+
+		t._run();
+		
+		function afterTest() {
+			if (isFunction(suite.tearDown)) {
+				suite.tearDown.apply(suite, [t]);
+			}
+			if (isFunction(t.tearDown)) {
+				t.tearDown.apply(t, [t]);
+			}
+			suite.log("finished test [%s]", t.name);
+			updateProgressBar();
+			suite.updateProgressBar();
+			suite.runNextTest();
+		}
+		
+		if (t.isAsync) {
+			t.whenFinished = afterTest;
+		} else {
+			setTimeout(afterTest, 1);
+		}
+	};
+
+	Suite.prototype.reportSuccess = function() {
+	};
+
+	/* ---------------------------------------------------------------------- */
+	/**
+	 * Create a new test
+	 */
+	var Test = function(name, callback, suite, setUp, tearDown) {
+		this.name = name;
+		this.callback = callback;
+		this.suite = suite;
+		this.setUp = setUp;
+		this.tearDown = tearDown;
+		this.log = log;
+		this.error = error;
+		this.assertCount = 0;
+		this.logMessages = [];
+		this.logExpanded = false;
+	};
+
+	/**
+	 * Default success reporter, please override
+	 */
+	Test.prototype.reportSuccess = function(name, timeTaken) {
+		/* default success reporting handler */
+		this.reportHeading = document.createElement("dt");
+		var text = this.name + " passed in " + timeTaken + "ms";
+		
+		this.reportHeading.appendChild(document.createTextNode(text));
+
+		this.reportHeading.className = "success";
+		var dd = document.createElement("dd");
+		dd.className = "success";
+
+		this.suite.reportContainer.appendChild(this.reportHeading);
+		this.suite.reportContainer.appendChild(dd);
+		this.createLogReport();
+	};
+
+	/**
+	 * Cause the test to immediately fail
+	 */
+	Test.prototype.reportFailure = function(name, msg, ex) {
+		this.suite.testFailed = true;
+		this.suite.progressBar.className = "failure";
+		progressBar.className = "failure";
+		this.reportHeading = document.createElement("dt");
+		this.reportHeading.className = "failure";
+		var text = document.createTextNode(this.name);
+		this.reportHeading.appendChild(text);
+
+		var dd = document.createElement("dd");
+		dd.appendChild(document.createTextNode(msg));
+		dd.className = "failure";
+
+		this.suite.reportContainer.appendChild(this.reportHeading);
+		this.suite.reportContainer.appendChild(dd);
+		if (ex && ex.stack) {
+			var stackTraceContainer = this.suite.reportContainer.appendChild(document.createElement("code"));
+			stackTraceContainer.className = "xn_test_stacktrace";
+			stackTraceContainer.innerHTML = ex.stack.replace(/\r/g, "\n").replace(/\n{1,2}/g, "<br />");
+		}
+		this.createLogReport();
+	};
+	
+	Test.prototype.createLogReport = function() {
+		if (this.logMessages.length > 0) {
+			this.reportHeading.appendChild(document.createTextNode(" ("));
+			var logToggler = this.reportHeading.appendChild(document.createElement("a"));
+			logToggler.href = "#";
+			logToggler.innerHTML = "show log";
+			var test = this;
+			
+			logToggler.onclick = function() {
+				if (test.logExpanded) {
+					test.hideLogReport();
+					this.innerHTML = "show log";
+					test.logExpanded = false;
+				} else {
+					test.showLogReport();
+					this.innerHTML = "hide log";
+					test.logExpanded = true;
+				}
+				return false;
+			};
+
+			this.reportHeading.appendChild(document.createTextNode(")"));
+			
+			// Create log report
+			this.logReport = this.suite.reportContainer.appendChild(document.createElement("pre"));
+			this.logReport.style.display = "none";
+			this.logReport.className = "xn_test_log_report";
+			var logMessageDiv;
+			for (var i = 0, len = this.logMessages.length; i < len; i++) {
+				logMessageDiv = this.logReport.appendChild(document.createElement("div"));
+				logMessageDiv.appendChild(document.createTextNode(this.logMessages[i]));
+			}
+		}
+	};
+
+	Test.prototype.showLogReport = function() {
+		this.logReport.style.display = "inline-block";
+	};
+		
+	Test.prototype.hideLogReport = function() {
+		this.logReport.style.display = "none";
+	};
+
+	Test.prototype.async = function(timeout, callback) {
+		timeout = timeout || 250;
+		var self = this;
+		var timedOutFunc = function() {
+			if (!self.completed) {
+				var message = (typeof callback === "undefined") ?
+							"Asynchronous test timed out" : callback(self);
+				self.fail(message);
+			}
+		}
+		var timer = setTimeout(function () { timedOutFunc.apply(self, []); }, timeout)
+		this.isAsync = true;
+	};
+
+	/**
+	 * Run the test
+	 */
+	Test.prototype._run = function() {
+		this.log("starting test [%s]", this.name);
+		this.startTime = new Date();
+		currentTest = this;
+		try {
+			this.callback(this);
+			if (!this.completed && !this.isAsync) {
+				this.succeed();
+			}
+		} catch (e) {
+			this.log("test [%s] threw exception [%s]", this.name, e);
+			var s = (this.assertCount === 1) ? "" : "s";
+			this.fail("Exception thrown after " + this.assertCount + " successful assertion" + s + ": " + getExceptionStringRep(e), e);
+		}
+	};
+
+	/**
+	 * Cause the test to immediately succeed
+	 */
+	Test.prototype.succeed = function() {
+		if (this.completed) { return false; }
+		// this.log("test [%s] succeeded", this.name);
+		this.completed = true;
+		var timeTaken = new Date().getTime() - this.startTime.getTime();
+		testsPassedCount++;
+		this.reportSuccess(this.name, timeTaken);
+		if (this.whenFinished) {
+			this.whenFinished();
+		}
+	};
+
+	Test.prototype.fail = function(msg, ex)	{
+		if (typeof msg != "string") {
+			msg = getExceptionStringRep(msg);
+		}
+		if (this.completed) { return false; }
+		this.completed = true;
+		// this.log("test [%s] failed", this.name);
+		this.reportFailure(this.name, msg, ex);
+		if (this.whenFinished) {
+			this.whenFinished();
+		}
+	};
+	
+	Test.prototype.addLogMessage = function(logMessage) {
+		this.logMessages.push(logMessage);
+	};
+
+	/* assertions */
+	var displayStringForValue = function(obj) {
+		if (obj === null) {
+			return "null";
+		} else if (typeof obj === "undefined") {
+			return "undefined";
+		}
+		return obj.toString();
+	};
+
+	var assert = function(args, expectedArgsCount, testFunction, defaultComment) {
+		this.assertCount++;
+		var comment = defaultComment;
+		var i;
+		var success;
+		var values = [];
+		if (args.length == expectedArgsCount) {
+			for (i = 0; i < args.length; i++) {
+				values[i] = args[i];
+			}
+		} else if (args.length == expectedArgsCount + 1) {
+			comment = args[0];
+			for (i = 1; i < args.length; i++) {
+				values[i - 1] = args[i];
+			}
+		} else {
+			throw new Error("Invalid number of arguments passed to assert function");
+		}
+		success = testFunction(values);
+		if (!success) {
+			var regex = /\{([0-9]+)\}/;
+			while (regex.test(comment)) {
+				comment = comment.replace(regex, displayStringForValue(values[parseInt(RegExp.$1)]));
+			}
+			this.fail("Test failed on assertion " + this.assertCount + ": " + comment);
+		}
+	};
+
+	var testNull = function(values) {
+		return (values[0] === null);
+	};
+
+	Test.prototype.assertNull = function() {
+		assert.apply(this, [arguments, 1, testNull, "Expected to be null but was {0}"]);
+	}
+
+	var testNotNull = function(values) {
+		return (values[0] !== null);
+	};
+
+	Test.prototype.assertNotNull = function() {
+		assert.apply(this, [arguments, 1, testNotNull, "Expected not to be null but was {0}"]);
+	}
+
+	var testBoolean = function(values) {
+		return (Boolean(values[0]));
+	};
+
+	Test.prototype.assert = function() {
+		assert.apply(this, [arguments, 1, testBoolean, "Expected not to be equivalent to false"]);
+	};
+
+	var testTrue = function(values) {
+		return (values[0] === true);
+	};
+
+	Test.prototype.assertTrue = function() {
+		assert.apply(this, [arguments, 1, testTrue, "Expected to be true but was {0}"]);
+	};
+
+	Test.prototype.assert = function() {
+		assert.apply(this, [arguments, 1, testTrue, "Expected to be true but was {0}"]);
+	};
+
+	var testFalse = function(values) {
+		return (values[0] === false);
+	};
+
+	Test.prototype.assertFalse = function() {
+		assert.apply(this, [arguments, 1, testFalse, "Expected to be false but was {0}"]);
+	}
+
+	var testEquivalent = function(values) {
+		return (values[0] === values[1]);
+	};
+
+	Test.prototype.assertEquivalent = function() {
+		assert.apply(this, [arguments, 2, testEquivalent, "Expected to be equal but values were {0} and {1}"]);
+	}
+
+	var testNotEquivalent = function(values) {
+		return (values[0] !== values[1]);
+	};
+
+	Test.prototype.assertNotEquivalent = function() {
+		assert.apply(this, [arguments, 2, testNotEquivalent, "Expected to be not equal but values were {0} and {1}"]);
+	}
+
+	var testEquals = function(values) {
+		return (values[0] == values[1]);
+	};
+
+	Test.prototype.assertEquals = function() {
+		assert.apply(this, [arguments, 2, testEquals, "Expected to be equal but values were {0} and {1}"]);
+	}
+
+	var testNotEquals = function(values) {
+		return (values[0] != values[1]);
+	};
+
+	Test.prototype.assertNotEquals = function() {
+		assert.apply(this, [arguments, 2, testNotEquals, "Expected to be not equal but values were {0} and {1}"]);
+	}
+
+	var testRegexMatches = function(values) {
+		return (values[0].test(values[1]));
+	};
+
+	Test.prototype.assertRegexMatches = function() {
+		assert.apply(this, [arguments, 2, testRegexMatches, "Expected regex {0} to match value {1} but it didn't"]);
+	}
+
+	Test.prototype.assertError = function(f, errorType) {
+		try {
+			f();
+			this.fail("Expected error to be thrown");
+		} catch (e) {
+			if (errorType && (!(e instanceof errorType))) {
+				this.fail("Expected error of type " + errorType + " to be thrown but error thrown was " + e);
+			}
+		}
+	};
+
+	/**
+	 * Execute a synchronous test
+	 */
+	xn.test = function(name, callback) {
+		xn.test.suite("Anonymous", function(s) {
+			s.test(name, callback);
+		});
+	}
+
+	/**
+	 * Create a test suite with a given name
+	 */
+	xn.test.suite = function(name, callback, hideSuccessful) {
+		var s = new Suite(name, callback, hideSuccessful);
+	}
+})();
\ No newline at end of file
diff --git a/planetstack/core/static/planetstack.css b/planetstack/core/static/planetstack.css
index 873a9d9..59b2199 100644
--- a/planetstack/core/static/planetstack.css
+++ b/planetstack/core/static/planetstack.css
@@ -535,3 +535,32 @@
 .left-nav>ul>li.active>a>.icon-reservation , .left-nav>ul>li:hover>a>.icon-reservation , .left-nav>ul>li.focus>a>.icon-reservation{
 background-image: url("Reservations_over.png");
 }
+
+#dashboardHPC {
+    padding-bottom: 10px;
+}
+.summary-attr {
+    padding-right: 20px;
+}
+.summary-attr-util {
+    padding-right: 20px;
+    color: green;
+}
+.SiteDetail {
+color: darkBlue;
+    font-size: 1.5em;
+}
+#addSlivers {
+ color: green;
+text-decoration: underline;
+    padding-right: 20px;
+}
+#remSlivers {
+ color: red;
+ text-decoration: underline;
+}
+#map-us {
+    padding-top: 10px;
+    width: 700px;
+    height: 400px;
+}
diff --git a/planetstack/templates/admin/dashboard/welcome.html b/planetstack/templates/admin/dashboard/welcome.html
index 707ee96..bec703d 100644
--- a/planetstack/templates/admin/dashboard/welcome.html
+++ b/planetstack/templates/admin/dashboard/welcome.html
@@ -22,4 +22,100 @@
 {% endif %}
 {% endfor %}
 </table>
+<script type="text/javascript" src="{% static 'log4javascript-1.4.6/log4javascript.js' %}"></script>
+    <h1>HPC Dashboard</h1>
+    <span id="hpcSummary">
+        <span class="summary-attr"><b>Active Slivers:</b> 78 </span>
+        <span class="summary-attr"><b>Overall Throughput:</b> 58Gbps</span>
+        <span class="summary-attr-util"><b>CPU Utilization:</b> 45%</span>
+
+    </span>
+    <div id="map-us" ></div>
+<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css" />
+<script src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js"></script>
+
+<script src="{% static 'js/Leaflet.MakiMarkers.js' %}" > </script>
+
+<script>
+var consoleAppender = new log4javascript.BrowserConsoleAppender();
+var patternLayout = new log4javascript.PatternLayout("%d{HH:mm:ss,SSS} %l{s:l} %-5p - %m{1}%n");
+consoleAppender.setLayout(patternLayout);
+
+var log  = log4javascript.getRootLogger();
+log.addAppender(consoleAppender);
+log.setLevel(log4javascript.Level.ALL);
+
+
+L.Map = L.Map.extend({
+    openPopup: function(popup) {
+        this._popup = popup;
+
+        return this.addLayer(popup).fire('popupopen', {
+            popup: this._popup
+        });
+    }
+});
+
+
+//Iterate through data and find the max/min coordinates to include all of our points to start
+var map = L.map('map-us'); //.setView([0, 0], 1);
+
+L.tileLayer('http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{z}/{x}/{y}.png', {
+    maxZoom: 18,
+    attribution: 'Test'
+}).addTo(map);
+
+var arrayOfLatLngs = [];
+var data = {{ cdnData|safe }};
+log.info( data );
+
+for ( var key in data ) {
+    arrayOfLatLngs.push([data[key]['lat'],data[key]['long']]);
+    log.info( arrayOfLatLngs );
+    var colorChoices = ["#007FFF", "#0000FF", "#7f00ff", "#FF00FF", "#FF007F", "#FF0000"];
+
+    var ratio = data[key]['numHPCSlivers']/data[key]['numNodes'] * 100;
+    var numColors = colorChoices.length;
+    var colorBands = 100/numColors;
+
+    log.info("numColors: " + numColors);
+    log.info("colorBands: " + colorBands);
+    log.info("ratio: " + ratio);
+
+    //Algorithm for color tone should consider the number of available nodes 
+    // on the site, and then how much the current dedicated nodes are impacted
+    //var iconColor = 0;
+    var iconColor = 0;
+    for (;iconColor < numColors; iconColor ++) {
+        if (ratio < colorBands * iconColor+1) { 
+            break;
+        }
+    }
+   
+    var icon = L.MakiMarkers.icon({icon: "star-stroked", color: colorChoices[iconColor] , size: "s"});
+
+    L.marker([data[key]['lat'], data[key]['long']], {icon: icon}).addTo(map)
+        .bindPopup( '<span class="SiteDetail"><b>' + key + '</b></span>' + 
+                   '</br><a href="' + data[key]['siteUrl'] + '">' + data[key]['siteUrl'] + '</a>' + 
+                   '</br><b>Available Nodes: </b>' + data[key]['numNodes'] + 
+                   '</br><b>Active HPC Slivers: </b>' + data[key]['numHPCSlivers'] + 
+                   '</br><span id="addSlivers">Add HPC Slivers</span>' + 
+                   '<span id="remSlivers">Remove HPC Slivers</span>' + 
+
+                   '');//.openPopup();
+
+}
+var bounds = new L.LatLngBounds(arrayOfLatLngs);
+map.fitBounds(bounds);
+
+var popup = L.popup();
+
+function onMapClick(e) {
+    popup
+    .setLatLng(e.latlng)
+    .setContent("You clicked the map at " + e.latlng.toString())
+    .openOn(map);
+}
+
+</script>
 {% endblock %}