'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
+
--- /dev/null
+/*
+ * 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);
+ };
+})();
--- /dev/null
+log4javascript change log\r
+-------------------------\r
+\r
+1.4.6 (19/3/2013)\r
+- Added fix to handle 1223 status code from XMLHttpRequest in IE\r
+\r
+1.4.5 (20/2/2013)\r
+- Changed AjaxAppender to send raw data rather than URL-encoded form data when\r
+ content-type is not "application/x-www-form-urlencoded"\r
+\r
+- Exposed sendAllRemaining() method of AjaxAppender\r
+\r
+1.4.4 (8/2/2013)\r
+- Fixed issue with repeated Content-Type headers in AjaxAppender\r
+\r
+- Improved uniqueness of PopUpAppender window name\r
+\r
+1.4.3 (18/9/2012)\r
+- Added addHeader() and getHeaders() methods to AjaxAppender\r
+\r
+- Modified sendAllOnUnload feature of AjaxAppender. It now works in WebKit but\r
+ at the expense of popping up a confirm dialog. That being the case, it is now\r
+ disabled by default.\r
+\r
+- Removed leaked global variable "initialized" \r
+\r
+- Fixed bugs #3528265, #3560924, #3560922, #2805479, #3510639 on Sourceforge\r
+ Tracker\r
+\r
+\r
+1.4.2 (13/10/2011)\r
+- Fixed JsonLayout trailing comma issue. See\r
+ http://stackoverflow.com/questions/7735382/asmx-weirdness-deserializing-json-\r
+ blob-from-log4javascript-logging\r
+\r
+- Fixed bugs #3401332, #3185753, #2884623, #2817213 on Sourceforge Tracker\r
+\r
+\r
+1.4.1 (23/3/2009)\r
+- Fixed document.domain/query string bug (#2519903 on Sourceforge Tracker)\r
+\r
+- Added isVisible() method to PopUpAppender\r
+\r
+- Added check for whether the console has been closed in isVisible() method of\r
+ InPageAppender\r
+\r
+- Included unit tests in the distribution\r
+\r
+\r
+1.4 (30/10/2008)\r
+\r
+- Added time() and timeEnd() methods to Logger\r
+\r
+- Added group() and groupEnd() methods to Logger and support for displaying\r
+ expandable groups to InPageAppender and PopUpAppender\r
+\r
+- Added facility to layout custom fields. A custom field value may now\r
+ optionally be a function which is passed a reference to the layout and a\r
+ logging event and run at the time the layout's format method is called\r
+\r
+- Added option to XmlLayout and JsonLayout to allow multiple messages to be\r
+ formatted either as one combined message or multiple messages\r
+\r
+- Added code to set log4javascript as a property of the window object. This\r
+ ensures that if log4javascript is loaded via eval() (e.g. Dojo's module\r
+ loading system), the log4javascript object is guaranteed to be available even\r
+ though IE does not evaluate the script in the global scope\r
+\r
+- Added useDocumentWrite parameter to constructors and isUseDocumentWrite()\r
+ and setUseDocumentWrite() methods for InPageAppender and PopUpAppender and\r
+ added console.html to the build so that the appender may use either the\r
+ existing document.write method or the external HTML file to build the console.\r
+ This is to allow support for setting document.domain in the main document,\r
+ which is impossible with the document.write method\r
+\r
+- Added milliseconds property to logging events and changed JsonLayout,\r
+ XmlLayout and HttpPostDataLayout to include milliseconds by default\r
+\r
+- Added layout parameter to AjaxAppender and a toString() method on each layout\r
+\r
+- Setting configuration properties in appenders via constructor paramaters has\r
+ been phased out.\r
+\r
+- Added window.unload handler for AjaxAppender to send outstanding messages.\r
+ Doesn't work in Opera\r
+\r
+- Implemented log4j-style hierarchical loggers with additive appenders. For\r
+ example, a logger called "app.stuff" has as its parent the logger called\r
+ "app", all of whose appenders it inherits\r
+\r
+- Changed XmlLayout and JsonLayout to send data as a key/value pair\r
+\r
+- Bugfix for inaccessible error details\r
+\r
+- An appender can no longer be added more than once to the same logger\r
+\r
+- Multiple messages may now be specified in logger methods\r
+\r
+- New conversion character 'a' added to PatternLayout. This is the same as 'm'\r
+ except that if the first message specified is an array then it treats each\r
+ element of the array as though it had been passed in as a message parameter\r
+\r
+- Command line added to console windows with configurable object expansion\r
+ depth. Command line presence and object expansion depth are configurable in\r
+ the appender via setShowCommandLine() and setCommandLineObjectExpansionDepth()\r
+ methods respectively\r
+\r
+- Command line history, navigated by cursor keys and stored in a session cookie\r
+\r
+- Firebug-inspired command line functions added: $, dir, dirxml, cd, clear,\r
+ keys, values, expansionDepth\r
+\r
+- Fixes for several bugs in object expansion\r
+\r
+- Fix for bug in initialization of InPageAppender in IE 5\r
+\r
+- Fix to allow searchable HTML in log entries\r
+\r
+- Fix for bug which automatically displayed search next/previous buttons when\r
+ the search box is clicked regardless of whether there were any matches\r
+\r
+- Searches in PopUpAppender and InPageAppender now preserve formatting\r
+\r
+- More fixes to interaction of search and severity filters in console window\r
+ used by PopUpAppender and InPageAppender\r
+\r
+- Added SwitchableConsoleAppender that allows flipping from an in-page console\r
+ to a pop-up console window and back again while retaining state\r
+\r
+- Custom events added that are raised when PopUpAppender and InPageAppender\r
+ windows load and unload, and on the main log4javascript object when the main\r
+ page loads, when the main page is resized and when log4javascript errors occur\r
+\r
+- InPageAppender may now be initialized before the page loads by providing an\r
+ element id for its container, or omitting the container altogether (in which\r
+ case the appender is added as a fixed div at the bottom of the page)\r
+\r
+- Tweaked PopUpAppender and InPageAppender so that the formatted log message is\r
+ produced when append() is called rather than when the message is actually sent\r
+ to the console window, thus allowing reliable temporary switching of layouts\r
+\r
+- Much improved scrolling to current search match: scrolls only if part of the\r
+ search match is not visible and centres around it rather than putting flush to\r
+ the top left\r
+\r
+- Removed setReadable() method from JsonLayout - now specified only in the\r
+ constructor\r
+\r
+- Fixed problem in IE where copying selections of log entries would produce two\r
+ copies of each log entry\r
+\r
+\r
+1.3.1 (20/11/2006)\r
+\r
+- Fix to interaction of search and severity filters in console window used by\r
+ PopUpAppender and InPageAppender\r
+\r
+\r
+1.3 (19/10/2006)\r
+\r
+- Fully tested and supported in IE 7 Beta 3\r
+\r
+- Added support for FireBug logging levels in BrowserConsoleAppender\r
+\r
+- Added optional limit to the number of log messages stored by PopUpAppender and\r
+ InPageAppender. When this limit is reached, each new message causes the oldest\r
+ message to be discarded.\r
+\r
+- Exceptions passed into logging methods are now displayed in logging output.\r
+\r
+- Added facility to pass objects as well as strings to logging methods.\r
+ Enhanced conversion character 'm' to PatternLayout to expand object properties\r
+ in the formatted output\r
+\r
+- Added stack trace to error reports (alerts and log entries) in Firefox. This\r
+ is turned off by default but can be switched on via the new\r
+ log4javascript.setShowStackTraces function\r
+\r
+- Added log4javascript_stub.js to distribution - this has stub versions of all\r
+ objects and methods in log4javascript.js and can be used as a lightweight\r
+ replacement for log4javascript.js in production systems\r
+\r
+- Added log4javascript_compressed.js to distribution - comments and whitespace\r
+ are removed, resulting in a 30% smaller file\r
+\r
+- Added custom fields to layouts\r
+\r
+- Added setReopenWhenClosed and isReopenWhenClosed methods to PopUpAppender to\r
+ allow log4javascript to open a new pop-up console window automatically at the\r
+ time of the next log entry after the original window was closed\r
+\r
+- Layout.ignoresThrowable implemented to allow Layout/Appender combinations to\r
+ decide whether to display exceptions\r
+\r
+- Added NullLayout that performs no formatting on the logging event\r
+\r
+- Lowered BrowserConsoleAppender's default threshold to DEBUG and set its\r
+ default layout to NullLayout so that unformatted objects can be passed into\r
+ FireBug\r
+\r
+- Renamed InlineAppender to InPageAppender (though InlineAppender still works\r
+ for the sake of backwards compatibility)\r
+\r
+- Cosmetic changes to InPageAppender and PopUpAppender\r
+\r
+- Added equals() method to Level\r
+\r
+- Added removeAppender() and removeAllAppenders() methods to Logger\r
+\r
+- Added extensive test script\r
+\r
+- Fixed bug where Appender.setLayout and Appender.setThreshold threw an\r
+ unhandled error if not supplied with a genuine Layout or Level respectively\r
+\r
+- Fixed bug where InlinePopUpAppender and PopUpAppender continue to poll their\r
+ console windows indefinitely (thus generating warnings) if the console window\r
+ is closed before it has fully loaded\r
+\r
+- Fixed bug in w and W symbols in SimpleDateFormat\r
+\r
+- Fixed bug with quotes inside messages in JsonLayout\r
+\r
+- Fixed bugs in PatternLayout with built-in DATE format and truncation modifiers\r
+\r
+- Changed execution order of callbacks in AjaxAppender so that\r
+ requestSuccessCallback is guaranteed to be called before the next request is\r
+ sent\r
+\r
+- Changed AjaxAppender so that log messages are formatted immediately before\r
+ a request is sent rather than when append() is called, thus guaranteeing that\r
+ changes to the layout take effect immediately\r
+\r
+- PopUpAppender windows now have unique names per hostname to prevent clashes\r
+ from multiple instances of log4javascript running on different servers\r
+\r
+- Fixed error in XmlLayout's format method when passed an object\r
+\r
+- Fixed errors in JsonLayout's handling of strings containing line breaks and/or\r
+ double quotes\r
+\r
+\r
+1.2 (21/6/2006)\r
+\r
+- Tested in and added workaround for a bug in Opera 9 Beta 2 and Opera 9.0\r
+\r
+- Tested in Konqueror 3.4 and 3.5 and added workarounds and fixes for browser\r
+ bugs\r
+\r
+- Added addErrorListener and removeErrorListener methods to log4javascript\r
+ object to allow custom error handling\r
+\r
+- Added close() method to PopUpAppender and InlineAppender\r
+\r
+- Added test directory with an HTML page containing automated tests\r
+\r
+- Added enable/disable logging checkbox to InlinePopUpAppender and PopUpAppender\r
+ so that unnecessary messages (for instance, from a timer) can be ignored\r
+\r
+- An invalid value supplied to a configuration option setter now leaves config\r
+ property unchanged rather than reverting to the default\r
+\r
+- Fixed bug in PopUpAppender in IE on Windows XP Service Pack 2 when accessed\r
+ via the file system. The browser by default disables JavaScript in the pop-up\r
+ window until the user opts to enable it, at which point they would previously\r
+ see an uncaught error in log4javascript. Now, a proper error message is\r
+ displayed and the appender is disabled.\r
+\r
+- Slight alterations to toolbar in InlineAppender and PopUpAppender - text\r
+ capitalization and title attributes added to inputs\r
+\r
+- toString() method added to all appenders\r
+\r
+- Correction to errors in XmlLayout's output\r
+\r
+- Documentation corrections and additions\r
+\r
+\r
+1.1.1 (17/5/2006)\r
+\r
+- Fixed a minor bug with scrolling to the latest message and added "scroll to\r
+ latest" checkbox to console window in InlineAppender and PopUpAppender\r
+\r
+\r
+1.1 (16/5/2006)\r
+\r
+- Added configuration option setters on Appenders and refactored to prevent\r
+ config properties being altered directly. Several configuration options\r
+ may not be altered after the appender has been initialized\r
+\r
+- Added scrollToLatestMessage constructor parameter, isScrollToLatestMessage\r
+ and setScrollToLatestMessage methods to InlineAppender and PopUpAppender\r
+\r
+- Added isVisible method to InlineAppender\r
+\r
+- Changed setShowOneError to setAlertAllErrors in logLog, with obvious change\r
+ in logic\r
+\r
+- Added layout property key configuration options to layout constructors for\r
+ JsonLayout and HttpPostDataLayout\r
+\r
+- Changed the default timestamp property name to "timestamp" instead of\r
+ "timeStamp" in JsonLayout and HttpPostDataLayout\r
+\r
+- Expanded documentation to include a section in the manual about configuring\r
+ appenders\r
+\r
+- Removed browser sniffing code\r
+\r
+\r
+1.0.1 (30/4/2006)\r
+\r
+- Option to have new log messages appear at the top added to InlineAppender and\r
+ PopUpAppender. This option can be specified in the constructor and can also\r
+ be toggled via a checkbox in the console window\r
+\r
+- PopUpAppender changed to not focus the pop-up console window by default, and\r
+ the demo page altered to create its own logger with focussing turned on,\r
+ meaning the behaviour in the demo is essentially unchanged\r
+\r
+\r
+1.0 (26/4/2006)\r
+\r
+- Tweaks to default values in PopUpAppender and InlineAppender\r
+\r
+- Bugfixes and stylistic tweaks resulting from running JSLint on\r
+ log4javascript.js\r
+\r
+\r
+1.0 beta 2\r
+\r
+- Show/hide button removed from InlineAppender, replaced by show() and hide()\r
+ methods on the InlineAppender object\r
+\r
+- batchSeparator, batchHeader and batchFooter added to Layout and applied to\r
+ JsonLayout - a batch of JSON log messages is now created as an array literal\r
+\r
+\r
+1.0 beta\r
+\r
+- TRACE level added, since this was added to log4j in 1.2.12\r
+\r
+- PopUpAppender default settings bugfix\r
+\r
+- getLevel method added to Logger\r
+\r
+- Tweak to vertical alignment of checkboxes and padding of buttons in\r
+ InlineAppender and PopUpAppender\r
+\r
+- Fixed getDefaultLogger and getNullLogger to return loggers other than the\r
+ root logger\r
+\r
+0.96\r
+\r
+- Moved console.html to inline document.writes in log4javascript.js\r
+\r
+- Fixed getDefaultLogger to return the same object on successive calls\r
+\r
+- Fixed scrolling issue in Opera InlineAppender and PopUpAppender\r
+\r
+- Scrollbars are now automatic on InlineAppender and PopUpAppender, i.e. they\r
+ only appear when required\r
+\r
+- Fixed bug where regex searches were not applied to new log entries in\r
+ InlineAppender and PopUpAppender\r
+\r
+- Changed Safari font size in InlineAppender and PopUpAppender\r
+\r
+0.95\r
+\r
+- AjaxAppender enhancements:\r
+ - waitForResponse added\r
+ - timer added\r
+\r
+- layout parameter added to all appender constructors\r
+\r
+0.94\r
+- First publicly available version\r
+- IE 5 support added\r
+- Full support for wrapping in IE added for InlineAppender and PopUpAppender
\ No newline at end of file
--- /dev/null
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+<head>\r
+<title>log4javascript</title>\r
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\r
+<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->\r
+<meta http-equiv="X-UA-Compatible" content="IE=7" />\r
+<script type="text/javascript">var isIe = false, isIePre7 = false;</script>\r
+<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->\r
+<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->\r
+<script type="text/javascript">\r
+//<![CDATA[\r
+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];}}\r
+function LogItem(){}\r
+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();}\r
+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();}\r
+this.unwrappedElementContainer=null;this.wrappedElementContainer=null;this.mainElementContainer=null;}\r
+if(this.group&&removeFromGroup){this.group.removeChild(this,doUpdate);}\r
+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(){}\r
+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=" ";}\r
+SeparatorElementContainer.prototype=new LogItemContainerElement();SeparatorElementContainer.prototype.remove=function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;};function Separator(){this.rendered=false;}\r
+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];}\r
+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();}};}}\r
+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="+";}\r
+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);}\r
+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;}\r
+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();}\r
+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];}\r
+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);}\r
+this.children=[];this.update();if(this===currentGroup){currentGroup=this.group;}\r
+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);}\r
+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(){}\r
+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;}\r
+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;}\r
+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));}\r
+LogEntryMainElementContainer.prototype=new LogEntryElementContainer();function LogEntry(level,formattedMessage){this.level=level;this.formattedMessage=formattedMessage;this.rendered=false;}\r
+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];}\r
+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");}\r
+for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setContent(content,wrappedContent);}\r
+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]);}}\r
+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(){}\r
+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=[];}\r
+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;}}}\r
+logMainContainer=$("log");if(isIePre7){addClass(logMainContainer,"oldIe");}\r
+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;}\r
+break;case 75:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusSearch();cancelKeyEvent(evt);return false;}\r
+break;case 40:case 76:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusCommandLine();cancelKeyEvent(evt);return false;}\r
+break;}};setTimeout(setLogContainerHeight,20);setShowCommandLine(showCommandLine);doSearch();};window.onunload=function(){if(mainWindowExists()){appender.unload();}\r
+appender=null;};function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}\r
+function setLoggingEnabled(enable){loggingEnabled=enable;}\r
+var appender=null;function setAppender(appenderParam){appender=appenderParam;}\r
+function setShowCloseButton(showCloseButton){$("closeButton").style.display=showCloseButton?"inline":"none";}\r
+function setShowHideButton(showHideButton){$("hideButton").style.display=showHideButton?"inline":"none";}\r
+var newestAtTop=false;function LogItemContentReverser(){}\r
+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;}\r
+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]);}}\r
+currentSearch.matches=matches;if(currentMatch){currentMatch.setCurrent();}}else if(scrollToLatest){doScrollToLatest();}}\r
+$("newestAtTop").checked=isNewestAtTop;}\r
+function toggleNewestAtTop(){var isNewestAtTop=$("newestAtTop").checked;setNewestAtTop(isNewestAtTop);}\r
+var scrollToLatest=true;function setScrollToLatest(isScrollToLatest){scrollToLatest=isScrollToLatest;if(scrollToLatest){doScrollToLatest();}\r
+$("scrollToLatest").checked=isScrollToLatest;}\r
+function toggleScrollToLatest(){var isScrollToLatest=$("scrollToLatest").checked;setScrollToLatest(isScrollToLatest);}\r
+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;}}}}\r
+var closeIfOpenerCloses=true;function setCloseIfOpenerCloses(isCloseIfOpenerCloses){closeIfOpenerCloses=isCloseIfOpenerCloses;}\r
+var maxMessages=null;function setMaxMessages(max){maxMessages=max;pruneLogEntries();}\r
+var showCommandLine=false;function setShowCommandLine(isShowCommandLine){showCommandLine=isShowCommandLine;if(loaded){$("commandLine").style.display=showCommandLine?"block":"none";setCommandInputWidth();setLogContainerHeight();}}\r
+function focusCommandLine(){if(loaded){$("command").focus();}}\r
+function focusSearch(){if(loaded){$("searchBox").focus();}}\r
+function getLogItems(){var items=[];for(var i=0,len=logItems.length;i<len;i++){logItems[i].serialize(items);}\r
+return items;}\r
+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;}}\r
+loggingEnabled=loggingReallyEnabled;}\r
+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);}\r
+logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}\r
+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]);}}}\r
+if(currentSearch){if(pruned){if(currentSearch.hasVisibleMatches()){if(currentMatchIndex===null){setCurrentMatchIndex(0);}\r
+displayMatches();}else{displayNoMatches();}}else if(!initiallyHasMatches&¤tSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}}\r
+if(scrollToLatest){doScrollToLatest();}\r
+unrenderedLogItemsExist=false;}\r
+function pruneLogEntries(){if((maxMessages!==null)&&(logEntriesAndSeparators.length>maxMessages)){var numberToDelete=logEntriesAndSeparators.length-maxMessages;var prunedLogEntries=logEntriesAndSeparators.slice(0,numberToDelete);if(currentSearch){currentSearch.removeMatches(prunedLogEntries);}\r
+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);}}\r
+logEntriesAndSeparators=array_removeFromStart(logEntriesAndSeparators,numberToDelete);return true;}\r
+return false;}\r
+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);}\r
+logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}\r
+function groupEnd(){currentGroup=(currentGroup===rootGroup)?rootGroup:currentGroup.group;}\r
+function mainPageReloaded(){currentGroup=rootGroup;var separator=new Separator();logEntriesAndSeparators.push(separator);logItems.push(separator);currentGroup.addChild(separator);}\r
+function closeWindow(){if(appender&&mainWindowExists()){appender.close(true);}else{window.close();}}\r
+function hide(){if(appender&&mainWindowExists()){appender.hide();}}\r
+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();}}\r
+function pollOpener(){if(closeIfOpenerCloses){if(mainWindowExists()){setTimeout(pollOpener,500);}else{closeWindow();}}}\r
+function mainWindowExists(){try{return(mainWindow&&!mainWindow.closed&&mainWindow[windowId]==window);}catch(ex){}\r
+return false;}\r
+var logLevels=["TRACE","DEBUG","INFO","WARN","ERROR","FATAL"];function getCheckBox(logLevel){return $("switch_"+logLevel);}\r
+function getIeWrappedLogContainer(){return $("log_wrapped");}\r
+function getIeUnwrappedLogContainer(){return $("log_unwrapped");}\r
+function applyFilters(){for(var i=0;i<logLevels.length;i++){if(getCheckBox(logLevels[i]).checked){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}\r
+updateSearchFromFilters();}\r
+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]);}}}\r
+function checkAllLevels(){for(var i=0;i<logLevels.length;i++){if(!getCheckBox(logLevels[i]).checked){getCheckBox("ALL").checked=false;return;}}\r
+getCheckBox("ALL").checked=true;}\r
+function clearLog(){rootGroup.clear();currentGroup=rootGroup;logEntries=[];logItems=[];logEntriesAndSeparators=[];doSearch();}\r
+function toggleWrap(){var enable=$("wrap").checked;if(enable){addClass(logMainContainer,"wrap");}else{removeClass(logMainContainer,"wrap");}\r
+refreshCurrentMatch();}\r
+var searchTimer=null;function scheduleSearch(){try{clearTimeout(searchTimer);}catch(ex){}\r
+searchTimer=setTimeout(doSearch,500);}\r
+function Search(searchTerm,isRegex,searchRegex,isCaseSensitive){this.searchTerm=searchTerm;this.isRegex=isRegex;this.searchRegex=searchRegex;this.isCaseSensitive=isCaseSensitive;this.matches=[];}\r
+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;}}}\r
+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);}\r
+return matchesSearch;},getNextVisibleMatchIndex:function(){for(var i=currentMatchIndex+1;i<this.matches.length;i++){if(this.matches[i].isVisible()){return i;}}\r
+for(i=0;i<=currentMatchIndex;i++){if(this.matches[i].isVisible()){return i;}}\r
+return-1;},getPreviousVisibleMatchIndex:function(){for(var i=currentMatchIndex-1;i>=0;i--){if(this.matches[i].isVisible()){return i;}}\r
+for(var i=this.matches.length-1;i>=currentMatchIndex;i--){if(this.matches[i].isVisible()){return i;}}\r
+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+\r
+preEndTag+searchTermReplacementEndTag;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+\r
+matchedText+searchTermReplacementEndTag;}\r
+startIndex=endTokenIndex+endToken.length;}\r
+logEntryContent+=preStartTag+searchString.substr(startIndex)+preEndTag;if(isIe){wrappedLogEntryContent+=searchString.substr(startIndex);}}else{logEntryContent="";wrappedLogEntryContent="";var searchTermReplacementLength=searchTermReplacementStartTag.length+\r
+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+\r
+preStartTag+matchedText+preEndTag+searchTermReplacementEndTag;logEntryContent+=preStartTag+textBeforeMatch+preEndTag+searchTermReplacement;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+\r
+matchedText+searchTermReplacementEndTag;}\r
+startIndex=searchIndex+searchTermLength;}\r
+var textAfterLastMatch=escapeHtml(logEntry.formattedMessage.substr(startIndex));logEntryContent+=preStartTag+textAfterLastMatch+preEndTag;if(isIe){wrappedLogEntryContent+=textAfterLastMatch;}}\r
+logEntry.setContent(logEntryContent,wrappedLogEntryContent);var logEntryMatches=logEntry.getSearchMatches();this.matches=this.matches.concat(logEntryMatches);}else{logEntry.setSearchMatch(false);logEntry.setContent(logEntry.formattedMessage,logEntry.formattedMessage);}\r
+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;}}}}\r
+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;}}}\r
+for(i=0,iLen=matchesToRemove.length;i<iLen;i++){array_remove(this.matches,matchesToRemove[i]);matchesToRemove[i].remove();}\r
+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;}}\r
+setCurrentMatchIndex(newMatchIndex);}}else{currentMatchIndex=null;displayNoMatches();}}};function getPageOffsetTop(el,container){var currentEl=el;var y=0;while(currentEl&¤tEl!=container){y+=currentEl.offsetTop;currentEl=currentEl.offsetParent;}\r
+return y;}\r
+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;}}\r
+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;}}\r
+function Match(logEntryLevel,spanInMainDiv,spanInUnwrappedPre,spanInWrappedDiv){this.logEntryLevel=logEntryLevel;this.spanInMainDiv=spanInMainDiv;if(isIe){this.spanInUnwrappedPre=spanInUnwrappedPre;this.spanInWrappedDiv=spanInWrappedDiv;}\r
+this.mainSpan=isIe?spanInUnwrappedPre:spanInMainDiv;}\r
+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);}\r
+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");}\r
+addClass(document.body,"searching");currentSearch=new Search(searchTerm,isRegex,searchRegex,isCaseSensitive);for(i=0;i<logEntries.length;i++){currentSearch.applyTo(logEntries[i]);}\r
+setLogContainerHeight();if(currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}else{displayNoMatches();}}}\r
+function updateSearchFromFilters(){if(currentSearch){if(currentSearch.hasMatches()){if(currentMatchIndex===null){currentMatchIndex=0;}\r
+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();}}}\r
+function refreshCurrentMatch(){if(currentSearch&¤tSearch.hasVisibleMatches()){setCurrentMatchIndex(currentMatchIndex);}}\r
+function displayMatches(){replaceClass($("searchBox"),"hasmatches","nomatches");$("searchBox").title=""+currentSearch.matches.length+" matches found";$("searchNav").style.display="block";setLogContainerHeight();}\r
+function displayNoMatches(){replaceClass($("searchBox"),"nomatches","hasmatches");$("searchBox").title="No matches found";$("searchNav").style.display="none";setLogContainerHeight();}\r
+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!=="")&¤tSearch&¤tSearch.hasVisibleMatches())?"block":"none";if(enable){removeClass($("search"),"greyedout");addClass(document.body,"searching");if($("searchHighlight").checked){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}\r
+if($("searchFilter").checked){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}\r
+$("searchDisable").checked=!enable;}else{addClass($("search"),"greyedout");removeClass(document.body,"searching");removeClass(logMainContainer,"searchhighlight");removeClass(logMainContainer,"searchfilter");}\r
+setLogContainerHeight();}\r
+function toggleSearchFilter(){var enable=$("searchFilter").checked;if(enable){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}\r
+refreshCurrentMatch();}\r
+function toggleSearchHighlight(){var enable=$("searchHighlight").checked;if(enable){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}}\r
+function clearSearch(){$("searchBox").value="";doSearch();}\r
+function searchNext(){if(currentSearch!==null&¤tMatchIndex!==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);}}}\r
+function searchPrevious(){if(currentSearch!==null&¤tMatchIndex!==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);}}}\r
+function setCurrentMatchIndex(index){currentMatchIndex=index;currentSearch.matches[currentMatchIndex].setCurrent();}\r
+function addClass(el,cssClass){if(!hasClass(el,cssClass)){if(el.className){el.className+=" "+cssClass;}else{el.className=cssClass;}}}\r
+function hasClass(el,cssClass){if(el.className){var classNames=el.className.split(" ");return array_contains(classNames,cssClass);}\r
+return false;}\r
+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];}}\r
+el.className=newClasses.join(" ");}}\r
+function replaceClass(el,newCssClass,oldCssClass){removeClass(el,oldCssClass);addClass(el,newCssClass);}\r
+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]);}}\r
+return matches;}\r
+function $(id){return document.getElementById(id);}\r
+function isDescendant(node,ancestorNode){while(node!=null){if(node===ancestorNode){return true;}\r
+node=node.parentNode;}\r
+return false;}\r
+function isOrphan(node){var currentNode=node;while(currentNode){if(currentNode==document.body){return false;}\r
+currentNode=currentNode.parentNode;}\r
+return true;}\r
+function escapeHtml(str){return str.replace(/&/g,"&").replace(/[<]/g,"<").replace(/>/g,">");}\r
+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;}\r
+return 0;}\r
+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;}\r
+return 0;}\r
+function getToolBarsHeight(){return $("switches").offsetHeight;}\r
+function getChromeHeight(){var height=getToolBarsHeight();if(showCommandLine){height+=$("commandLine").offsetHeight;}\r
+return height;}\r
+function setLogContainerHeight(){if(logMainContainer){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";logMainContainer.style.height=""+\r
+Math.max(0,windowHeight-getChromeHeight())+"px";}}\r
+function setCommandInputWidth(){if(showCommandLine){$("command").style.width=""+Math.max(0,$("commandLineContainer").offsetWidth-\r
+($("evaluateButton").offsetWidth+13))+"px";}}\r
+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];}\r
+return this.length;};}\r
+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;}};}\r
+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];}\r
+this.length=this.length-1;return firstItem;}};}\r
+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];}\r
+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]);}\r
+return itemsDeleted;};}\r
+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;}}\r
+if(index>=0){arr.splice(index,1);return index;}else{return false;}}\r
+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];}\r
+array.length=array.length-numberToRemove;}\r
+return array;}\r
+function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}\r
+return false;}\r
+function getErrorMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}\r
+return""+ex;}\r
+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();}\r
+input.focus();}\r
+function stopPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}}\r
+function getEvent(evt){return evt?evt:event;}\r
+function getTarget(evt){return evt.target?evt.target:evt.srcElement;}\r
+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;}}}\r
+function cancelKeyEvent(evt){evt.returnValue=false;stopPropagation(evt);}\r
+function evalCommandLine(){var expr=$("command").value;evalCommand(expr);$("command").value="";}\r
+function evalLastCommand(){if(lastCommand!=null){evalCommand(lastCommand);}}\r
+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));}}\r
+if(expr!=commandHistory[commandHistory.length-1]){commandHistory.push(expr);if(appender){appender.storeCommandHistory(commandHistory);}}\r
+currentCommandIndex=(expr==commandHistory[currentCommandIndex])?currentCommandIndex+1:commandHistory.length;lastCommand=expr;}\r
+//]]>\r
+</script>\r
+<style type="text/css">\r
+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}\r
+</style>\r
+</head>\r
+<body id="body">\r
+<div id="switchesContainer">\r
+<div id="switches">\r
+<div id="levels" class="toolbar">\r
+Filters:\r
+<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>\r
+<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>\r
+<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>\r
+<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>\r
+<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>\r
+<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>\r
+<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>\r
+</div>\r
+<div id="search" class="toolbar">\r
+<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />\r
+<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />\r
+<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>\r
+<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>\r
+<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>\r
+<div id="searchNav">\r
+<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />\r
+<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />\r
+<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>\r
+<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>\r
+</div>\r
+</div>\r
+<div id="options" class="toolbar">\r
+Options:\r
+<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>\r
+<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>\r
+<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>\r
+<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>\r
+<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages" />\r
+<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />\r
+<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />\r
+</div>\r
+</div>\r
+</div>\r
+<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>\r
+<div id="commandLine" class="toolbar">\r
+<div id="commandLineContainer">\r
+<input type="text" id="command" title="Enter a JavaScript command here and hit return or press 'Evaluate'" />\r
+<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />\r
+</div>\r
+</div>\r
+</body>\r
+</html>\r
--- /dev/null
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript</title>\r
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\r
+ <!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->\r
+ <meta http-equiv="X-UA-Compatible" content="IE=7" />\r
+ <script type="text/javascript">var isIe = false, isIePre7 = false;</script>\r
+ <!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->\r
+ <!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->\r
+ <script type="text/javascript">\r
+ //<![CDATA[\r
+ var loggingEnabled = true;\r
+ var logQueuedEventsTimer = null;\r
+ var logEntries = [];\r
+ var logEntriesAndSeparators = [];\r
+ var logItems = [];\r
+ var renderDelay = 100;\r
+ var unrenderedLogItemsExist = false;\r
+ var rootGroup, currentGroup = null;\r
+ var loaded = false;\r
+ var currentLogItem = null;\r
+ var logMainContainer;\r
+\r
+ function copyProperties(obj, props) {\r
+ for (var i in props) {\r
+ obj[i] = props[i];\r
+ }\r
+ }\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function LogItem() {\r
+ }\r
+\r
+ LogItem.prototype = {\r
+ mainContainer: null,\r
+ wrappedContainer: null,\r
+ unwrappedContainer: null,\r
+ group: null,\r
+\r
+ appendToLog: function() {\r
+ for (var i = 0, len = this.elementContainers.length; i < len; i++) {\r
+ this.elementContainers[i].appendToLog();\r
+ }\r
+ this.group.update();\r
+ },\r
+\r
+ doRemove: function(doUpdate, removeFromGroup) {\r
+ if (this.rendered) {\r
+ for (var i = 0, len = this.elementContainers.length; i < len; i++) {\r
+ this.elementContainers[i].remove();\r
+ }\r
+ this.unwrappedElementContainer = null;\r
+ this.wrappedElementContainer = null;\r
+ this.mainElementContainer = null;\r
+ }\r
+ if (this.group && removeFromGroup) {\r
+ this.group.removeChild(this, doUpdate);\r
+ }\r
+ if (this === currentLogItem) {\r
+ currentLogItem = null;\r
+ }\r
+ },\r
+\r
+ remove: function(doUpdate, removeFromGroup) {\r
+ this.doRemove(doUpdate, removeFromGroup);\r
+ },\r
+\r
+ render: function() {},\r
+\r
+ accept: function(visitor) {\r
+ visitor.visit(this);\r
+ },\r
+\r
+ getUnwrappedDomContainer: function() {\r
+ return this.group.unwrappedElementContainer.contentDiv;\r
+ },\r
+\r
+ getWrappedDomContainer: function() {\r
+ return this.group.wrappedElementContainer.contentDiv;\r
+ },\r
+\r
+ getMainDomContainer: function() {\r
+ return this.group.mainElementContainer.contentDiv;\r
+ }\r
+ };\r
+\r
+ LogItem.serializedItemKeys = {LOG_ENTRY: 0, GROUP_START: 1, GROUP_END: 2};\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function LogItemContainerElement() {\r
+ }\r
+\r
+ LogItemContainerElement.prototype = {\r
+ appendToLog: function() {\r
+ var insertBeforeFirst = (newestAtTop && this.containerDomNode.hasChildNodes());\r
+ if (insertBeforeFirst) {\r
+ this.containerDomNode.insertBefore(this.mainDiv, this.containerDomNode.firstChild);\r
+ } else {\r
+ this.containerDomNode.appendChild(this.mainDiv);\r
+ }\r
+ }\r
+ };\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function SeparatorElementContainer(containerDomNode) {\r
+ this.containerDomNode = containerDomNode;\r
+ this.mainDiv = document.createElement("div");\r
+ this.mainDiv.className = "separator";\r
+ this.mainDiv.innerHTML = " ";\r
+ }\r
+\r
+ SeparatorElementContainer.prototype = new LogItemContainerElement();\r
+\r
+ SeparatorElementContainer.prototype.remove = function() {\r
+ this.mainDiv.parentNode.removeChild(this.mainDiv);\r
+ this.mainDiv = null;\r
+ };\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function Separator() {\r
+ this.rendered = false;\r
+ }\r
+\r
+ Separator.prototype = new LogItem();\r
+\r
+ copyProperties(Separator.prototype, {\r
+ render: function() {\r
+ var containerDomNode = this.group.contentDiv;\r
+ if (isIe) {\r
+ this.unwrappedElementContainer = new SeparatorElementContainer(this.getUnwrappedDomContainer());\r
+ this.wrappedElementContainer = new SeparatorElementContainer(this.getWrappedDomContainer());\r
+ this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];\r
+ } else {\r
+ this.mainElementContainer = new SeparatorElementContainer(this.getMainDomContainer());\r
+ this.elementContainers = [this.mainElementContainer];\r
+ }\r
+ this.content = this.formattedMessage;\r
+ this.rendered = true;\r
+ }\r
+ });\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function GroupElementContainer(group, containerDomNode, isRoot, isWrapped) {\r
+ this.group = group;\r
+ this.containerDomNode = containerDomNode;\r
+ this.isRoot = isRoot;\r
+ this.isWrapped = isWrapped;\r
+ this.expandable = false;\r
+\r
+ if (this.isRoot) {\r
+ if (isIe) {\r
+ this.contentDiv = logMainContainer.appendChild(document.createElement("div"));\r
+ this.contentDiv.id = this.isWrapped ? "log_wrapped" : "log_unwrapped";\r
+ } else {\r
+ this.contentDiv = logMainContainer;\r
+ }\r
+ } else {\r
+ var groupElementContainer = this;\r
+ \r
+ this.mainDiv = document.createElement("div");\r
+ this.mainDiv.className = "group";\r
+\r
+ this.headingDiv = this.mainDiv.appendChild(document.createElement("div"));\r
+ this.headingDiv.className = "groupheading";\r
+\r
+ this.expander = this.headingDiv.appendChild(document.createElement("span"));\r
+ this.expander.className = "expander unselectable greyedout";\r
+ this.expander.unselectable = true;\r
+ var expanderText = this.group.expanded ? "-" : "+";\r
+ this.expanderTextNode = this.expander.appendChild(document.createTextNode(expanderText));\r
+ \r
+ this.headingDiv.appendChild(document.createTextNode(" " + this.group.name));\r
+\r
+ this.contentDiv = this.mainDiv.appendChild(document.createElement("div"));\r
+ var contentCssClass = this.group.expanded ? "expanded" : "collapsed";\r
+ this.contentDiv.className = "groupcontent " + contentCssClass;\r
+\r
+ this.expander.onclick = function() {\r
+ if (groupElementContainer.group.expandable) {\r
+ groupElementContainer.group.toggleExpanded();\r
+ }\r
+ };\r
+ }\r
+ }\r
+\r
+ GroupElementContainer.prototype = new LogItemContainerElement();\r
+\r
+ copyProperties(GroupElementContainer.prototype, {\r
+ toggleExpanded: function() {\r
+ if (!this.isRoot) {\r
+ var oldCssClass, newCssClass, expanderText;\r
+ if (this.group.expanded) {\r
+ newCssClass = "expanded";\r
+ oldCssClass = "collapsed";\r
+ expanderText = "-";\r
+ } else {\r
+ newCssClass = "collapsed";\r
+ oldCssClass = "expanded";\r
+ expanderText = "+";\r
+ }\r
+ replaceClass(this.contentDiv, newCssClass, oldCssClass);\r
+ this.expanderTextNode.nodeValue = expanderText;\r
+ }\r
+ },\r
+\r
+ remove: function() {\r
+ if (!this.isRoot) {\r
+ this.headingDiv = null;\r
+ this.expander.onclick = null;\r
+ this.expander = null;\r
+ this.expanderTextNode = null;\r
+ this.contentDiv = null;\r
+ this.containerDomNode = null;\r
+ this.mainDiv.parentNode.removeChild(this.mainDiv);\r
+ this.mainDiv = null;\r
+ }\r
+ },\r
+\r
+ reverseChildren: function() {\r
+ // Invert the order of the log entries\r
+ var node = null;\r
+\r
+ // Remove all the log container nodes\r
+ var childDomNodes = [];\r
+ while ((node = this.contentDiv.firstChild)) {\r
+ this.contentDiv.removeChild(node);\r
+ childDomNodes.push(node);\r
+ }\r
+\r
+ // Put them all back in reverse order\r
+ while ((node = childDomNodes.pop())) {\r
+ this.contentDiv.appendChild(node);\r
+ }\r
+ },\r
+\r
+ update: function() {\r
+ if (!this.isRoot) {\r
+ if (this.group.expandable) {\r
+ removeClass(this.expander, "greyedout");\r
+ } else {\r
+ addClass(this.expander, "greyedout");\r
+ }\r
+ }\r
+ },\r
+\r
+ clear: function() {\r
+ if (this.isRoot) {\r
+ this.contentDiv.innerHTML = "";\r
+ }\r
+ }\r
+ });\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function Group(name, isRoot, initiallyExpanded) {\r
+ this.name = name;\r
+ this.group = null;\r
+ this.isRoot = isRoot;\r
+ this.initiallyExpanded = initiallyExpanded;\r
+ this.elementContainers = [];\r
+ this.children = [];\r
+ this.expanded = initiallyExpanded;\r
+ this.rendered = false;\r
+ this.expandable = false;\r
+ }\r
+\r
+ Group.prototype = new LogItem();\r
+\r
+ copyProperties(Group.prototype, {\r
+ addChild: function(logItem) {\r
+ this.children.push(logItem);\r
+ logItem.group = this;\r
+ },\r
+\r
+ render: function() {\r
+ if (isIe) {\r
+ var unwrappedDomContainer, wrappedDomContainer;\r
+ if (this.isRoot) {\r
+ unwrappedDomContainer = logMainContainer;\r
+ wrappedDomContainer = logMainContainer;\r
+ } else {\r
+ unwrappedDomContainer = this.getUnwrappedDomContainer();\r
+ wrappedDomContainer = this.getWrappedDomContainer();\r
+ }\r
+ this.unwrappedElementContainer = new GroupElementContainer(this, unwrappedDomContainer, this.isRoot, false);\r
+ this.wrappedElementContainer = new GroupElementContainer(this, wrappedDomContainer, this.isRoot, true);\r
+ this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];\r
+ } else {\r
+ var mainDomContainer = this.isRoot ? logMainContainer : this.getMainDomContainer();\r
+ this.mainElementContainer = new GroupElementContainer(this, mainDomContainer, this.isRoot, false);\r
+ this.elementContainers = [this.mainElementContainer];\r
+ }\r
+ this.rendered = true;\r
+ },\r
+\r
+ toggleExpanded: function() {\r
+ this.expanded = !this.expanded;\r
+ for (var i = 0, len = this.elementContainers.length; i < len; i++) {\r
+ this.elementContainers[i].toggleExpanded();\r
+ }\r
+ },\r
+\r
+ expand: function() {\r
+ if (!this.expanded) {\r
+ this.toggleExpanded();\r
+ }\r
+ },\r
+\r
+ accept: function(visitor) {\r
+ visitor.visitGroup(this);\r
+ },\r
+\r
+ reverseChildren: function() {\r
+ if (this.rendered) {\r
+ for (var i = 0, len = this.elementContainers.length; i < len; i++) {\r
+ this.elementContainers[i].reverseChildren();\r
+ }\r
+ }\r
+ },\r
+\r
+ update: function() {\r
+ var previouslyExpandable = this.expandable;\r
+ this.expandable = (this.children.length !== 0);\r
+ if (this.expandable !== previouslyExpandable) {\r
+ for (var i = 0, len = this.elementContainers.length; i < len; i++) {\r
+ this.elementContainers[i].update();\r
+ }\r
+ }\r
+ },\r
+\r
+ flatten: function() {\r
+ var visitor = new GroupFlattener();\r
+ this.accept(visitor);\r
+ return visitor.logEntriesAndSeparators;\r
+ },\r
+\r
+ removeChild: function(child, doUpdate) {\r
+ array_remove(this.children, child);\r
+ child.group = null;\r
+ if (doUpdate) {\r
+ this.update();\r
+ }\r
+ },\r
+\r
+ remove: function(doUpdate, removeFromGroup) {\r
+ for (var i = 0, len = this.children.length; i < len; i++) {\r
+ this.children[i].remove(false, false);\r
+ }\r
+ this.children = [];\r
+ this.update();\r
+ if (this === currentGroup) {\r
+ currentGroup = this.group;\r
+ }\r
+ this.doRemove(doUpdate, removeFromGroup);\r
+ },\r
+\r
+ serialize: function(items) {\r
+ items.push([LogItem.serializedItemKeys.GROUP_START, this.name]);\r
+ for (var i = 0, len = this.children.length; i < len; i++) {\r
+ this.children[i].serialize(items);\r
+ }\r
+ if (this !== currentGroup) {\r
+ items.push([LogItem.serializedItemKeys.GROUP_END]);\r
+ }\r
+ },\r
+\r
+ clear: function() {\r
+ for (var i = 0, len = this.elementContainers.length; i < len; i++) {\r
+ this.elementContainers[i].clear();\r
+ }\r
+ }\r
+ });\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function LogEntryElementContainer() {\r
+ }\r
+\r
+ LogEntryElementContainer.prototype = new LogItemContainerElement();\r
+\r
+ copyProperties(LogEntryElementContainer.prototype, {\r
+ remove: function() {\r
+ this.doRemove();\r
+ },\r
+\r
+ doRemove: function() {\r
+ this.mainDiv.parentNode.removeChild(this.mainDiv);\r
+ this.mainDiv = null;\r
+ this.contentElement = null;\r
+ this.containerDomNode = null;\r
+ },\r
+\r
+ setContent: function(content, wrappedContent) {\r
+ if (content === this.formattedMessage) {\r
+ this.contentElement.innerHTML = "";\r
+ this.contentElement.appendChild(document.createTextNode(this.formattedMessage));\r
+ } else {\r
+ this.contentElement.innerHTML = content;\r
+ }\r
+ },\r
+\r
+ setSearchMatch: function(isMatch) {\r
+ var oldCssClass = isMatch ? "searchnonmatch" : "searchmatch";\r
+ var newCssClass = isMatch ? "searchmatch" : "searchnonmatch";\r
+ replaceClass(this.mainDiv, newCssClass, oldCssClass);\r
+ },\r
+\r
+ clearSearch: function() {\r
+ removeClass(this.mainDiv, "searchmatch");\r
+ removeClass(this.mainDiv, "searchnonmatch");\r
+ }\r
+ });\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function LogEntryWrappedElementContainer(logEntry, containerDomNode) {\r
+ this.logEntry = logEntry;\r
+ this.containerDomNode = containerDomNode;\r
+ this.mainDiv = document.createElement("div");\r
+ this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));\r
+ this.mainDiv.className = "logentry wrapped " + this.logEntry.level;\r
+ this.contentElement = this.mainDiv;\r
+ }\r
+\r
+ LogEntryWrappedElementContainer.prototype = new LogEntryElementContainer();\r
+\r
+ LogEntryWrappedElementContainer.prototype.setContent = function(content, wrappedContent) {\r
+ if (content === this.formattedMessage) {\r
+ this.contentElement.innerHTML = "";\r
+ this.contentElement.appendChild(document.createTextNode(this.formattedMessage));\r
+ } else {\r
+ this.contentElement.innerHTML = wrappedContent;\r
+ }\r
+ };\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function LogEntryUnwrappedElementContainer(logEntry, containerDomNode) {\r
+ this.logEntry = logEntry;\r
+ this.containerDomNode = containerDomNode;\r
+ this.mainDiv = document.createElement("div");\r
+ this.mainDiv.className = "logentry unwrapped " + this.logEntry.level;\r
+ this.pre = this.mainDiv.appendChild(document.createElement("pre"));\r
+ this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));\r
+ this.pre.className = "unwrapped";\r
+ this.contentElement = this.pre;\r
+ }\r
+\r
+ LogEntryUnwrappedElementContainer.prototype = new LogEntryElementContainer();\r
+\r
+ LogEntryUnwrappedElementContainer.prototype.remove = function() {\r
+ this.doRemove();\r
+ this.pre = null;\r
+ };\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function LogEntryMainElementContainer(logEntry, containerDomNode) {\r
+ this.logEntry = logEntry;\r
+ this.containerDomNode = containerDomNode;\r
+ this.mainDiv = document.createElement("div");\r
+ this.mainDiv.className = "logentry nonielogentry " + this.logEntry.level;\r
+ this.contentElement = this.mainDiv.appendChild(document.createElement("span"));\r
+ this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));\r
+ }\r
+\r
+ LogEntryMainElementContainer.prototype = new LogEntryElementContainer();\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function LogEntry(level, formattedMessage) {\r
+ this.level = level;\r
+ this.formattedMessage = formattedMessage;\r
+ this.rendered = false;\r
+ }\r
+\r
+ LogEntry.prototype = new LogItem();\r
+\r
+ copyProperties(LogEntry.prototype, {\r
+ render: function() {\r
+ var logEntry = this;\r
+ var containerDomNode = this.group.contentDiv;\r
+\r
+ // Support for the CSS attribute white-space in IE for Windows is\r
+ // non-existent pre version 6 and slightly odd in 6, so instead\r
+ // use two different HTML elements\r
+ if (isIe) {\r
+ this.formattedMessage = this.formattedMessage.replace(/\r\n/g, "\r"); // Workaround for IE's treatment of white space\r
+ this.unwrappedElementContainer = new LogEntryUnwrappedElementContainer(this, this.getUnwrappedDomContainer());\r
+ this.wrappedElementContainer = new LogEntryWrappedElementContainer(this, this.getWrappedDomContainer());\r
+ this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];\r
+ } else {\r
+ this.mainElementContainer = new LogEntryMainElementContainer(this, this.getMainDomContainer());\r
+ this.elementContainers = [this.mainElementContainer];\r
+ }\r
+ this.content = this.formattedMessage;\r
+ this.rendered = true;\r
+ },\r
+\r
+ setContent: function(content, wrappedContent) {\r
+ if (content != this.content) {\r
+ if (isIe && (content !== this.formattedMessage)) {\r
+ content = content.replace(/\r\n/g, "\r"); // Workaround for IE's treatment of white space\r
+ }\r
+ for (var i = 0, len = this.elementContainers.length; i < len; i++) {\r
+ this.elementContainers[i].setContent(content, wrappedContent);\r
+ }\r
+ this.content = content;\r
+ }\r
+ },\r
+\r
+ getSearchMatches: function() {\r
+ var matches = [];\r
+ var i, len;\r
+ if (isIe) {\r
+ var unwrappedEls = getElementsByClass(this.unwrappedElementContainer.mainDiv, "searchterm", "span");\r
+ var wrappedEls = getElementsByClass(this.wrappedElementContainer.mainDiv, "searchterm", "span");\r
+ for (i = 0, len = unwrappedEls.length; i < len; i++) {\r
+ matches[i] = new Match(this.level, null, unwrappedEls[i], wrappedEls[i]);\r
+ }\r
+ } else {\r
+ var els = getElementsByClass(this.mainElementContainer.mainDiv, "searchterm", "span");\r
+ for (i = 0, len = els.length; i < len; i++) {\r
+ matches[i] = new Match(this.level, els[i]);\r
+ }\r
+ }\r
+ return matches;\r
+ },\r
+\r
+ setSearchMatch: function(isMatch) {\r
+ for (var i = 0, len = this.elementContainers.length; i < len; i++) {\r
+ this.elementContainers[i].setSearchMatch(isMatch);\r
+ }\r
+ },\r
+\r
+ clearSearch: function() {\r
+ for (var i = 0, len = this.elementContainers.length; i < len; i++) {\r
+ this.elementContainers[i].clearSearch();\r
+ }\r
+ },\r
+\r
+ accept: function(visitor) {\r
+ visitor.visitLogEntry(this);\r
+ },\r
+\r
+ serialize: function(items) {\r
+ items.push([LogItem.serializedItemKeys.LOG_ENTRY, this.level, this.formattedMessage]);\r
+ }\r
+ });\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function LogItemVisitor() {\r
+ }\r
+\r
+ LogItemVisitor.prototype = {\r
+ visit: function(logItem) {\r
+ },\r
+\r
+ visitParent: function(logItem) {\r
+ if (logItem.group) {\r
+ logItem.group.accept(this);\r
+ }\r
+ },\r
+\r
+ visitChildren: function(logItem) {\r
+ for (var i = 0, len = logItem.children.length; i < len; i++) {\r
+ logItem.children[i].accept(this);\r
+ }\r
+ },\r
+\r
+ visitLogEntry: function(logEntry) {\r
+ this.visit(logEntry);\r
+ },\r
+\r
+ visitSeparator: function(separator) {\r
+ this.visit(separator);\r
+ },\r
+\r
+ visitGroup: function(group) {\r
+ this.visit(group);\r
+ }\r
+ };\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function GroupFlattener() {\r
+ this.logEntriesAndSeparators = [];\r
+ }\r
+\r
+ GroupFlattener.prototype = new LogItemVisitor();\r
+\r
+ GroupFlattener.prototype.visitGroup = function(group) {\r
+ this.visitChildren(group);\r
+ };\r
+\r
+ GroupFlattener.prototype.visitLogEntry = function(logEntry) {\r
+ this.logEntriesAndSeparators.push(logEntry);\r
+ };\r
+\r
+ GroupFlattener.prototype.visitSeparator = function(separator) {\r
+ this.logEntriesAndSeparators.push(separator);\r
+ };\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ window.onload = function() {\r
+ // Sort out document.domain\r
+ if (location.search) {\r
+ var queryBits = unescape(location.search).substr(1).split("&"), nameValueBits;\r
+ for (var i = 0, len = queryBits.length; i < len; i++) {\r
+ nameValueBits = queryBits[i].split("=");\r
+ if (nameValueBits[0] == "log4javascript_domain") {\r
+ document.domain = nameValueBits[1];\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ // Create DOM objects\r
+ logMainContainer = $("log");\r
+ if (isIePre7) {\r
+ addClass(logMainContainer, "oldIe");\r
+ }\r
+\r
+ rootGroup = new Group("root", true);\r
+ rootGroup.render();\r
+ currentGroup = rootGroup;\r
+ \r
+ setCommandInputWidth();\r
+ setLogContainerHeight();\r
+ toggleLoggingEnabled();\r
+ toggleSearchEnabled();\r
+ toggleSearchFilter();\r
+ toggleSearchHighlight();\r
+ applyFilters();\r
+ checkAllLevels();\r
+ toggleWrap();\r
+ toggleNewestAtTop();\r
+ toggleScrollToLatest();\r
+ renderQueuedLogItems();\r
+ loaded = true;\r
+ $("command").value = "";\r
+ $("command").autocomplete = "off";\r
+ $("command").onkeydown = function(evt) {\r
+ evt = getEvent(evt);\r
+ if (evt.keyCode == 10 || evt.keyCode == 13) { // Return/Enter\r
+ evalCommandLine();\r
+ stopPropagation(evt);\r
+ } else if (evt.keyCode == 27) { // Escape\r
+ this.value = "";\r
+ this.focus();\r
+ } else if (evt.keyCode == 38 && commandHistory.length > 0) { // Up\r
+ currentCommandIndex = Math.max(0, currentCommandIndex - 1);\r
+ this.value = commandHistory[currentCommandIndex];\r
+ moveCaretToEnd(this);\r
+ } else if (evt.keyCode == 40 && commandHistory.length > 0) { // Down\r
+ currentCommandIndex = Math.min(commandHistory.length - 1, currentCommandIndex + 1);\r
+ this.value = commandHistory[currentCommandIndex];\r
+ moveCaretToEnd(this);\r
+ }\r
+ };\r
+\r
+ // Prevent the keypress moving the caret in Firefox\r
+ $("command").onkeypress = function(evt) {\r
+ evt = getEvent(evt);\r
+ if (evt.keyCode == 38 && commandHistory.length > 0 && evt.preventDefault) { // Up\r
+ evt.preventDefault();\r
+ }\r
+ };\r
+\r
+ // Prevent the keyup event blurring the input in Opera\r
+ $("command").onkeyup = function(evt) {\r
+ evt = getEvent(evt);\r
+ if (evt.keyCode == 27 && evt.preventDefault) { // Up\r
+ evt.preventDefault();\r
+ this.focus();\r
+ }\r
+ };\r
+\r
+ // Add document keyboard shortcuts\r
+ document.onkeydown = function keyEventHandler(evt) {\r
+ evt = getEvent(evt);\r
+ switch (evt.keyCode) {\r
+ case 69: // Ctrl + shift + E: re-execute last command\r
+ if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {\r
+ evalLastCommand();\r
+ cancelKeyEvent(evt);\r
+ return false;\r
+ }\r
+ break;\r
+ case 75: // Ctrl + shift + K: focus search\r
+ if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {\r
+ focusSearch();\r
+ cancelKeyEvent(evt);\r
+ return false;\r
+ }\r
+ break;\r
+ case 40: // Ctrl + shift + down arrow: focus command line\r
+ case 76: // Ctrl + shift + L: focus command line\r
+ if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {\r
+ focusCommandLine();\r
+ cancelKeyEvent(evt);\r
+ return false;\r
+ }\r
+ break;\r
+ }\r
+ };\r
+\r
+ // Workaround to make sure log div starts at the correct size\r
+ setTimeout(setLogContainerHeight, 20);\r
+\r
+ setShowCommandLine(showCommandLine);\r
+ doSearch();\r
+ };\r
+\r
+ window.onunload = function() {\r
+ if (mainWindowExists()) {\r
+ appender.unload();\r
+ }\r
+ appender = null;\r
+ };\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function toggleLoggingEnabled() {\r
+ setLoggingEnabled($("enableLogging").checked);\r
+ }\r
+\r
+ function setLoggingEnabled(enable) {\r
+ loggingEnabled = enable;\r
+ }\r
+\r
+ var appender = null;\r
+\r
+ function setAppender(appenderParam) {\r
+ appender = appenderParam;\r
+ }\r
+\r
+ function setShowCloseButton(showCloseButton) {\r
+ $("closeButton").style.display = showCloseButton ? "inline" : "none";\r
+ }\r
+\r
+ function setShowHideButton(showHideButton) {\r
+ $("hideButton").style.display = showHideButton ? "inline" : "none";\r
+ }\r
+\r
+ var newestAtTop = false;\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function LogItemContentReverser() {\r
+ }\r
+ \r
+ LogItemContentReverser.prototype = new LogItemVisitor();\r
+ \r
+ LogItemContentReverser.prototype.visitGroup = function(group) {\r
+ group.reverseChildren();\r
+ this.visitChildren(group);\r
+ };\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function setNewestAtTop(isNewestAtTop) {\r
+ var oldNewestAtTop = newestAtTop;\r
+ var i, iLen, j, jLen;\r
+ newestAtTop = Boolean(isNewestAtTop);\r
+ if (oldNewestAtTop != newestAtTop) {\r
+ var visitor = new LogItemContentReverser();\r
+ rootGroup.accept(visitor);\r
+\r
+ // Reassemble the matches array\r
+ if (currentSearch) {\r
+ var currentMatch = currentSearch.matches[currentMatchIndex];\r
+ var matchIndex = 0;\r
+ var matches = [];\r
+ var actOnLogEntry = function(logEntry) {\r
+ var logEntryMatches = logEntry.getSearchMatches();\r
+ for (j = 0, jLen = logEntryMatches.length; j < jLen; j++) {\r
+ matches[matchIndex] = logEntryMatches[j];\r
+ if (currentMatch && logEntryMatches[j].equals(currentMatch)) {\r
+ currentMatchIndex = matchIndex;\r
+ }\r
+ matchIndex++;\r
+ }\r
+ };\r
+ if (newestAtTop) {\r
+ for (i = logEntries.length - 1; i >= 0; i--) {\r
+ actOnLogEntry(logEntries[i]);\r
+ }\r
+ } else {\r
+ for (i = 0, iLen = logEntries.length; i < iLen; i++) {\r
+ actOnLogEntry(logEntries[i]);\r
+ }\r
+ }\r
+ currentSearch.matches = matches;\r
+ if (currentMatch) {\r
+ currentMatch.setCurrent();\r
+ }\r
+ } else if (scrollToLatest) {\r
+ doScrollToLatest();\r
+ }\r
+ }\r
+ $("newestAtTop").checked = isNewestAtTop;\r
+ }\r
+\r
+ function toggleNewestAtTop() {\r
+ var isNewestAtTop = $("newestAtTop").checked;\r
+ setNewestAtTop(isNewestAtTop);\r
+ }\r
+\r
+ var scrollToLatest = true;\r
+\r
+ function setScrollToLatest(isScrollToLatest) {\r
+ scrollToLatest = isScrollToLatest;\r
+ if (scrollToLatest) {\r
+ doScrollToLatest();\r
+ }\r
+ $("scrollToLatest").checked = isScrollToLatest;\r
+ }\r
+\r
+ function toggleScrollToLatest() {\r
+ var isScrollToLatest = $("scrollToLatest").checked;\r
+ setScrollToLatest(isScrollToLatest);\r
+ }\r
+\r
+ function doScrollToLatest() {\r
+ var l = logMainContainer;\r
+ if (typeof l.scrollTop != "undefined") {\r
+ if (newestAtTop) {\r
+ l.scrollTop = 0;\r
+ } else {\r
+ var latestLogEntry = l.lastChild;\r
+ if (latestLogEntry) {\r
+ l.scrollTop = l.scrollHeight;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ var closeIfOpenerCloses = true;\r
+\r
+ function setCloseIfOpenerCloses(isCloseIfOpenerCloses) {\r
+ closeIfOpenerCloses = isCloseIfOpenerCloses;\r
+ }\r
+\r
+ var maxMessages = null;\r
+\r
+ function setMaxMessages(max) {\r
+ maxMessages = max;\r
+ pruneLogEntries();\r
+ }\r
+\r
+ var showCommandLine = false;\r
+\r
+ function setShowCommandLine(isShowCommandLine) {\r
+ showCommandLine = isShowCommandLine;\r
+ if (loaded) {\r
+ $("commandLine").style.display = showCommandLine ? "block" : "none";\r
+ setCommandInputWidth();\r
+ setLogContainerHeight();\r
+ }\r
+ }\r
+\r
+ function focusCommandLine() {\r
+ if (loaded) {\r
+ $("command").focus();\r
+ }\r
+ }\r
+\r
+ function focusSearch() {\r
+ if (loaded) {\r
+ $("searchBox").focus();\r
+ }\r
+ }\r
+\r
+ function getLogItems() {\r
+ var items = [];\r
+ for (var i = 0, len = logItems.length; i < len; i++) {\r
+ logItems[i].serialize(items);\r
+ }\r
+ return items;\r
+ }\r
+\r
+ function setLogItems(items) {\r
+ var loggingReallyEnabled = loggingEnabled;\r
+ // Temporarily turn logging on\r
+ loggingEnabled = true;\r
+ for (var i = 0, len = items.length; i < len; i++) {\r
+ switch (items[i][0]) {\r
+ case LogItem.serializedItemKeys.LOG_ENTRY:\r
+ log(items[i][1], items[i][2]);\r
+ break;\r
+ case LogItem.serializedItemKeys.GROUP_START:\r
+ group(items[i][1]);\r
+ break;\r
+ case LogItem.serializedItemKeys.GROUP_END:\r
+ groupEnd();\r
+ break;\r
+ }\r
+ }\r
+ loggingEnabled = loggingReallyEnabled;\r
+ }\r
+\r
+ function log(logLevel, formattedMessage) {\r
+ if (loggingEnabled) {\r
+ var logEntry = new LogEntry(logLevel, formattedMessage);\r
+ logEntries.push(logEntry);\r
+ logEntriesAndSeparators.push(logEntry);\r
+ logItems.push(logEntry);\r
+ currentGroup.addChild(logEntry);\r
+ if (loaded) {\r
+ if (logQueuedEventsTimer !== null) {\r
+ clearTimeout(logQueuedEventsTimer);\r
+ }\r
+ logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);\r
+ unrenderedLogItemsExist = true;\r
+ }\r
+ }\r
+ }\r
+\r
+ function renderQueuedLogItems() {\r
+ logQueuedEventsTimer = null;\r
+ var pruned = pruneLogEntries();\r
+\r
+ // Render any unrendered log entries and apply the current search to them\r
+ var initiallyHasMatches = currentSearch ? currentSearch.hasMatches() : false;\r
+ for (var i = 0, len = logItems.length; i < len; i++) {\r
+ if (!logItems[i].rendered) {\r
+ logItems[i].render();\r
+ logItems[i].appendToLog();\r
+ if (currentSearch && (logItems[i] instanceof LogEntry)) {\r
+ currentSearch.applyTo(logItems[i]);\r
+ }\r
+ }\r
+ }\r
+ if (currentSearch) {\r
+ if (pruned) {\r
+ if (currentSearch.hasVisibleMatches()) {\r
+ if (currentMatchIndex === null) {\r
+ setCurrentMatchIndex(0);\r
+ }\r
+ displayMatches();\r
+ } else {\r
+ displayNoMatches();\r
+ }\r
+ } else if (!initiallyHasMatches && currentSearch.hasVisibleMatches()) {\r
+ setCurrentMatchIndex(0);\r
+ displayMatches();\r
+ }\r
+ }\r
+ if (scrollToLatest) {\r
+ doScrollToLatest();\r
+ }\r
+ unrenderedLogItemsExist = false;\r
+ }\r
+\r
+ function pruneLogEntries() {\r
+ if ((maxMessages !== null) && (logEntriesAndSeparators.length > maxMessages)) {\r
+ var numberToDelete = logEntriesAndSeparators.length - maxMessages;\r
+ var prunedLogEntries = logEntriesAndSeparators.slice(0, numberToDelete);\r
+ if (currentSearch) {\r
+ currentSearch.removeMatches(prunedLogEntries);\r
+ }\r
+ var group;\r
+ for (var i = 0; i < numberToDelete; i++) {\r
+ group = logEntriesAndSeparators[i].group;\r
+ array_remove(logItems, logEntriesAndSeparators[i]);\r
+ array_remove(logEntries, logEntriesAndSeparators[i]);\r
+ logEntriesAndSeparators[i].remove(true, true);\r
+ if (group.children.length === 0 && group !== currentGroup && group !== rootGroup) {\r
+ array_remove(logItems, group);\r
+ group.remove(true, true);\r
+ }\r
+ }\r
+ logEntriesAndSeparators = array_removeFromStart(logEntriesAndSeparators, numberToDelete);\r
+ return true;\r
+ }\r
+ return false;\r
+ }\r
+\r
+ function group(name, startExpanded) {\r
+ if (loggingEnabled) {\r
+ initiallyExpanded = (typeof startExpanded === "undefined") ? true : Boolean(startExpanded);\r
+ var newGroup = new Group(name, false, initiallyExpanded);\r
+ currentGroup.addChild(newGroup);\r
+ currentGroup = newGroup;\r
+ logItems.push(newGroup);\r
+ if (loaded) {\r
+ if (logQueuedEventsTimer !== null) {\r
+ clearTimeout(logQueuedEventsTimer);\r
+ }\r
+ logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);\r
+ unrenderedLogItemsExist = true;\r
+ }\r
+ }\r
+ }\r
+\r
+ function groupEnd() {\r
+ currentGroup = (currentGroup === rootGroup) ? rootGroup : currentGroup.group;\r
+ }\r
+\r
+ function mainPageReloaded() {\r
+ currentGroup = rootGroup;\r
+ var separator = new Separator();\r
+ logEntriesAndSeparators.push(separator);\r
+ logItems.push(separator);\r
+ currentGroup.addChild(separator);\r
+ }\r
+\r
+ function closeWindow() {\r
+ if (appender && mainWindowExists()) {\r
+ appender.close(true);\r
+ } else {\r
+ window.close();\r
+ }\r
+ }\r
+\r
+ function hide() {\r
+ if (appender && mainWindowExists()) {\r
+ appender.hide();\r
+ }\r
+ }\r
+\r
+ var mainWindow = window;\r
+ var windowId = "log4javascriptConsoleWindow_" + new Date().getTime() + "_" + ("" + Math.random()).substr(2);\r
+\r
+ function setMainWindow(win) {\r
+ mainWindow = win;\r
+ mainWindow[windowId] = window;\r
+ // If this is a pop-up, poll the opener to see if it's closed\r
+ if (opener && closeIfOpenerCloses) {\r
+ pollOpener();\r
+ }\r
+ }\r
+\r
+ function pollOpener() {\r
+ if (closeIfOpenerCloses) {\r
+ if (mainWindowExists()) {\r
+ setTimeout(pollOpener, 500);\r
+ } else {\r
+ closeWindow();\r
+ }\r
+ }\r
+ }\r
+\r
+ function mainWindowExists() {\r
+ try {\r
+ return (mainWindow && !mainWindow.closed &&\r
+ mainWindow[windowId] == window);\r
+ } catch (ex) {}\r
+ return false;\r
+ }\r
+\r
+ var logLevels = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"];\r
+\r
+ function getCheckBox(logLevel) {\r
+ return $("switch_" + logLevel);\r
+ }\r
+\r
+ function getIeWrappedLogContainer() {\r
+ return $("log_wrapped");\r
+ }\r
+\r
+ function getIeUnwrappedLogContainer() {\r
+ return $("log_unwrapped");\r
+ }\r
+\r
+ function applyFilters() {\r
+ for (var i = 0; i < logLevels.length; i++) {\r
+ if (getCheckBox(logLevels[i]).checked) {\r
+ addClass(logMainContainer, logLevels[i]);\r
+ } else {\r
+ removeClass(logMainContainer, logLevels[i]);\r
+ }\r
+ }\r
+ updateSearchFromFilters();\r
+ }\r
+\r
+ function toggleAllLevels() {\r
+ var turnOn = $("switch_ALL").checked;\r
+ for (var i = 0; i < logLevels.length; i++) {\r
+ getCheckBox(logLevels[i]).checked = turnOn;\r
+ if (turnOn) {\r
+ addClass(logMainContainer, logLevels[i]);\r
+ } else {\r
+ removeClass(logMainContainer, logLevels[i]);\r
+ }\r
+ }\r
+ }\r
+\r
+ function checkAllLevels() {\r
+ for (var i = 0; i < logLevels.length; i++) {\r
+ if (!getCheckBox(logLevels[i]).checked) {\r
+ getCheckBox("ALL").checked = false;\r
+ return;\r
+ }\r
+ }\r
+ getCheckBox("ALL").checked = true;\r
+ }\r
+\r
+ function clearLog() {\r
+ rootGroup.clear();\r
+ currentGroup = rootGroup;\r
+ logEntries = [];\r
+ logItems = [];\r
+ logEntriesAndSeparators = [];\r
+ doSearch();\r
+ }\r
+\r
+ function toggleWrap() {\r
+ var enable = $("wrap").checked;\r
+ if (enable) {\r
+ addClass(logMainContainer, "wrap");\r
+ } else {\r
+ removeClass(logMainContainer, "wrap");\r
+ }\r
+ refreshCurrentMatch();\r
+ }\r
+\r
+ /* ------------------------------------------------------------------- */\r
+\r
+ // Search\r
+\r
+ var searchTimer = null;\r
+\r
+ function scheduleSearch() {\r
+ try {\r
+ clearTimeout(searchTimer);\r
+ } catch (ex) {\r
+ // Do nothing\r
+ }\r
+ searchTimer = setTimeout(doSearch, 500);\r
+ }\r
+\r
+ function Search(searchTerm, isRegex, searchRegex, isCaseSensitive) {\r
+ this.searchTerm = searchTerm;\r
+ this.isRegex = isRegex;\r
+ this.searchRegex = searchRegex;\r
+ this.isCaseSensitive = isCaseSensitive;\r
+ this.matches = [];\r
+ }\r
+\r
+ Search.prototype = {\r
+ hasMatches: function() {\r
+ return this.matches.length > 0;\r
+ },\r
+\r
+ hasVisibleMatches: function() {\r
+ if (this.hasMatches()) {\r
+ for (var i = 0; i < this.matches.length; i++) {\r
+ if (this.matches[i].isVisible()) {\r
+ return true;\r
+ }\r
+ }\r
+ }\r
+ return false;\r
+ },\r
+\r
+ match: function(logEntry) {\r
+ var entryText = String(logEntry.formattedMessage);\r
+ var matchesSearch = false;\r
+ if (this.isRegex) {\r
+ matchesSearch = this.searchRegex.test(entryText);\r
+ } else if (this.isCaseSensitive) {\r
+ matchesSearch = (entryText.indexOf(this.searchTerm) > -1);\r
+ } else {\r
+ matchesSearch = (entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1);\r
+ }\r
+ return matchesSearch;\r
+ },\r
+\r
+ getNextVisibleMatchIndex: function() {\r
+ for (var i = currentMatchIndex + 1; i < this.matches.length; i++) {\r
+ if (this.matches[i].isVisible()) {\r
+ return i;\r
+ }\r
+ }\r
+ // Start again from the first match\r
+ for (i = 0; i <= currentMatchIndex; i++) {\r
+ if (this.matches[i].isVisible()) {\r
+ return i;\r
+ }\r
+ }\r
+ return -1;\r
+ },\r
+\r
+ getPreviousVisibleMatchIndex: function() {\r
+ for (var i = currentMatchIndex - 1; i >= 0; i--) {\r
+ if (this.matches[i].isVisible()) {\r
+ return i;\r
+ }\r
+ }\r
+ // Start again from the last match\r
+ for (var i = this.matches.length - 1; i >= currentMatchIndex; i--) {\r
+ if (this.matches[i].isVisible()) {\r
+ return i;\r
+ }\r
+ }\r
+ return -1;\r
+ },\r
+\r
+ applyTo: function(logEntry) {\r
+ var doesMatch = this.match(logEntry);\r
+ if (doesMatch) {\r
+ logEntry.group.expand();\r
+ logEntry.setSearchMatch(true);\r
+ var logEntryContent;\r
+ var wrappedLogEntryContent;\r
+ var searchTermReplacementStartTag = "<span class=\"searchterm\">";\r
+ var searchTermReplacementEndTag = "<" + "/span>";\r
+ var preTagName = isIe ? "pre" : "span";\r
+ var preStartTag = "<" + preTagName + " class=\"pre\">";\r
+ var preEndTag = "<" + "/" + preTagName + ">";\r
+ var startIndex = 0;\r
+ var searchIndex, matchedText, textBeforeMatch;\r
+ if (this.isRegex) {\r
+ var flags = this.isCaseSensitive ? "g" : "gi";\r
+ var capturingRegex = new RegExp("(" + this.searchRegex.source + ")", flags);\r
+\r
+ // Replace the search term with temporary tokens for the start and end tags\r
+ var rnd = ("" + Math.random()).substr(2);\r
+ var startToken = "%%s" + rnd + "%%";\r
+ var endToken = "%%e" + rnd + "%%";\r
+ logEntryContent = logEntry.formattedMessage.replace(capturingRegex, startToken + "$1" + endToken);\r
+\r
+ // Escape the HTML to get rid of angle brackets\r
+ logEntryContent = escapeHtml(logEntryContent);\r
+\r
+ // Substitute the proper HTML back in for the search match\r
+ var result;\r
+ var searchString = logEntryContent;\r
+ logEntryContent = "";\r
+ wrappedLogEntryContent = "";\r
+ while ((searchIndex = searchString.indexOf(startToken, startIndex)) > -1) {\r
+ var endTokenIndex = searchString.indexOf(endToken, searchIndex);\r
+ matchedText = searchString.substring(searchIndex + startToken.length, endTokenIndex);\r
+ textBeforeMatch = searchString.substring(startIndex, searchIndex);\r
+ logEntryContent += preStartTag + textBeforeMatch + preEndTag;\r
+ logEntryContent += searchTermReplacementStartTag + preStartTag + matchedText +\r
+ preEndTag + searchTermReplacementEndTag;\r
+ if (isIe) {\r
+ wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +\r
+ matchedText + searchTermReplacementEndTag;\r
+ }\r
+ startIndex = endTokenIndex + endToken.length;\r
+ }\r
+ logEntryContent += preStartTag + searchString.substr(startIndex) + preEndTag;\r
+ if (isIe) {\r
+ wrappedLogEntryContent += searchString.substr(startIndex);\r
+ }\r
+ } else {\r
+ logEntryContent = "";\r
+ wrappedLogEntryContent = "";\r
+ var searchTermReplacementLength = searchTermReplacementStartTag.length +\r
+ this.searchTerm.length + searchTermReplacementEndTag.length;\r
+ var searchTermLength = this.searchTerm.length;\r
+ var searchTermLowerCase = this.searchTerm.toLowerCase();\r
+ var logTextLowerCase = logEntry.formattedMessage.toLowerCase();\r
+ while ((searchIndex = logTextLowerCase.indexOf(searchTermLowerCase, startIndex)) > -1) {\r
+ matchedText = escapeHtml(logEntry.formattedMessage.substr(searchIndex, this.searchTerm.length));\r
+ textBeforeMatch = escapeHtml(logEntry.formattedMessage.substring(startIndex, searchIndex));\r
+ var searchTermReplacement = searchTermReplacementStartTag +\r
+ preStartTag + matchedText + preEndTag + searchTermReplacementEndTag;\r
+ logEntryContent += preStartTag + textBeforeMatch + preEndTag + searchTermReplacement;\r
+ if (isIe) {\r
+ wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +\r
+ matchedText + searchTermReplacementEndTag;\r
+ }\r
+ startIndex = searchIndex + searchTermLength;\r
+ }\r
+ var textAfterLastMatch = escapeHtml(logEntry.formattedMessage.substr(startIndex));\r
+ logEntryContent += preStartTag + textAfterLastMatch + preEndTag;\r
+ if (isIe) {\r
+ wrappedLogEntryContent += textAfterLastMatch;\r
+ }\r
+ }\r
+ logEntry.setContent(logEntryContent, wrappedLogEntryContent);\r
+ var logEntryMatches = logEntry.getSearchMatches();\r
+ this.matches = this.matches.concat(logEntryMatches);\r
+ } else {\r
+ logEntry.setSearchMatch(false);\r
+ logEntry.setContent(logEntry.formattedMessage, logEntry.formattedMessage);\r
+ }\r
+ return doesMatch;\r
+ },\r
+\r
+ removeMatches: function(logEntries) {\r
+ var matchesToRemoveCount = 0;\r
+ var currentMatchRemoved = false;\r
+ var matchesToRemove = [];\r
+ var i, iLen, j, jLen;\r
+\r
+ // Establish the list of matches to be removed\r
+ for (i = 0, iLen = this.matches.length; i < iLen; i++) {\r
+ for (j = 0, jLen = logEntries.length; j < jLen; j++) {\r
+ if (this.matches[i].belongsTo(logEntries[j])) {\r
+ matchesToRemove.push(this.matches[i]);\r
+ if (i === currentMatchIndex) {\r
+ currentMatchRemoved = true;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ // Set the new current match index if the current match has been deleted\r
+ // This will be the first match that appears after the first log entry being\r
+ // deleted, if one exists; otherwise, it's the first match overall\r
+ var newMatch = currentMatchRemoved ? null : this.matches[currentMatchIndex];\r
+ if (currentMatchRemoved) {\r
+ for (i = currentMatchIndex, iLen = this.matches.length; i < iLen; i++) {\r
+ if (this.matches[i].isVisible() && !array_contains(matchesToRemove, this.matches[i])) {\r
+ newMatch = this.matches[i];\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ // Remove the matches\r
+ for (i = 0, iLen = matchesToRemove.length; i < iLen; i++) {\r
+ array_remove(this.matches, matchesToRemove[i]);\r
+ matchesToRemove[i].remove();\r
+ }\r
+\r
+ // Set the new match, if one exists\r
+ if (this.hasVisibleMatches()) {\r
+ if (newMatch === null) {\r
+ setCurrentMatchIndex(0);\r
+ } else {\r
+ // Get the index of the new match\r
+ var newMatchIndex = 0;\r
+ for (i = 0, iLen = this.matches.length; i < iLen; i++) {\r
+ if (newMatch === this.matches[i]) {\r
+ newMatchIndex = i;\r
+ break;\r
+ }\r
+ }\r
+ setCurrentMatchIndex(newMatchIndex);\r
+ }\r
+ } else {\r
+ currentMatchIndex = null;\r
+ displayNoMatches();\r
+ }\r
+ }\r
+ };\r
+\r
+ function getPageOffsetTop(el, container) {\r
+ var currentEl = el;\r
+ var y = 0;\r
+ while (currentEl && currentEl != container) {\r
+ y += currentEl.offsetTop;\r
+ currentEl = currentEl.offsetParent;\r
+ }\r
+ return y;\r
+ }\r
+\r
+ function scrollIntoView(el) {\r
+ var logContainer = logMainContainer;\r
+ // Check if the whole width of the element is visible and centre if not\r
+ if (!$("wrap").checked) {\r
+ var logContainerLeft = logContainer.scrollLeft;\r
+ var logContainerRight = logContainerLeft + logContainer.offsetWidth;\r
+ var elLeft = el.offsetLeft;\r
+ var elRight = elLeft + el.offsetWidth;\r
+ if (elLeft < logContainerLeft || elRight > logContainerRight) {\r
+ logContainer.scrollLeft = elLeft - (logContainer.offsetWidth - el.offsetWidth) / 2;\r
+ }\r
+ }\r
+ // Check if the whole height of the element is visible and centre if not\r
+ var logContainerTop = logContainer.scrollTop;\r
+ var logContainerBottom = logContainerTop + logContainer.offsetHeight;\r
+ var elTop = getPageOffsetTop(el) - getToolBarsHeight();\r
+ var elBottom = elTop + el.offsetHeight;\r
+ if (elTop < logContainerTop || elBottom > logContainerBottom) {\r
+ logContainer.scrollTop = elTop - (logContainer.offsetHeight - el.offsetHeight) / 2;\r
+ }\r
+ }\r
+\r
+ function Match(logEntryLevel, spanInMainDiv, spanInUnwrappedPre, spanInWrappedDiv) {\r
+ this.logEntryLevel = logEntryLevel;\r
+ this.spanInMainDiv = spanInMainDiv;\r
+ if (isIe) {\r
+ this.spanInUnwrappedPre = spanInUnwrappedPre;\r
+ this.spanInWrappedDiv = spanInWrappedDiv;\r
+ }\r
+ this.mainSpan = isIe ? spanInUnwrappedPre : spanInMainDiv;\r
+ }\r
+\r
+ Match.prototype = {\r
+ equals: function(match) {\r
+ return this.mainSpan === match.mainSpan;\r
+ },\r
+\r
+ setCurrent: function() {\r
+ if (isIe) {\r
+ addClass(this.spanInUnwrappedPre, "currentmatch");\r
+ addClass(this.spanInWrappedDiv, "currentmatch");\r
+ // Scroll the visible one into view\r
+ var elementToScroll = $("wrap").checked ? this.spanInWrappedDiv : this.spanInUnwrappedPre;\r
+ scrollIntoView(elementToScroll);\r
+ } else {\r
+ addClass(this.spanInMainDiv, "currentmatch");\r
+ scrollIntoView(this.spanInMainDiv);\r
+ }\r
+ },\r
+\r
+ belongsTo: function(logEntry) {\r
+ if (isIe) {\r
+ return isDescendant(this.spanInUnwrappedPre, logEntry.unwrappedPre);\r
+ } else {\r
+ return isDescendant(this.spanInMainDiv, logEntry.mainDiv);\r
+ }\r
+ },\r
+\r
+ setNotCurrent: function() {\r
+ if (isIe) {\r
+ removeClass(this.spanInUnwrappedPre, "currentmatch");\r
+ removeClass(this.spanInWrappedDiv, "currentmatch");\r
+ } else {\r
+ removeClass(this.spanInMainDiv, "currentmatch");\r
+ }\r
+ },\r
+\r
+ isOrphan: function() {\r
+ return isOrphan(this.mainSpan);\r
+ },\r
+\r
+ isVisible: function() {\r
+ return getCheckBox(this.logEntryLevel).checked;\r
+ },\r
+\r
+ remove: function() {\r
+ if (isIe) {\r
+ this.spanInUnwrappedPre = null;\r
+ this.spanInWrappedDiv = null;\r
+ } else {\r
+ this.spanInMainDiv = null;\r
+ }\r
+ }\r
+ };\r
+\r
+ var currentSearch = null;\r
+ var currentMatchIndex = null;\r
+\r
+ function doSearch() {\r
+ var searchBox = $("searchBox");\r
+ var searchTerm = searchBox.value;\r
+ var isRegex = $("searchRegex").checked;\r
+ var isCaseSensitive = $("searchCaseSensitive").checked;\r
+ var i;\r
+\r
+ if (searchTerm === "") {\r
+ $("searchReset").disabled = true;\r
+ $("searchNav").style.display = "none";\r
+ removeClass(document.body, "searching");\r
+ removeClass(searchBox, "hasmatches");\r
+ removeClass(searchBox, "nomatches");\r
+ for (i = 0; i < logEntries.length; i++) {\r
+ logEntries[i].clearSearch();\r
+ logEntries[i].setContent(logEntries[i].formattedMessage, logEntries[i].formattedMessage);\r
+ }\r
+ currentSearch = null;\r
+ setLogContainerHeight();\r
+ } else {\r
+ $("searchReset").disabled = false;\r
+ $("searchNav").style.display = "block";\r
+ var searchRegex;\r
+ var regexValid;\r
+ if (isRegex) {\r
+ try {\r
+ searchRegex = isCaseSensitive ? new RegExp(searchTerm, "g") : new RegExp(searchTerm, "gi");\r
+ regexValid = true;\r
+ replaceClass(searchBox, "validregex", "invalidregex");\r
+ searchBox.title = "Valid regex";\r
+ } catch (ex) {\r
+ regexValid = false;\r
+ replaceClass(searchBox, "invalidregex", "validregex");\r
+ searchBox.title = "Invalid regex: " + (ex.message ? ex.message : (ex.description ? ex.description : "unknown error"));\r
+ return;\r
+ }\r
+ } else {\r
+ searchBox.title = "";\r
+ removeClass(searchBox, "validregex");\r
+ removeClass(searchBox, "invalidregex");\r
+ }\r
+ addClass(document.body, "searching");\r
+ currentSearch = new Search(searchTerm, isRegex, searchRegex, isCaseSensitive);\r
+ for (i = 0; i < logEntries.length; i++) {\r
+ currentSearch.applyTo(logEntries[i]);\r
+ }\r
+ setLogContainerHeight();\r
+\r
+ // Highlight the first search match\r
+ if (currentSearch.hasVisibleMatches()) {\r
+ setCurrentMatchIndex(0);\r
+ displayMatches();\r
+ } else {\r
+ displayNoMatches();\r
+ }\r
+ }\r
+ }\r
+\r
+ function updateSearchFromFilters() {\r
+ if (currentSearch) {\r
+ if (currentSearch.hasMatches()) {\r
+ if (currentMatchIndex === null) {\r
+ currentMatchIndex = 0;\r
+ }\r
+ var currentMatch = currentSearch.matches[currentMatchIndex];\r
+ if (currentMatch.isVisible()) {\r
+ displayMatches();\r
+ setCurrentMatchIndex(currentMatchIndex);\r
+ } else {\r
+ currentMatch.setNotCurrent();\r
+ // Find the next visible match, if one exists\r
+ var nextVisibleMatchIndex = currentSearch.getNextVisibleMatchIndex();\r
+ if (nextVisibleMatchIndex > -1) {\r
+ setCurrentMatchIndex(nextVisibleMatchIndex);\r
+ displayMatches();\r
+ } else {\r
+ displayNoMatches();\r
+ }\r
+ }\r
+ } else {\r
+ displayNoMatches();\r
+ }\r
+ }\r
+ }\r
+\r
+ function refreshCurrentMatch() {\r
+ if (currentSearch && currentSearch.hasVisibleMatches()) {\r
+ setCurrentMatchIndex(currentMatchIndex);\r
+ }\r
+ }\r
+\r
+ function displayMatches() {\r
+ replaceClass($("searchBox"), "hasmatches", "nomatches");\r
+ $("searchBox").title = "" + currentSearch.matches.length + " matches found";\r
+ $("searchNav").style.display = "block";\r
+ setLogContainerHeight();\r
+ }\r
+\r
+ function displayNoMatches() {\r
+ replaceClass($("searchBox"), "nomatches", "hasmatches");\r
+ $("searchBox").title = "No matches found";\r
+ $("searchNav").style.display = "none";\r
+ setLogContainerHeight();\r
+ }\r
+\r
+ function toggleSearchEnabled(enable) {\r
+ enable = (typeof enable == "undefined") ? !$("searchDisable").checked : enable;\r
+ $("searchBox").disabled = !enable;\r
+ $("searchReset").disabled = !enable;\r
+ $("searchRegex").disabled = !enable;\r
+ $("searchNext").disabled = !enable;\r
+ $("searchPrevious").disabled = !enable;\r
+ $("searchCaseSensitive").disabled = !enable;\r
+ $("searchNav").style.display = (enable && ($("searchBox").value !== "") &&\r
+ currentSearch && currentSearch.hasVisibleMatches()) ?\r
+ "block" : "none";\r
+ if (enable) {\r
+ removeClass($("search"), "greyedout");\r
+ addClass(document.body, "searching");\r
+ if ($("searchHighlight").checked) {\r
+ addClass(logMainContainer, "searchhighlight");\r
+ } else {\r
+ removeClass(logMainContainer, "searchhighlight");\r
+ }\r
+ if ($("searchFilter").checked) {\r
+ addClass(logMainContainer, "searchfilter");\r
+ } else {\r
+ removeClass(logMainContainer, "searchfilter");\r
+ }\r
+ $("searchDisable").checked = !enable;\r
+ } else {\r
+ addClass($("search"), "greyedout");\r
+ removeClass(document.body, "searching");\r
+ removeClass(logMainContainer, "searchhighlight");\r
+ removeClass(logMainContainer, "searchfilter");\r
+ }\r
+ setLogContainerHeight();\r
+ }\r
+\r
+ function toggleSearchFilter() {\r
+ var enable = $("searchFilter").checked;\r
+ if (enable) {\r
+ addClass(logMainContainer, "searchfilter");\r
+ } else {\r
+ removeClass(logMainContainer, "searchfilter");\r
+ }\r
+ refreshCurrentMatch();\r
+ }\r
+\r
+ function toggleSearchHighlight() {\r
+ var enable = $("searchHighlight").checked;\r
+ if (enable) {\r
+ addClass(logMainContainer, "searchhighlight");\r
+ } else {\r
+ removeClass(logMainContainer, "searchhighlight");\r
+ }\r
+ }\r
+\r
+ function clearSearch() {\r
+ $("searchBox").value = "";\r
+ doSearch();\r
+ }\r
+\r
+ function searchNext() {\r
+ if (currentSearch !== null && currentMatchIndex !== null) {\r
+ currentSearch.matches[currentMatchIndex].setNotCurrent();\r
+ var nextMatchIndex = currentSearch.getNextVisibleMatchIndex();\r
+ if (nextMatchIndex > currentMatchIndex || confirm("Reached the end of the page. Start from the top?")) {\r
+ setCurrentMatchIndex(nextMatchIndex);\r
+ }\r
+ }\r
+ }\r
+\r
+ function searchPrevious() {\r
+ if (currentSearch !== null && currentMatchIndex !== null) {\r
+ currentSearch.matches[currentMatchIndex].setNotCurrent();\r
+ var previousMatchIndex = currentSearch.getPreviousVisibleMatchIndex();\r
+ if (previousMatchIndex < currentMatchIndex || confirm("Reached the start of the page. Continue from the bottom?")) {\r
+ setCurrentMatchIndex(previousMatchIndex);\r
+ }\r
+ }\r
+ }\r
+\r
+ function setCurrentMatchIndex(index) {\r
+ currentMatchIndex = index;\r
+ currentSearch.matches[currentMatchIndex].setCurrent();\r
+ }\r
+\r
+ /* ------------------------------------------------------------------------- */\r
+\r
+ // CSS Utilities\r
+\r
+ function addClass(el, cssClass) {\r
+ if (!hasClass(el, cssClass)) {\r
+ if (el.className) {\r
+ el.className += " " + cssClass;\r
+ } else {\r
+ el.className = cssClass;\r
+ }\r
+ }\r
+ }\r
+\r
+ function hasClass(el, cssClass) {\r
+ if (el.className) {\r
+ var classNames = el.className.split(" ");\r
+ return array_contains(classNames, cssClass);\r
+ }\r
+ return false;\r
+ }\r
+\r
+ function removeClass(el, cssClass) {\r
+ if (hasClass(el, cssClass)) {\r
+ // Rebuild the className property\r
+ var existingClasses = el.className.split(" ");\r
+ var newClasses = [];\r
+ for (var i = 0, len = existingClasses.length; i < len; i++) {\r
+ if (existingClasses[i] != cssClass) {\r
+ newClasses[newClasses.length] = existingClasses[i];\r
+ }\r
+ }\r
+ el.className = newClasses.join(" ");\r
+ }\r
+ }\r
+\r
+ function replaceClass(el, newCssClass, oldCssClass) {\r
+ removeClass(el, oldCssClass);\r
+ addClass(el, newCssClass);\r
+ }\r
+\r
+ /* ------------------------------------------------------------------------- */\r
+\r
+ // Other utility functions\r
+\r
+ function getElementsByClass(el, cssClass, tagName) {\r
+ var elements = el.getElementsByTagName(tagName);\r
+ var matches = [];\r
+ for (var i = 0, len = elements.length; i < len; i++) {\r
+ if (hasClass(elements[i], cssClass)) {\r
+ matches.push(elements[i]);\r
+ }\r
+ }\r
+ return matches;\r
+ }\r
+\r
+ // Syntax borrowed from Prototype library\r
+ function $(id) {\r
+ return document.getElementById(id);\r
+ }\r
+\r
+ function isDescendant(node, ancestorNode) {\r
+ while (node != null) {\r
+ if (node === ancestorNode) {\r
+ return true;\r
+ }\r
+ node = node.parentNode;\r
+ }\r
+ return false;\r
+ }\r
+\r
+ function isOrphan(node) {\r
+ var currentNode = node;\r
+ while (currentNode) {\r
+ if (currentNode == document.body) {\r
+ return false;\r
+ }\r
+ currentNode = currentNode.parentNode;\r
+ }\r
+ return true;\r
+ }\r
+\r
+ function escapeHtml(str) {\r
+ return str.replace(/&/g, "&").replace(/[<]/g, "<").replace(/>/g, ">");\r
+ }\r
+\r
+ function getWindowWidth() {\r
+ if (window.innerWidth) {\r
+ return window.innerWidth;\r
+ } else if (document.documentElement && document.documentElement.clientWidth) {\r
+ return document.documentElement.clientWidth;\r
+ } else if (document.body) {\r
+ return document.body.clientWidth;\r
+ }\r
+ return 0;\r
+ }\r
+\r
+ function getWindowHeight() {\r
+ if (window.innerHeight) {\r
+ return window.innerHeight;\r
+ } else if (document.documentElement && document.documentElement.clientHeight) {\r
+ return document.documentElement.clientHeight;\r
+ } else if (document.body) {\r
+ return document.body.clientHeight;\r
+ }\r
+ return 0;\r
+ }\r
+\r
+ function getToolBarsHeight() {\r
+ return $("switches").offsetHeight;\r
+ }\r
+\r
+ function getChromeHeight() {\r
+ var height = getToolBarsHeight();\r
+ if (showCommandLine) {\r
+ height += $("commandLine").offsetHeight;\r
+ }\r
+ return height;\r
+ }\r
+\r
+ function setLogContainerHeight() {\r
+ if (logMainContainer) {\r
+ var windowHeight = getWindowHeight();\r
+ $("body").style.height = getWindowHeight() + "px";\r
+ logMainContainer.style.height = "" +\r
+ Math.max(0, windowHeight - getChromeHeight()) + "px";\r
+ }\r
+ }\r
+\r
+ function setCommandInputWidth() {\r
+ if (showCommandLine) {\r
+ $("command").style.width = "" + Math.max(0, $("commandLineContainer").offsetWidth -\r
+ ($("evaluateButton").offsetWidth + 13)) + "px";\r
+ }\r
+ }\r
+\r
+ window.onresize = function() {\r
+ setCommandInputWidth();\r
+ setLogContainerHeight();\r
+ };\r
+\r
+ if (!Array.prototype.push) {\r
+ Array.prototype.push = function() {\r
+ for (var i = 0, len = arguments.length; i < len; i++){\r
+ this[this.length] = arguments[i];\r
+ }\r
+ return this.length;\r
+ };\r
+ }\r
+\r
+ if (!Array.prototype.pop) {\r
+ Array.prototype.pop = function() {\r
+ if (this.length > 0) {\r
+ var val = this[this.length - 1];\r
+ this.length = this.length - 1;\r
+ return val;\r
+ }\r
+ };\r
+ }\r
+\r
+ if (!Array.prototype.shift) {\r
+ Array.prototype.shift = function() {\r
+ if (this.length > 0) {\r
+ var firstItem = this[0];\r
+ for (var i = 0, len = this.length - 1; i < len; i++) {\r
+ this[i] = this[i + 1];\r
+ }\r
+ this.length = this.length - 1;\r
+ return firstItem;\r
+ }\r
+ };\r
+ }\r
+\r
+ if (!Array.prototype.splice) {\r
+ Array.prototype.splice = function(startIndex, deleteCount) {\r
+ var itemsAfterDeleted = this.slice(startIndex + deleteCount);\r
+ var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);\r
+ this.length = startIndex;\r
+ // Copy the arguments into a proper Array object\r
+ var argumentsArray = [];\r
+ for (var i = 0, len = arguments.length; i < len; i++) {\r
+ argumentsArray[i] = arguments[i];\r
+ }\r
+ var itemsToAppend = (argumentsArray.length > 2) ?\r
+ itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;\r
+ for (i = 0, len = itemsToAppend.length; i < len; i++) {\r
+ this.push(itemsToAppend[i]);\r
+ }\r
+ return itemsDeleted;\r
+ };\r
+ }\r
+\r
+ function array_remove(arr, val) {\r
+ var index = -1;\r
+ for (var i = 0, len = arr.length; i < len; i++) {\r
+ if (arr[i] === val) {\r
+ index = i;\r
+ break;\r
+ }\r
+ }\r
+ if (index >= 0) {\r
+ arr.splice(index, 1);\r
+ return index;\r
+ } else {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ function array_removeFromStart(array, numberToRemove) {\r
+ if (Array.prototype.splice) {\r
+ array.splice(0, numberToRemove);\r
+ } else {\r
+ for (var i = numberToRemove, len = array.length; i < len; i++) {\r
+ array[i - numberToRemove] = array[i];\r
+ }\r
+ array.length = array.length - numberToRemove;\r
+ }\r
+ return array;\r
+ }\r
+\r
+ function array_contains(arr, val) {\r
+ for (var i = 0, len = arr.length; i < len; i++) {\r
+ if (arr[i] == val) {\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+\r
+ function getErrorMessage(ex) {\r
+ if (ex.message) {\r
+ return ex.message;\r
+ } else if (ex.description) {\r
+ return ex.description;\r
+ }\r
+ return "" + ex;\r
+ }\r
+\r
+ function moveCaretToEnd(input) {\r
+ if (input.setSelectionRange) {\r
+ input.focus();\r
+ var length = input.value.length;\r
+ input.setSelectionRange(length, length);\r
+ } else if (input.createTextRange) {\r
+ var range = input.createTextRange();\r
+ range.collapse(false);\r
+ range.select();\r
+ }\r
+ input.focus();\r
+ }\r
+\r
+ function stopPropagation(evt) {\r
+ if (evt.stopPropagation) {\r
+ evt.stopPropagation();\r
+ } else if (typeof evt.cancelBubble != "undefined") {\r
+ evt.cancelBubble = true;\r
+ }\r
+ }\r
+\r
+ function getEvent(evt) {\r
+ return evt ? evt : event;\r
+ }\r
+\r
+ function getTarget(evt) {\r
+ return evt.target ? evt.target : evt.srcElement;\r
+ }\r
+\r
+ function getRelatedTarget(evt) {\r
+ if (evt.relatedTarget) {\r
+ return evt.relatedTarget;\r
+ } else if (evt.srcElement) {\r
+ switch(evt.type) {\r
+ case "mouseover":\r
+ return evt.fromElement;\r
+ case "mouseout":\r
+ return evt.toElement;\r
+ default:\r
+ return evt.srcElement;\r
+ }\r
+ }\r
+ }\r
+\r
+ function cancelKeyEvent(evt) {\r
+ evt.returnValue = false;\r
+ stopPropagation(evt);\r
+ }\r
+\r
+ function evalCommandLine() {\r
+ var expr = $("command").value;\r
+ evalCommand(expr);\r
+ $("command").value = "";\r
+ }\r
+\r
+ function evalLastCommand() {\r
+ if (lastCommand != null) {\r
+ evalCommand(lastCommand);\r
+ }\r
+ }\r
+\r
+ var lastCommand = null;\r
+ var commandHistory = [];\r
+ var currentCommandIndex = 0;\r
+\r
+ function evalCommand(expr) {\r
+ if (appender) {\r
+ appender.evalCommandAndAppend(expr);\r
+ } else {\r
+ var prefix = ">>> " + expr + "\r\n";\r
+ try {\r
+ log("INFO", prefix + eval(expr));\r
+ } catch (ex) {\r
+ log("ERROR", prefix + "Error: " + getErrorMessage(ex));\r
+ }\r
+ }\r
+ // Update command history\r
+ if (expr != commandHistory[commandHistory.length - 1]) {\r
+ commandHistory.push(expr);\r
+ // Update the appender\r
+ if (appender) {\r
+ appender.storeCommandHistory(commandHistory);\r
+ }\r
+ }\r
+ currentCommandIndex = (expr == commandHistory[currentCommandIndex]) ? currentCommandIndex + 1 : commandHistory.length;\r
+ lastCommand = expr;\r
+ }\r
+ //]]>\r
+ </script>\r
+ <style type="text/css">\r
+ body {\r
+ background-color: white;\r
+ color: black;\r
+ padding: 0;\r
+ margin: 0;\r
+ font-family: tahoma, verdana, arial, helvetica, sans-serif;\r
+ overflow: hidden;\r
+ }\r
+\r
+ div#switchesContainer input {\r
+ margin-bottom: 0;\r
+ }\r
+\r
+ div.toolbar {\r
+ border-top: solid #ffffff 1px;\r
+ border-bottom: solid #aca899 1px;\r
+ background-color: #f1efe7;\r
+ padding: 3px 5px;\r
+ font-size: 68.75%;\r
+ }\r
+\r
+ div.toolbar, div#search input {\r
+ font-family: tahoma, verdana, arial, helvetica, sans-serif;\r
+ }\r
+\r
+ div.toolbar input.button {\r
+ padding: 0 5px;\r
+ font-size: 100%;\r
+ }\r
+\r
+ div.toolbar input.hidden {\r
+ display: none;\r
+ }\r
+\r
+ div#switches input#clearButton {\r
+ margin-left: 20px;\r
+ }\r
+\r
+ div#levels label {\r
+ font-weight: bold;\r
+ }\r
+\r
+ div#levels label, div#options label {\r
+ margin-right: 5px;\r
+ }\r
+\r
+ div#levels label#wrapLabel {\r
+ font-weight: normal;\r
+ }\r
+\r
+ div#search label {\r
+ margin-right: 10px;\r
+ }\r
+\r
+ div#search label.searchboxlabel {\r
+ margin-right: 0;\r
+ }\r
+\r
+ div#search input {\r
+ font-size: 100%;\r
+ }\r
+\r
+ div#search input.validregex {\r
+ color: green;\r
+ }\r
+\r
+ div#search input.invalidregex {\r
+ color: red;\r
+ }\r
+\r
+ div#search input.nomatches {\r
+ color: white;\r
+ background-color: #ff6666;\r
+ }\r
+\r
+ div#search input.nomatches {\r
+ color: white;\r
+ background-color: #ff6666;\r
+ }\r
+\r
+ div#searchNav {\r
+ display: none;\r
+ }\r
+\r
+ div#commandLine {\r
+ display: none;\r
+ }\r
+\r
+ div#commandLine input#command {\r
+ font-size: 100%;\r
+ font-family: Courier New, Courier;\r
+ }\r
+\r
+ div#commandLine input#evaluateButton {\r
+ }\r
+\r
+ *.greyedout {\r
+ color: gray !important;\r
+ border-color: gray !important;\r
+ }\r
+\r
+ *.greyedout *.alwaysenabled { color: black; }\r
+\r
+ *.unselectable {\r
+ -khtml-user-select: none;\r
+ -moz-user-select: none;\r
+ user-select: none;\r
+ }\r
+\r
+ div#log {\r
+ font-family: Courier New, Courier;\r
+ font-size: 75%;\r
+ width: 100%;\r
+ overflow: auto;\r
+ clear: both;\r
+ position: relative;\r
+ }\r
+\r
+ div.group {\r
+ border-color: #cccccc;\r
+ border-style: solid;\r
+ border-width: 1px 0 1px 1px;\r
+ overflow: visible;\r
+ }\r
+\r
+ div.oldIe div.group, div.oldIe div.group *, div.oldIe *.logentry {\r
+ height: 1%;\r
+ }\r
+\r
+ div.group div.groupheading span.expander {\r
+ border: solid black 1px;\r
+ font-family: Courier New, Courier;\r
+ font-size: 0.833em;\r
+ background-color: #eeeeee;\r
+ position: relative;\r
+ top: -1px;\r
+ color: black;\r
+ padding: 0 2px;\r
+ cursor: pointer;\r
+ cursor: hand;\r
+ height: 1%;\r
+ }\r
+\r
+ div.group div.groupcontent {\r
+ margin-left: 10px;\r
+ padding-bottom: 2px;\r
+ overflow: visible;\r
+ }\r
+\r
+ div.group div.expanded {\r
+ display: block;\r
+ }\r
+\r
+ div.group div.collapsed {\r
+ display: none;\r
+ }\r
+\r
+ *.logentry {\r
+ overflow: visible;\r
+ display: none;\r
+ white-space: pre;\r
+ }\r
+\r
+ span.pre {\r
+ white-space: pre;\r
+ }\r
+ \r
+ pre.unwrapped {\r
+ display: inline !important;\r
+ }\r
+\r
+ pre.unwrapped pre.pre, div.wrapped pre.pre {\r
+ display: inline;\r
+ }\r
+\r
+ div.wrapped pre.pre {\r
+ white-space: normal;\r
+ }\r
+\r
+ div.wrapped {\r
+ display: none;\r
+ }\r
+\r
+ body.searching *.logentry span.currentmatch {\r
+ color: white !important;\r
+ background-color: green !important;\r
+ }\r
+\r
+ body.searching div.searchhighlight *.logentry span.searchterm {\r
+ color: black;\r
+ background-color: yellow;\r
+ }\r
+\r
+ div.wrap *.logentry {\r
+ white-space: normal !important;\r
+ border-width: 0 0 1px 0;\r
+ border-color: #dddddd;\r
+ border-style: dotted;\r
+ }\r
+\r
+ div.wrap #log_wrapped, #log_unwrapped {\r
+ display: block;\r
+ }\r
+\r
+ div.wrap #log_unwrapped, #log_wrapped {\r
+ display: none;\r
+ }\r
+\r
+ div.wrap *.logentry span.pre {\r
+ overflow: visible;\r
+ white-space: normal;\r
+ }\r
+\r
+ div.wrap *.logentry pre.unwrapped {\r
+ display: none;\r
+ }\r
+\r
+ div.wrap *.logentry span.wrapped {\r
+ display: inline;\r
+ }\r
+\r
+ div.searchfilter *.searchnonmatch {\r
+ display: none !important;\r
+ }\r
+\r
+ div#log *.TRACE, label#label_TRACE {\r
+ color: #666666;\r
+ }\r
+\r
+ div#log *.DEBUG, label#label_DEBUG {\r
+ color: green;\r
+ }\r
+\r
+ div#log *.INFO, label#label_INFO {\r
+ color: #000099;\r
+ }\r
+\r
+ div#log *.WARN, label#label_WARN {\r
+ color: #999900;\r
+ }\r
+\r
+ div#log *.ERROR, label#label_ERROR {\r
+ color: red;\r
+ }\r
+\r
+ div#log *.FATAL, label#label_FATAL {\r
+ color: #660066;\r
+ }\r
+\r
+ div.TRACE#log *.TRACE,\r
+ div.DEBUG#log *.DEBUG,\r
+ div.INFO#log *.INFO,\r
+ div.WARN#log *.WARN,\r
+ div.ERROR#log *.ERROR,\r
+ div.FATAL#log *.FATAL {\r
+ display: block;\r
+ }\r
+\r
+ div#log div.separator {\r
+ background-color: #cccccc;\r
+ margin: 5px 0;\r
+ line-height: 1px;\r
+ }\r
+ </style>\r
+ </head>\r
+\r
+ <body id="body">\r
+ <div id="switchesContainer">\r
+ <div id="switches">\r
+ <div id="levels" class="toolbar">\r
+ Filters:\r
+ <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>\r
+ <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>\r
+ <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>\r
+ <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>\r
+ <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>\r
+ <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>\r
+ <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>\r
+ </div>\r
+ <div id="search" class="toolbar">\r
+ <label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />\r
+ <input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />\r
+ <input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>\r
+ <input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>\r
+ <input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>\r
+ <div id="searchNav">\r
+ <input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />\r
+ <input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />\r
+ <input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>\r
+ <input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>\r
+ </div>\r
+ </div>\r
+ <div id="options" class="toolbar">\r
+ Options:\r
+ <input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>\r
+ <input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>\r
+ <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>\r
+ <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>\r
+ <input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages" />\r
+ <input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />\r
+ <input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />\r
+ </div>\r
+ </div>\r
+ </div>\r
+ <div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>\r
+ <div id="commandLine" class="toolbar">\r
+ <div id="commandLineContainer">\r
+ <input type="text" id="command" title="Enter a JavaScript command here and hit return or press 'Evaluate'" />\r
+ <input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />\r
+ </div>\r
+ </div>\r
+ </body>\r
+</html>\r
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript basic demo</title>\r
+ <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />\r
+ <meta name="author" content="Tim Down - tim@log4javascript.org" />\r
+ <meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />\r
+ <meta name="robots" content="all" />\r
+ <link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />\r
+ <script type="text/javascript" src="../js/log4javascript.js"></script>\r
+ <script type="text/javascript">\r
+ // <![CDATA[\r
+ var log = log4javascript.getLogger("main");\r
+ var appender = new log4javascript.PopUpAppender();\r
+ log.addAppender(appender);\r
+ log.debug("This is debugging message from the log4javascript basic demo page");\r
+\r
+ var words = ["Watford", "eased", "their", "relegation", "fears", "with", "a", "win",\r
+ "against", "a", "Charlton", "side", "who", "slipped", "further", "towards", "the",\r
+ "drop", "Don", "Cowie", "drilled", "in", "a", "shot", "to", "put", "the", "Hornets",\r
+ "ahead", "before", "Tresor", "Kandol", "ended", "a", "powerful", "run", "by",\r
+ "rounding", "keeper", "Scott", "Loach", "and", "slotting", "in", "to", "level"\r
+ ];\r
+\r
+ var loaded = false;\r
+\r
+ function generateRandom() {\r
+ var numberOfEntries = parseInt(document.getElementById("numberOfLogEntries").value);\r
+ for (var i = 0; i < numberOfEntries; i++) {\r
+ var numberOfWords = 1 + Math.floor(10 * Math.random());\r
+ var entryWords = [];\r
+ for (var j = 0; j < numberOfWords; j++) {\r
+ entryWords.push(words[Math.floor(Math.random() * words.length)]);\r
+ }\r
+ var entryMessage = entryWords.join(" ");\r
+ var levelNum = Math.floor(Math.random() * 6);\r
+ switch (levelNum) {\r
+ case 0:\r
+ log.trace(entryMessage);\r
+ break;\r
+ case 1:\r
+ log.debug(entryMessage);\r
+ break;\r
+ case 2:\r
+ log.info(entryMessage);\r
+ break;\r
+ case 3:\r
+ log.warn(entryMessage);\r
+ break;\r
+ case 4:\r
+ log.error(entryMessage);\r
+ break;\r
+ case 5:\r
+ log.fatal(entryMessage);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ function generateObjectExpansion() {\r
+ var debugObj = {\r
+ a: {\r
+ b: "stuff",\r
+ c: 3,\r
+ d: {\r
+ e: ["a", "b", "c"]\r
+ }\r
+ },\r
+ f: "Things",\r
+ g: 5\r
+ };\r
+ log.debug(debugObj);\r
+ }\r
+\r
+ function generateError() {\r
+ try {\r
+ throw new Error("Made up error");\r
+ } catch (ex) {\r
+ log.error("Logging an error!", ex);\r
+ }\r
+ }\r
+ // ]]>\r
+ </script>\r
+ </head>\r
+ <body onload="loaded = true; document.getElementById('enabled').checked = true;">\r
+ <div id="container" class="nonav">\r
+ <div id="header">\r
+ <h1><a href="/docs/index.html">log4javascript</a></h1>\r
+ </div>\r
+ <div id="content">\r
+ <div id="nav">\r
+ <a class="navitem" href="../index.html">home</a>\r
+ | <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>\r
+ | <a class="navitem" href="../docs/index.html">docs</a>\r
+ | <a class="navitem" href="../docs/quickstart.html">quick start</a>\r
+ | <a class="navitem" href="index.html">demos</a>\r
+ | <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>\r
+ | <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>\r
+ </div>\r
+ <h1>log4javascript basic demo</h1>\r
+ <p>\r
+ <em><strong>NB.</strong> Since the demo below uses pop-up windows, you will\r
+ need to disable any pop-up blockers you may have for it to work.</em>\r
+ </p>\r
+ <p>\r
+ This demo demonstrates the default logger. For more options, please see the\r
+ <a href="index.html">demos area</a>.\r
+ </p>\r
+ <p>\r
+ Enter a log message below and click on one of the buttons to log\r
+ your message at your desired level. You can then filter by\r
+ log level, toggle word-wrapping and perform text and regular\r
+ expression searches on the log entries.\r
+ </p>\r
+ <div class="example">\r
+ <input type="text" id="logText" value="Put log message here" />\r
+ <input type="button" value="debug" onclick="log.debug(document.getElementById('logText').value)" />\r
+ <input type="button" value="info" onclick="log.info(document.getElementById('logText').value)" />\r
+ <input type="button" value="warn" onclick="log.warn(document.getElementById('logText').value)" />\r
+ <input type="button" value="error" onclick="log.error(document.getElementById('logText').value)" />\r
+ <input type="button" value="fatal" onclick="log.fatal(document.getElementById('logText').value)" />\r
+ <br />\r
+ <input type="button" value="assert 1 equals 1" onclick="log.assert(1 === 1)" />\r
+ <input type="button" value="assert 1 equals 2" onclick="log.assert(1 === 2)" />\r
+ <br />\r
+ Generate <input type="text" size="5" id="numberOfLogEntries" value="50" /> random log entries\r
+ <input type="button" value="go" onclick="generateRandom()" />\r
+ <br />\r
+ <input type="button" value="Log exception" onclick="generateError()" />\r
+ <input type="button" value="Log example object" onclick="generateObjectExpansion()" />\r
+ <br />\r
+ <input type="checkbox" id="enabled" onclick="log4javascript.setEnabled(this.checked)" checked="checked" /> <label for="enabled">logging enabled</label>\r
+ <br />\r
+ <input type="text" id="groupName" value="Group name" />\r
+ <input type="button" value="group" onclick="log.group(document.getElementById('groupName').value)" />\r
+ <input type="button" value="end group" onclick="log.groupEnd()" />\r
+ <br />\r
+ <input type="text" id="timerName" value="Example timer name" />\r
+ <input type="button" value="start timer" onclick="log.time(document.getElementById('timerName').value)" />\r
+ <input type="button" value="end timer" onclick="log.timeEnd(document.getElementById('timerName').value)" />\r
+ </div>\r
+ </div>\r
+ <br class="clear" />\r
+ <div id="footer">\r
+ <span class="externallinkinfo">\r
+ <strong>NB.</strong> All external links open in a new window.\r
+ </span>\r
+ Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>\r
+ <br />\r
+ log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"\r
+ title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,\r
+ Version 2.0</a>\r
+\r
+ </div>\r
+ </div>\r
+\r
+ </body>\r
+</html>\r
--- /dev/null
+<html>\r
+<head><title>Blank page</title></head>\r
+<body></body>\r
+</html>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript demos</title>\r
+ <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />\r
+ <meta name="author" content="Tim Down - tim@log4javascript.org" />\r
+ <meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />\r
+ <meta name="robots" content="all" />\r
+ <link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />\r
+ </head>\r
+ <body>\r
+ <div id="container" class="nonav">\r
+ <div id="header">\r
+ <h1><a href="/docs/index.html">log4javascript</a></h1>\r
+ </div>\r
+ <div id="content">\r
+ <div id="nav">\r
+ <a class="navitem" href="../index.html">home</a>\r
+ | <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>\r
+ | <a class="navitem" href="../docs/index.html">docs</a>\r
+ | <a class="navitem" href="../docs/quickstart.html">quick start</a>\r
+ | <span class="navitem">demos</span>\r
+ | <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>\r
+ | <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>\r
+ </div>\r
+ <h1>log4javascript demos</h1>\r
+ <ul>\r
+ <li><a href="basic.html">Basic demo</a></li>\r
+ <li><a href="inpage.html">In-page console demo</a></li>\r
+ <li><a href="lite.html">log4javascript Lite demo</a></li>\r
+ </ul>\r
+ </div>\r
+ <br class="clear" />\r
+ <div id="footer">\r
+ <span class="externallinkinfo">\r
+ <strong>NB.</strong> All external links open in a new window.\r
+ </span>\r
+ Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>\r
+ <br />\r
+ log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"\r
+ title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,\r
+ Version 2.0</a>\r
+\r
+ </div>\r
+ </div>\r
+\r
+ </body>\r
+</html>\r
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript in-page console demo</title>\r
+ <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />\r
+ <meta name="author" content="Tim Down - tim@log4javascript.org" />\r
+ <meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />\r
+ <meta name="robots" content="all" />\r
+ <link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />\r
+ <script type="text/javascript" src="../js/log4javascript_uncompressed.js"></script>\r
+ <script type="text/javascript">\r
+ // <![CDATA[\r
+ var log = log4javascript.getLogger("main");\r
+ var appender = new log4javascript.InPageAppender();\r
+ log.addAppender(appender);\r
+ log.debug("This is a debugging message from the log4javascript in-page page");\r
+\r
+ var words = ["Watford", "eased", "their", "relegation", "fears", "with", "a", "win",\r
+ "against", "a", "Charlton", "side", "who", "slipped", "further", "towards", "the",\r
+ "drop", "Don", "Cowie", "drilled", "in", "a", "shot", "to", "put", "the", "Hornets",\r
+ "ahead", "before", "Tresor", "Kandol", "ended", "a", "powerful", "run", "by",\r
+ "rounding", "keeper", "Scott", "Loach", "and", "slotting", "in", "to", "level"\r
+ ];\r
+\r
+ var loaded = false;\r
+\r
+ function generateRandom() {\r
+ var numberOfEntries = parseInt(document.getElementById("numberOfLogEntries").value);\r
+ for (var i = 0; i < numberOfEntries; i++) {\r
+ var numberOfWords = 1 + Math.floor(10 * Math.random());\r
+ var entryWords = [];\r
+ for (var j = 0; j < numberOfWords; j++) {\r
+ entryWords.push(words[Math.floor(Math.random() * words.length)]);\r
+ }\r
+ var entryMessage = entryWords.join(" ");\r
+ var levelNum = Math.floor(Math.random() * 6);\r
+ switch (levelNum) {\r
+ case 0:\r
+ log.trace(entryMessage);\r
+ break;\r
+ case 1:\r
+ log.debug(entryMessage);\r
+ break;\r
+ case 2:\r
+ log.info(entryMessage);\r
+ break;\r
+ case 3:\r
+ log.warn(entryMessage);\r
+ break;\r
+ case 4:\r
+ log.error(entryMessage);\r
+ break;\r
+ case 5:\r
+ log.fatal(entryMessage);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ \r
+ var consoleVisible = true;\r
+ \r
+ function toggleConsole(button) {\r
+ if (consoleVisible) {\r
+ appender.hide();\r
+ button.value = "Show console";\r
+ consoleVisible = false;\r
+ } else {\r
+ appender.show();\r
+ button.value = "Hide console";\r
+ consoleVisible = true;\r
+ }\r
+ }\r
+\r
+ function generateObjectExpansion() {\r
+ var debugObj = {\r
+ a: {\r
+ b: "stuff",\r
+ c: 3,\r
+ d: {\r
+ e: ["a", "b", "c"]\r
+ }\r
+ },\r
+ f: "Things",\r
+ g: 5\r
+ };\r
+ log.debug(debugObj);\r
+ }\r
+\r
+ function generateError() {\r
+ try {\r
+ throw new Error("Made up error");\r
+ } catch (ex) {\r
+ log.error("Logging an error!", ex);\r
+ }\r
+ }\r
+ // ]]>\r
+ </script>\r
+ </head>\r
+ <body>\r
+ <div id="container" class="nonav">\r
+ <div id="header">\r
+ <h1><a href="/docs/index.html">log4javascript</a></h1>\r
+ </div>\r
+ <div id="content">\r
+ <div id="nav">\r
+ <a class="navitem" href="../index.html">home</a>\r
+ | <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>\r
+ | <a class="navitem" href="../docs/index.html">docs</a>\r
+ | <a class="navitem" href="../docs/quickstart.html">quick start</a>\r
+ | <a class="navitem" href="index.html">demos</a>\r
+ | <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>\r
+ | <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>\r
+ </div>\r
+ <h1>log4javascript in-page console demo</h1>\r
+ <p>\r
+ This demo demonstrates an in-page logger. The example uses the default behaviour, which\r
+ is to place the log console in a fixed area at the bottom of the page. However, the\r
+ console may be placed inside any element in the page. To do this, you may specify the ID\r
+ of the element (even if the page has not yet loaded) or a reference to the element itself.\r
+ </p>\r
+ <p>\r
+ Enter a log message below and click on one of the buttons to log\r
+ your message at your desired level. You can then filter by\r
+ log level, toggle word-wrapping and perform text and regular\r
+ expression searches on the log entries.\r
+ </p>\r
+ <div class="example">\r
+ <input type="button" value="Hide console" onclick="toggleConsole(this)" />\r
+ <br />\r
+ <input type="text" id="logText" value="Put log message here" />\r
+ <input type="button" value="debug" onclick="log.debug(document.getElementById('logText').value)" />\r
+ <input type="button" value="info" onclick="log.info(document.getElementById('logText').value)" />\r
+ <input type="button" value="warn" onclick="log.warn(document.getElementById('logText').value)" />\r
+ <input type="button" value="error" onclick="log.error(document.getElementById('logText').value)" />\r
+ <input type="button" value="fatal" onclick="log.fatal(document.getElementById('logText').value)" />\r
+ <br />\r
+ <input type="button" value="assert 1 equals 1" onclick="log.assert(1 === 1)" />\r
+ <input type="button" value="assert 1 equals 2" onclick="log.assert(1 === 2)" />\r
+ <br />\r
+ Generate <input type="text" size="5" id="numberOfLogEntries" value="50" /> random log entries\r
+ <input type="button" value="go" onclick="generateRandom()" />\r
+ <br />\r
+ <input type="button" value="Log exception" onclick="generateError()" />\r
+ <input type="button" value="Log example object" onclick="generateObjectExpansion()" />\r
+ <br />\r
+ <input type="checkbox" id="enabled" onclick="log4javascript.setEnabled(this.checked)" checked="checked" /> <label for="enabled">logging enabled</label>\r
+ <br />\r
+ <input type="text" id="groupName" value="Group name" />\r
+ <input type="button" value="group" onclick="log.group(document.getElementById('groupName').value)" />\r
+ <input type="button" value="end group" onclick="log.groupEnd()" />\r
+ <br />\r
+ <input type="text" id="timerName" value="Example timer name" />\r
+ <input type="button" value="start timer" onclick="log.time(document.getElementById('timerName').value)" />\r
+ <input type="button" value="end timer" onclick="log.timeEnd(document.getElementById('timerName').value)" />\r
+ </div>\r
+ </div>\r
+ <br class="clear" />\r
+ <div id="log"></div>\r
+ <div id="footer">\r
+ <span class="externallinkinfo">\r
+ <strong>NB.</strong> All external links open in a new window.\r
+ </span>\r
+ Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>\r
+ <br />\r
+ log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"\r
+ title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,\r
+ Version 2.0</a>\r
+\r
+ </div>\r
+ </div>\r
+\r
+ </body>\r
+</html>\r
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript lite demo</title>\r
+ <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />\r
+ <meta name="author" content="Tim Down - tim@log4javascript.org" />\r
+ <meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />\r
+ <meta name="robots" content="all" />\r
+ <link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />\r
+ <script type="text/javascript" src="../js/log4javascript_lite.js"></script>\r
+ <script type="text/javascript">\r
+ // <![CDATA[\r
+ var log = log4javascript.getDefaultLogger();\r
+ log.debug("This is debugging message from the log4javascript lite demo page");\r
+\r
+ var words = ["Boothroyd", "who", "took", "over", "two", "years",\r
+ "ago", "and", "continues", "to", "maintain", "that", "the",\r
+ "club", "are", "building", "for", "the", "future", "made",\r
+ "six", "changes", "and", "gave", "a", "first", "Premiership",\r
+ "start", "to", "on-loan", "Brazilian", "midfielder",\r
+ "Douglas", "Rinaldi", "Darius", "Henderson", "and", "Steve",\r
+ "Kabba", "were", "two", "of", "the", "players", "restored",\r
+ "to", "the", "home", "side", "and", "were", "responsible",\r
+ "for", "giving", "Chelsea", "an", "uncomfortable", "start",\r
+ "which", "set", "the", "pattern", "for", "the", "match"\r
+ ];\r
+\r
+ var loaded = false;\r
+\r
+ function generateRandom() {\r
+ var numberOfEntries = parseInt(document.getElementById("numberOfLogEntries").value);\r
+ for (var i = 0; i < numberOfEntries; i++) {\r
+ var numberOfWords = 1 + Math.floor(10 * Math.random());\r
+ var entryWords = [];\r
+ for (var j = 0; j < numberOfWords; j++) {\r
+ entryWords.push(words[Math.floor(Math.random() * words.length)]);\r
+ }\r
+ var entryMessage = entryWords.join(" ");\r
+ var levelNum = Math.floor(Math.random() * 6);\r
+ switch (levelNum) {\r
+ case 0:\r
+ log.trace(entryMessage);\r
+ break;\r
+ case 1:\r
+ log.debug(entryMessage);\r
+ break;\r
+ case 2:\r
+ log.info(entryMessage);\r
+ break;\r
+ case 3:\r
+ log.warn(entryMessage);\r
+ break;\r
+ case 4:\r
+ log.error(entryMessage);\r
+ break;\r
+ case 5:\r
+ log.fatal(entryMessage);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ function generateObjectExpansion() {\r
+ var debugObj = {\r
+ a: {\r
+ b: "stuff",\r
+ c: 3,\r
+ d: {\r
+ e: ["a", "b", "c"]\r
+ }\r
+ },\r
+ f: "Things",\r
+ g: 5\r
+ };\r
+ log.debug(debugObj);\r
+ }\r
+\r
+ function generateError() {\r
+ try {\r
+ throw new Error("Made up error");\r
+ } catch (ex) {\r
+ log.error("Logging an error!", ex);\r
+ }\r
+ }\r
+ // ]]>\r
+ </script>\r
+ </head>\r
+ <body onload="loaded = true; document.getElementById('enabled').checked = true;">\r
+ <div id="container" class="nonav">\r
+ <div id="header">\r
+ <h1><a href="/docs/index.html">log4javascript</a></h1>\r
+ </div>\r
+ <div id="content">\r
+ <div id="nav">\r
+ <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>\r
+ | <a class="navitem" href="../docs/index.html">docs</a>\r
+ | <a class="navitem" href="../docs/quickstart.html">quick start</a>\r
+ | <a class="navitem" href="../docs/manual.html">manual</a>\r
+ | <a class="navitem" href="index.html">demos</a>\r
+ | <a class="navitem" href="http://www.timdown.co.uk/log4javascript" target="_blank">website</a>\r
+ </div>\r
+ <h1>log4javascript lite demo</h1>\r
+ <p>\r
+ <em><strong>NB.</strong> Since the demo below uses pop-up windows, you will\r
+ need to disable any pop-up blockers you may have for it to work.</em>\r
+ </p>\r
+ <p>\r
+ This demo demonstrates the lite edition of log4javascript.\r
+ </p>\r
+ <p>\r
+ Enter a log message below and click on one of the buttons to log\r
+ your message at your desired level.\r
+ </p>\r
+ <div class="example">\r
+ <input type="text" id="logText" value="Put log message here" />\r
+ <input type="button" value="trace" onclick="log.trace(document.getElementById('logText').value)" />\r
+ <input type="button" value="debug" onclick="log.debug(document.getElementById('logText').value)" />\r
+ <input type="button" value="info" onclick="log.info(document.getElementById('logText').value)" />\r
+ <input type="button" value="warn" onclick="log.warn(document.getElementById('logText').value)" />\r
+ <input type="button" value="error" onclick="log.error(document.getElementById('logText').value)" />\r
+ <input type="button" value="fatal" onclick="log.fatal(document.getElementById('logText').value)" />\r
+ <br />\r
+ Generate <input type="text" size="5" id="numberOfLogEntries" value="50" /> random log entries\r
+ <input type="button" value="go" onclick="generateRandom()" />\r
+ <br />\r
+ <input type="button" value="Log exception" onclick="generateError()" />\r
+ <input type="button" value="Log example object" onclick="generateObjectExpansion()" />\r
+ <br />\r
+ <input type="checkbox" id="enabled" onclick="log4javascript.setEnabled(this.checked)" checked="checked" /> <label for="enabled">logging enabled</label>\r
+ <br />\r
+ </div>\r
+ </div>\r
+ <br class="clear" />\r
+ <div id="footer">\r
+ <span class="externallinkinfo">\r
+ <strong>NB.</strong> All external links open in a new window.\r
+ </span>\r
+ Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>\r
+ <br />\r
+ log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"\r
+ title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,\r
+ Version 2.0</a>\r
+\r
+ </div>\r
+ </div>\r
+ </body>\r
+</html>\r
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript - backwards incompatibilities in version 1.4</title>\r
+ <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />\r
+ <meta name="author" content="Tim Down - tim@log4javascript.org" />\r
+ <meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />\r
+ <meta name="robots" content="all" />\r
+ <link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />\r
+ </head>\r
+ <body>\r
+ <div id="container" class="nonav">\r
+ <div id="header">\r
+ <h1><a href="/index.html">log4javascript</a></h1>\r
+ </div>\r
+ <div id="content">\r
+ <div id="nav">\r
+ <a class="navitem" href="../index.html">home</a>\r
+ | <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>\r
+ | <a class="navitem" href="index.html">docs</a>\r
+ | <a class="navitem" href="quickstart.html">quick start</a>\r
+ | <a class="navitem" href="../demos/index.html">demos</a>\r
+ | <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>\r
+ | <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>\r
+ </div>\r
+ <h1>Backwards incompatibilities in log4javascript 1.4</h1>\r
+ <ul>\r
+ <li>\r
+ Loggers are now hierarchical. This means logger names containing full stops have\r
+ special meaning. For example, from version 1.4 the logger named <code>myapp.ajax</code>\r
+ by default inherits all the appenders of the logger named <code>myapp</code>, while\r
+ prior to version 1.4 these loggers would be entirely independent;\r
+ </li>\r
+ <li>\r
+ The signature of the <code>log</code> method of <code>Logger</code> has changed.\r
+ However, you should not use this method directly; instead, use one of the level-specific\r
+ wrapper functions (<code>debug</code>, <code>info</code>, <code>error</code> etc.);\r
+ </li>\r
+ <li>\r
+ Appenders can no longer be configured via constructor parameters. Instead you must use\r
+ setter methods;\r
+ </li>\r
+ <li>\r
+ The format of requests sent via <code><a href="manual.html#ajaxappender">AjaxAppender</a></code>\r
+ has changed when using <code><a href="manual.html#jsonlayout">JsonLayout</a></code> or\r
+ <code><a href="manual.html#xmllayout">XmlLayout</a></code>: the formatted log messages are sent\r
+ as a name-value pair (with default name <code>data</code>) rather than a single unencoded string;\r
+ </li>\r
+ <li>\r
+ All timestamps returned by <code><a href="manual.html#xmllayout">XmlLayout</a></code>,\r
+ <code><a href="manual.html#jsonlayout">JsonLayout</a></code> and\r
+ <code><a href="manual.html#httppostdatlayout">HttpPostDataLayout</a></code> are\r
+ now measured in milliseconds since January 1st 1970 (previously they were returned\r
+ as seconds since January 1st 1970);\r
+ </li>\r
+ <li>\r
+ The constructors for <a href="manual.html#jsonlayout">JsonLayout</a> and\r
+ <a href="manual.html#httppostdatlayout">HttpPostDataLayout</a> have changed; the property names\r
+ used for the properties of the logging event are now set via <code>setKeys</code> rather than\r
+ in the constructor;\r
+ </li>\r
+ <li>\r
+ <code>setReadable</code> has been removed from <a href="manual.html#jsonlayout">JsonLayout</a>.\r
+ The <code>readable</code> property should now be set via the constructor;\r
+ </li>\r
+ <li>\r
+ <code>addErrorListener</code> and <code>removeErrorListener</code> removed from\r
+ the <code>log4javascript</code> object and replaced with the more generic\r
+ <code><a href="manual.html#log4javascriptaddeventlistener">addEventListener</a></code>\r
+ and <code>removeEventListener</code> methods. The listener functions are passed\r
+ different parameters.\r
+ </li>\r
+ </ul>\r
+ </div>\r
+ <div id="footer">\r
+ <span class="externallinkinfo">\r
+ <strong>NB.</strong> All external links open in a new window.\r
+ </span>\r
+ Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>\r
+ <br />\r
+ log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"\r
+ title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,\r
+ Version 2.0</a>\r
+\r
+ </div>\r
+ </div>\r
+\r
+ </body>\r
+</html>\r
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en" >\r
+ <head>\r
+ <title>log4javascript 1.4 distribution</title>\r
+ <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />\r
+ <meta name="author" content="Tim Down - tim@log4javascript.org" />\r
+ <meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />\r
+ <meta name="robots" content="all" />\r
+ <link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />\r
+ </head>\r
+ <body>\r
+ <div id="container" class="nonav">\r
+ <div id="header">\r
+ <h1><a href="../index.html">log4javascript</a></h1>\r
+ </div>\r
+ <div id="content">\r
+ <div id="nav">\r
+ <a class="navitem" href="../index.html">home</a>\r
+ | <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>\r
+ | <a class="navitem" href="index.html">docs</a>\r
+ | <a class="navitem" href="quickstart.html">quick start</a>\r
+ | <a class="navitem" href="../demos/index.html">demos</a>\r
+ | <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>\r
+ | <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>\r
+ </div>\r
+ <h1>log4javascript 1.4 distribution</h1>\r
+ <p>\r
+ From version 1.4 the distribution includes three different editions of log4javascript:\r
+ </p>\r
+ <ul>\r
+ <li>\r
+ <div><strong>Standard Edition</strong></div>\r
+ <p>\r
+ Equivalent to log4javascript from earlier versions and suitable for general JavaScript\r
+ debugging and logging (including via Ajax).\r
+ </p>\r
+ </li>\r
+ <li>\r
+ <div><strong>Production Edition</strong></div>\r
+ <p>\r
+ Designed for use in production systems where the focus is solely on logging JavaScript\r
+ messages back to the server. Consequently this edition omits all appenders except\r
+ <a href="manual.html#ajaxappender">AjaxAppender</a>, resulting in a drastically reduced\r
+ file size compared to the standard edition.\r
+ </p>\r
+ </li>\r
+ <li>\r
+ <div><strong>Lite Edition</strong></div>\r
+ <p>\r
+ A lightweight version of log4javascript for quick page debugging. Included is a single logger\r
+ using a basic pop-up window appender with a fixed layout.\r
+ </p>\r
+ </li>\r
+ </ul>\r
+ <p>\r
+ Each edition comes in compressed and uncompressed versions. The compressed version is\r
+ functionally identical to the uncompressed version but has had whitespace and comments removed\r
+ and therefore downloads more quickly.\r
+ </p>\r
+ <p>\r
+ Each edition also comes with a stub version. This contains dummy implementations of all\r
+ log4javacript objects and methods in the public API, making it ideal for production environments\r
+ where logging is not required. Replacing the main log4javascript script file with this file\r
+ means that log calls may be left in production code. Compressed and uncompressed versions of\r
+ each stub are included.\r
+ </p>\r
+ <p>\r
+ Finally, each edition comes with a suite of unit tests, available as HTML pages in the\r
+ <code>test/</code> directory. Note that these tests crash old versions (pre-3.1) of Safari. Sorry.\r
+ </p>\r
+ </div>\r
+ <div id="footer">\r
+ <span class="externallinkinfo">\r
+ <strong>NB.</strong> All external links open in a new window.\r
+ </span>\r
+ Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>\r
+ <br />\r
+ log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"\r
+ title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,\r
+ Version 2.0</a>\r
+\r
+ </div>\r
+ </div>\r
+\r
+ </body>\r
+</html>\r
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript documentation</title>\r
+ <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />\r
+ <meta name="author" content="Tim Down - tim@log4javascript.org" />\r
+ <meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />\r
+ <meta name="robots" content="all" />\r
+ <link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />\r
+ </head>\r
+ <body>\r
+ <div id="container" class="nonav">\r
+ <div id="header">\r
+ <h1><a href="../index.html">log4javascript</a></h1>\r
+ <div id="nav">\r
+ <a class="navitem" href="../index.html">home</a>\r
+ | <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>\r
+ | <span class="navitem">docs</span>\r
+ | <a class="navitem" href="quickstart.html">quick start</a>\r
+ | <a class="navitem" href="../demos/index.html">demos</a>\r
+ | <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>\r
+ | <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>\r
+ </div>\r
+ </div>\r
+ <div id="content">\r
+ <h1>log4javascript 1.4 documentation</h1>\r
+ <div id="links">\r
+ <h2>Links</h2>\r
+ <ul>\r
+ <li><a href="quickstart.html">Quick start</a></li>\r
+ <li><a href="distribution.html">Details of the log4javascript distribution</a></li>\r
+ <li><a href="backwardsincompatibilities.html">Backwards incompatibilities</a></li>\r
+ <li><a href="whatsnew.html">What's new in this release</a></li>\r
+ <li><a href="../changelog.txt">Change log</a></li>\r
+ <li><a href="manual.html">log4javascript manual</a></li>\r
+ <li><a href="lite.html">log4javascript Lite</a></li>\r
+ <li><a href="manual_lite.html">log4javascript Lite manual</a></li>\r
+ <li><a href="../demos/basic.html">Basic demo</a></li>\r
+ <li><a href="../demos/ajax.html">Ajax demo</a></li>\r
+ </ul>\r
+ </div>\r
+ <div id="contents">\r
+ <h2>Contents</h2>\r
+ <ul>\r
+ <li><a href="#whatitis">What it is</a></li>\r
+ <li><a href="#whofor">Who it's for</a></li>\r
+ <li><a href="#previousversions">Note on previous versions</a></li>\r
+ <li><a href="#features">Features</a></li>\r
+ <li><a href="#browsers">Browser support</a></li>\r
+ <li><a href="#licence">Licence</a></li>\r
+ <li><a href="#furtherreading">Further reading</a></li>\r
+ </ul>\r
+ </div>\r
+ <div id="whatitis">\r
+ <h2>What it is</h2>\r
+ <p>\r
+ log4javascript is a JavaScript logging framework based on the Java\r
+ logging framework <a href="http://logging.apache.org/log4j/docs/index.html"\r
+ title="log4j home page (opens in new window)" target="_blank">log4j</a>.\r
+ </p>\r
+ <p>\r
+ log4javascript implements a subset of log4j (primarily loggers, appenders\r
+ and layouts) and has a few convenience methods of its own for\r
+ quick JavaScript development. It can be used to debug JavaScript\r
+ applications of all sizes, including Ajax applications.\r
+ </p>\r
+ <p>\r
+ If you just want to start using it, try the <a href="quickstart.html">quickstart\r
+ tutorial</a>.\r
+ </p>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="whofor">\r
+ <h2>Who it's for</h2>\r
+ <p>\r
+ log4javascript is aimed at JavaScript developers.\r
+ </p>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="previousversions">\r
+ <h2>Note on previous versions</h2>\r
+ <p>\r
+ Documentation for previous versions of log4javascript are not available here.\r
+ However, documentation is bundled with every previous version, all of which\r
+ are <a href="http://sourceforge.net/projects/log4javascript"\r
+ target="_blank" title="Download (opens in new window)">available to download</a>.\r
+ </p>\r
+ </div>\r
+ <div id="features">\r
+ <h2>Features</h2>\r
+ <ul>\r
+ <li>can be initialized with one JavaScript include and one line of code;</li>\r
+ <li>\r
+ by default logs to a pop-up console window with powerful search (including\r
+ regular expression) and filtering features. This console window can also\r
+ be used inline as an iframe in the main page;\r
+ </li>\r
+ <li>\r
+ can send log messages to the server via HTTP (Ajax, if you like);\r
+ </li>\r
+ <li>\r
+ highly configurable using familiar methods from log4j, including the\r
+ powerful <code><a href="manual.html#patternlayout">PatternLayout</a></code>\r
+ which gives the developer complete control over the format of the log messages.\r
+ </li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="browsers">\r
+ <h2>Browser support</h2>\r
+ <h3>Fully supported browsers:</h3>\r
+ <ul>\r
+ <li>All versions Firefox back to 0.6</li>\r
+ <li>Other Mozilla-based browsers, as far back as Netscape 7</li>\r
+ <li>Internet Explorer 5 and higher for Windows</li>\r
+ <li>Safari 1.3 and higher (untested on earlier versions)</li>\r
+ <li>Opera 8.01 and higher (pre- version 9 browsers have a rendering\r
+ bug related to scrolling that affects searching in PopUpAppender and InPageAppender)</li>\r
+ <li>Konqueror 3.4.3 and higher (untested on earlier versions)</li>\r
+ <li>Google Chrome</li>\r
+ </ul>\r
+ <h3>Partially supported browsers:</h3>\r
+ <ul>\r
+ <li>Older Mozilla-based browsers, e.g. Netscape 6.2 (generally OK except for\r
+ display problems searching and filtering PopUpAppender and InPageAppender)</li>\r
+ <li>Opera 7.0 - 8.0 (InPageAppender not supported until version 7.5, plus some display\r
+ problems searching PopUpAppender and InPageAppender. AjaxAppender not supported at all)</li>\r
+ </ul>\r
+ <h3>Unsupported browsers:</h3>\r
+ <ul>\r
+ <li>\r
+ Internet Explorer for Mac. There are no plans to make log4javascript work\r
+ in this browser.\r
+ </li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="licence">\r
+ <h2>Licence</h2>\r
+ <p>\r
+ log4javascript is licenced under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"\r
+ title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,\r
+ Version 2.0</a>. The Apache website has <a href="http://www.apache.org/foundation/licence-FAQ.html#WhatDoesItMEAN"\r
+ title="View licence (opens in new window)" target="_blank">more details</a>.\r
+ </p>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="furtherreading">\r
+ <h2>Further reading</h2>\r
+ <p>\r
+ In order to gain an understanding of the ideas behind log4j and therefore log4javascript,\r
+ I highly recommend reading the <a href="http://logging.apache.org/log4j/docs/manual.html">short\r
+ introduction to log4j</a> from the log4j website. log4javascript borrows heavily from\r
+ log4j but does not carry over all its concepts - for example, Filters and Renderers are not\r
+ implemented.\r
+ </p>\r
+ <p>\r
+ <a href="manual.html">The full log4javascript manual</a>\r
+ </p>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ </div>\r
+ <div id="footer">\r
+ <span class="externallinkinfo">\r
+ <strong>NB.</strong> All external links open in a new window.\r
+ </span>\r
+ Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>\r
+ <br />\r
+ log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"\r
+ title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,\r
+ Version 2.0</a>\r
+\r
+ </div>\r
+ </div>\r
+\r
+ </body>\r
+</html>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en" >\r
+ <head>\r
+ <title>log4javascript 1.4 Lite</title>\r
+ <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />\r
+ <meta name="author" content="Tim Down - tim@log4javascript.org" />\r
+ <meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />\r
+ <meta name="robots" content="all" />\r
+ <link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />\r
+ <style type="text/css">\r
+ .visibleifabletocopy {\r
+ display: none;\r
+ }\r
+ \r
+ body.abletocopy .visibleifabletocopy {\r
+ display: block;\r
+ }\r
+ </style>\r
+ <script type="text/javascript">\r
+ function copyCode() {\r
+ if (window.clipboardData && clipboardData.setData) {\r
+ clipboardData.setData("Text", code);\r
+ alert("Code copied to clipboard.")\r
+ }\r
+ }\r
+ \r
+ var code;\r
+ \r
+ window.onload = function() {\r
+ var textArea = document.getElementById("codetextarea");\r
+ code = textArea.value;\r
+ textArea.select(); \r
+ if (window.clipboardData && clipboardData.setData) {\r
+ document.body.className = "abletocopy";\r
+ }\r
+ };\r
+ </script>\r
+ <link rel="stylesheet" type="text/css" media="screen,print" href="lite.css" title="Default" />\r
+ </head>\r
+ <body>\r
+ <div id="container" class="nonav">\r
+ <div id="header">\r
+ <h1><a href="../index.html">log4javascript</a></h1>\r
+ </div>\r
+ <div id="content">\r
+ <div id="nav">\r
+ <a class="navitem" href="../index.html">home</a>\r
+ | <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>\r
+ | <a class="navitem" href="index.html">docs</a>\r
+ | <a class="navitem" href="quickstart.html">quick start</a>\r
+ | <a class="navitem" href="../demos/index.html">demos</a>\r
+ | <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>\r
+ | <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>\r
+ </div>\r
+ <h1>log4javascript 1.4 Lite</h1>\r
+ <h2>Contents</h2>\r
+ <ul>\r
+ <li><a href="#intro">Introduction</a></li>\r
+ <li><a href="#code">Code</a></li>\r
+ <li><a href="#api">API</a></li>\r
+ </ul>\r
+ <div id="intro">\r
+ <h2>Introduction</h2>\r
+ <p>\r
+ log4javascript Lite is designed to be a basic, lightweight, cross-browser logging tool. It\r
+ provides functions to log messages of different severity to a pop-up window using the exactly\r
+ the same syntax as log4javascript.\r
+ </p>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="code">\r
+ <h2>Code</h2>\r
+ <p>\r
+ You can copy the code for log4javascript Lite below:\r
+ </p>\r
+ <textarea id="codetextarea" cols="80" rows="10">\r
+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];}\r
+this.length--;return firstItem;}};}\r
+var log4javascript;(function(){var newLine="\r\n";function Log4JavaScript(){}\r
+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);}}\r
+function getUrlFileName(url){var lastSlashIndex=Math.max(url.lastIndexOf("/"),url.lastIndexOf("\\"));return url.substr(lastSlashIndex+1);}\r
+function getExceptionStringRep(ex){if(ex){var exStr="Exception: "+getExceptionMessage(ex);try{if(ex.lineNumber){exStr+=" on line number "+ex.lineNumber;}\r
+if(ex.fileName){exStr+=" in file "+getUrlFileName(ex.fileName);}}catch(localEx){}\r
+if(showStackTraces&&ex.stack){exStr+=newLine+"Stack trace:"+newLine+ex.stack;}\r
+return exStr;}\r
+return null;}\r
+function isError(err){return(err instanceof Error);}\r
+function bool(obj){return Boolean(obj);}\r
+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=" ";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;}}\r
+function finalInit(){popUpLoaded=true;appendQueuedLoggingEvents();}\r
+function writeHtml(doc){var lines=getConsoleHtmlLines();doc.open();for(var i=0,len=lines.length;i<len;i++){doc.writeln(lines[i]);}\r
+doc.close();}\r
+function pollConsoleWindow(){function pollConsoleWindowLoaded(){if(popUpLoaded){clearInterval(poll);}else if(bool(popUp)&&isLoaded(popUp)){clearInterval(poll);finalInit();}}\r
+var poll=setInterval(pollConsoleWindowLoaded,100);}\r
+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.");}}\r
+initialized=true;}\r
+function safeToAppend(){if(!popUpsBlocked&&!popUpClosed){if(popUp.closed){popUpClosed=true;return false;}\r
+if(!popUpLoaded&&popUp.loaded){popUpLoaded=true;}}\r
+return!popUpsBlocked&&popUpLoaded&&!popUpClosed;}\r
+function padWithZeroes(num,len){var str=""+num;while(str.length<len){str="0"+str;}\r
+return str;}\r
+function padWithSpaces(str,len){while(str.length<len){str+=" ";}\r
+return str;}\r
+this.append=function(loggingEvent){if(!initialized){init();}\r
+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)+":"+\r
+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;}\r
+popUp.log(currentLoggingEvent.level,formattedMessage);}\r
+if(focusPopUp){popUp.focus();}}}}\r
+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--;}\r
+var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];}\r
+var loggingEvent=new LoggingEvent(this,new Date(),level,messages,exception);appender.append(loggingEvent);}};this.setLevel=function(level){loggerLevel=level;};this.getLevel=function(){return loggerLevel;};}\r
+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();}\r
+return defaultLogger;};log4javascript.getLogger=log4javascript.getDefaultLogger;var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger();nullLogger.setLevel(Level.OFF);}\r
+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;})();\r
+</textarea>\r
+ <p class="visibleifabletocopy">\r
+ Press this button to copy the code to the clipboard:\r
+ <input type="button" value="Copy" onclick="copyCode()" />\r
+ </p>\r
+ <p>\r
+ You can either paste the above code inside a script tag:\r
+ </p>\r
+ <pre class="code">\r
+<script type="text/javascript">\r
+ ... [Code here]...\r
+</script>\r
+</pre>\r
+ <p>\r
+ ... or include the <code>log4javascript_lite.js</code> included in the distribution:\r
+ </p>\r
+ <pre class="code">\r
+<script type="text/javascript" src="log4javascript_lite.js"></script>\r
+</pre>\r
+ <pre class="code">\r
+<script type="text/javascript">\r
+ var log = log4javascript.getDefaultLogger();\r
+</script>\r
+</pre>\r
+ <p>\r
+ Using log4javascript Lite is identical to using log4javascript with its default logger:\r
+ </p>\r
+ <pre class="code">\r
+<script type="text/javascript">\r
+ var log = log4javascript.getDefaultLogger();\r
+ log.debug("What's going on here then?");\r
+</script>\r
+</pre>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="api">\r
+ <h2>API</h2>\r
+ <p>\r
+ The functions available in log4javascript Lite make up a small subset of those provided\r
+ by log4javascript proper. Each function is <strong>named and called identically to the equivalent\r
+ function in log4javascript</strong>. Full details can be found in the\r
+ <a href="manual_lite.html">log4javascript Lite manual</a>.\r
+ </p>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ </div>\r
+ <div id="footer">\r
+ <span class="externallinkinfo">\r
+ <strong>NB.</strong> All external links open in a new window.\r
+ </span>\r
+ Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>\r
+ <br />\r
+ log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"\r
+ title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,\r
+ Version 2.0</a>\r
+\r
+ </div>\r
+ </div>\r
+\r
+ </body>\r
+</html>\r
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript 1.4 manual</title>\r
+ <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />\r
+ <meta name="author" content="Tim Down - tim@log4javascript.org" />\r
+ <meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />\r
+ <meta name="robots" content="all" />\r
+ <link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />\r
+ </head>\r
+ <body>\r
+ <div id="container" class="nonav">\r
+ <div id="header">\r
+ <h1><a href="index.html">log4javascript</a></h1>\r
+ </div>\r
+ <div id="content">\r
+ <div id="nav">\r
+ <a class="navitem" href="../index.html">home</a>\r
+ | <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>\r
+ | <a class="navitem" href="index.html">docs</a>\r
+ | <a class="navitem" href="quickstart.html">quick start</a>\r
+ | <a class="navitem" href="../demos/index.html">demos</a>\r
+ | <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>\r
+ | <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>\r
+ </div>\r
+ <h1>log4javascript 1.4 manual</h1>\r
+ <h2>Contents</h2>\r
+ <ul>\r
+ <li><a href="#intro">Introduction</a></li>\r
+ <li><a href="#noteaboutlog4javascript">Note about the log4javascript object</a></li>\r
+ <li>\r
+ <a href="#loggersappenderslayoutslevels">Loggers, appenders, layouts and levels</a>\r
+ <ul>\r
+ <li><a href="#configuration">Configuring appenders</a></li>\r
+ <li><a href="#loggersappenderslayoutslevelsexample">Example</a></li>\r
+ </ul>\r
+ </li>\r
+ <li><a href="#log4javascript">log4javascript static properties/methods</a></li>\r
+ <li><a href="#levels">Levels</a></li>\r
+ <li><a href="#loggers">Loggers</a></li>\r
+ <li>\r
+ <a href="#appenders">Appenders</a>\r
+ <ul>\r
+ <li><a href="#appender">Appender</a></li>\r
+ <li><a href="#alertappender">AlertAppender</a></li>\r
+ <li><a href="#ajaxappender">AjaxAppender</a></li>\r
+ <li><a href="#popupappender">PopUpAppender</a></li>\r
+ <li><a href="#inpageappender">InPageAppender</a></li>\r
+ <li><a href="#browserconsoleappender">BrowserConsoleAppender</a></li>\r
+ </ul>\r
+ </li>\r
+ <li>\r
+ <a href="#layouts">Layouts</a>\r
+ <ul>\r
+ <li><a href="#layout">Layout</a></li>\r
+ <li><a href="#nulllayout">NullLayout</a></li>\r
+ <li><a href="#simplelayout">SimpleLayout</a></li>\r
+ <li><a href="#patternlayout">PatternLayout</a></li>\r
+ <li><a href="#xmllayout">XmlLayout</a></li>\r
+ <li><a href="#jsonlayout">JsonLayout</a></li>\r
+ <li><a href="#httppostdatalayout">HttpPostDataLayout</a></li>\r
+ </ul>\r
+ </li>\r
+ <li><a href="#enabling">Enabling / disabling log4javascript</a></li>\r
+ <li>\r
+ <a href="#errorhandling">log4javascript error handling</a>\r
+ <ul>\r
+ <li><a href="#loglog">LogLog</a></li>\r
+ </ul>\r
+ </li>\r
+ <li><a href="#differences">Differences between log4javascript and log4j</a></li>\r
+ </ul>\r
+ <div id="intro">\r
+ <h2>Introduction</h2>\r
+ <p>\r
+ Anyone who has done a reasonable amount of JavaScript development will be\r
+ familiar with <code>alert</code> as a means of debugging. For\r
+ a small script, it works fine. But for anything of greater complexity than,\r
+ say, a rollover script its shortcomings become apparent. The most obvious problem\r
+ is the endless clicking of 'OK'. Another problem is that for a page\r
+ heavily reliant on events generated from user actions, alerts\r
+ can actually alter the way the page behaves. One final problem is infinite loops:\r
+ without alerts, the browser will notice that the script has messed\r
+ up and will offer the user the chance to stop the script running. With an\r
+ alert inside an infinite loop, you're forced to kill the browser.\r
+ </p>\r
+ <p>\r
+ At the other end of the scale there is\r
+ <a href="http://www.mozilla.org/projects/venkman/" target="_blank">Venkman</a>,\r
+ a full-on JavaScript debugger for Mozilla-based browsers such as Firefox. Here\r
+ I have to confess that I simply have not put in the time to learn how to make\r
+ it work well for me and I suspect I am not alone.\r
+ </p>\r
+ <p>\r
+ Nowadays, easily the best option for day-to-day JavaScript development is the brilliant\r
+ <a href="http://www.getfirebug.com" title="Firebug home page (opens in new window)"\r
+ target="_blank">Firebug</a>, a Firefox plugin with built-in debugger, console, logging,\r
+ and profiler. It's a seriously impressive tool but by its very nature as a Firefox\r
+ plugin can only be used in one of the typical target browsers for mainstream web\r
+ development.\r
+ </p>\r
+ <p>\r
+ log4javascript was originally written as a cross-browser tool to ease the pain of JavaScript\r
+ debugging without the time investment required to use a debugger effectively. It requires\r
+ only a JavaScript include and one line of code to initialize with default settings.\r
+ Having for several years used log4j and its .NET port log4net, it was natural for me to\r
+ base it on log4j.\r
+ </p>\r
+ <p>\r
+ log4javascript is by no means the only JavaScript logging framework out there.\r
+ It is not even the only JavaScript implementation of log4j. It turns out the name\r
+ log4javascript is used by another JavaScript logging framework, and that the name log4js is\r
+ used by at least two other pieces of software; this version of log4javascript is unrelated\r
+ to any of those.\r
+ </p>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="noteaboutlog4javascript">\r
+ <h2>Note about the log4javascript object</h2>\r
+ <p>\r
+ All of log4javascript's instantiable classes are accessible via the log4javascript object, which\r
+ acts as a namespace. Therefore references to all class names must be preceded with "log4javascript.".\r
+ For example:\r
+ </p>\r
+ <p>\r
+ <code>var popUpAppender = new log4javascript.PopUpAppender();</code>\r
+ </p>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="loggersappenderslayoutslevels">\r
+ <h2>Loggers, Appenders, Layouts and Levels</h2>\r
+ <p>\r
+ A <em>logger</em> in log4javascript is the object on which log calls are\r
+ made. A logger may be assigned zero or more <em>appenders</em>.\r
+ An appender is an object that actually does the logging: for example,\r
+ a <code><a href="#popupappender">PopUpAppender</a></code> logs messages to\r
+ a pop-up console window while an <code><a href="#ajaxappender">AjaxAppender</a></code>\r
+ uses HTTP to send log messages back to the server. Each appender is assigned\r
+ a <em>layout</em>, which is responsible for formatting log messages that\r
+ are passed to an appender.\r
+ </p>\r
+ <p>\r
+ Every log message has a <em>level</em>. This is the severity of the message.\r
+ Available levels are <code>TRACE</code>, <code>DEBUG</code>, <code>INFO</code>,\r
+ <code>WARN</code>, <code>ERROR</code> and <code>FATAL</code> - these correspond to\r
+ the logging methods <code>trace</code>, <code>debug</code>, <code>info</code>,\r
+ <code>warn</code>, <code>error</code> and <code>fatal</code> of <code>Logger</code>.\r
+ Levels are ordered as follows: <code>TRACE</code> < <code>DEBUG</code> <\r
+ <code>INFO</code> < <code>WARN</code> < <code>ERROR</code> <\r
+ <code>FATAL</code>. This means the <code>FATAL</code> is the most severe and\r
+ <code>TRACE</code> the least. Also included are levels called <code>ALL</code>\r
+ and <code>OFF</code> intended to enable or disable all logging respectively.\r
+ </p>\r
+ <p>\r
+ Both loggers and appenders also have threshold levels (by default, <code>DEBUG</code>\r
+ for loggers and <code>ALL</code> for appenders).\r
+ Setting a level to either a logger or an appender disables log messages of severity\r
+ lower than that level. For instance, if a level of <code>INFO</code> is set on a\r
+ logger then only log messages of severity <code>INFO</code> or greater will be logged,\r
+ meaning <code>DEBUG</code> and <code>TRACE</code> messages will not be logged. If the\r
+ same logger had two appenders, one of level <code>DEBUG</code> and one of level\r
+ <code>WARN</code> then the first appender will still only log messages of\r
+ <code>INFO</code> or greater while the second appender will only log messages of level\r
+ <code>WARN</code> or greater.\r
+ </p>\r
+ <p>\r
+ This allows the developer fine control over which messages get logged where.\r
+ </p>\r
+ <div id="configuration">\r
+ <h3>Configuring appenders</h3>\r
+ <p>\r
+ From version 1.4, <strong>configuring appenders is only possible via configuration\r
+ methods</strong>. As the number of configuration options increases it becomes increasingly\r
+ undesirable to use constructor parameters, so support for it has been dropped.\r
+ </p>\r
+ </div>\r
+ <div id="loggersappenderslayoutslevelsexample">\r
+ <h3>Example</h3>\r
+ <p>\r
+ <strong>NB.</strong> The Ajax side of this example relies on having\r
+ server-side processing in place.\r
+ </p>\r
+ <p>\r
+ First, log4javascript is initialized, and a logger (actually the\r
+ anonymous logger) is assigned to a variable called <code>log</code>:\r
+ </p>\r
+ <pre class="code">\r
+<script type="text/javascript" src="log4javascript.js"></script>\r
+<script type="text/javascript">\r
+ //<![CDATA[\r
+ var log = log4javascript.getLogger();\r
+</pre>\r
+ <p>\r
+ <code>log</code> does not yet have any appenders, so a call to <code>log.debug()</code>\r
+ will do nothing as yet. For this example we will use a\r
+ <code><a href="#popupappender">PopUpAppender</a></code> for debugging purposes.\r
+ Since the lifespan of the messages displayed in the pop-up is only going to be the\r
+ same as that of the window, a <code><a href="#patternlayout">PatternLayout</a></code>\r
+ is used that displays the time of the message and not the date (note that this is\r
+ also true of PopUpAppender's default layout). The format of the string passed into\r
+ PatternLayout is explained <a href="#patternlayout">below</a>.\r
+ </p>\r
+ <pre class="code">\r
+ var popUpAppender = new log4javascript.PopUpAppender();\r
+ var popUpLayout = new log4javascript.PatternLayout("%d{HH:mm:ss} %-5p - %m%n");\r
+ popUpAppender.setLayout(popUpLayout);\r
+ log.addAppender(popUpAppender);\r
+</pre>\r
+ <p>\r
+ Suppose that we also want to send log messages to the server, but limited to\r
+ error messages only. To achieve this we use an\r
+ <code><a href="#ajaxappender">AjaxAppender</a></code>. Note that if no layout is\r
+ specified then for convenience a default layout is used; in the case of\r
+ AjaxAppender, that is <code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>,\r
+ which formats log messages as a standard HTTP POST string from which a simple\r
+ server-side script (not provided with log4javascript) will be able to extract\r
+ posted parameters. This is fine for our purposes:\r
+ </p>\r
+ <pre class="code">\r
+ var ajaxAppender = new log4javascript.AjaxAppender("myloggingservlet.do");\r
+ ajaxAppender.setThreshold(log4javascript.Level.<code>ERROR</code>);\r
+ log.addAppender(ajaxAppender);\r
+</pre>\r
+ <p>\r
+ Finally, some test log messages and the closing script tag:\r
+ </p>\r
+ <pre class="code">\r
+ log.debug("Debugging message (appears in pop-up)");\r
+ log.error("Error message (appears in pop-up and in server log)");\r
+ //]]>\r
+</script>\r
+</pre>\r
+ <p>\r
+ The full script:\r
+ </p>\r
+ <pre class="code">\r
+<script type="text/javascript" src="log4javascript.js"></script>\r
+<script type="text/javascript">\r
+ //<![CDATA[\r
+ var log = log4javascript.getLogger();\r
+ var popUpAppender = new log4javascript.PopUpAppender();\r
+ var popUpLayout = new log4javascript.PatternLayout("%d{HH:mm:ss} %-5p - %m%n");\r
+ popUpAppender.setLayout(popUpLayout);\r
+ log.addAppender(popUpAppender);\r
+ var ajaxAppender = new log4javascript.AjaxAppender("myloggingservlet.do");\r
+ ajaxAppender.setThreshold(log4javascript.Level.ERROR);\r
+ log.addAppender(ajaxAppender);\r
+ log.debug("Debugging message (appears in pop-up)");\r
+ log.error("Error message (appears in pop-up and in server log)");\r
+ //]]>\r
+</script>\r
+</pre>\r
+ <p>\r
+ <a href="../examples/example_manual.html" title="View example (opens in new window)"\r
+ target="_blank">See this example in action</a> (opens in new window)\r
+ </p>\r
+ </div>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="log4javascript">\r
+ <h2>log4javascript static properties/methods</h2>\r
+ <h4>Properties</h4>\r
+ <ul class="propertieslist">\r
+ <li class="property">\r
+ <div class="name">version</div>\r
+ <div class="summary">\r
+ The version number of your copy of log4javascript.\r
+ </div>\r
+ </li>\r
+ <li class="property">\r
+ <div class="name">edition</div>\r
+ <div class="summary">\r
+ The edition of your copy of log4javascript.\r
+ </div>\r
+ </li>\r
+ <li class="property">\r
+ <div class="name">logLog</div>\r
+ <div class="summary">\r
+ log4javascript's internal logging object. <a href="#loglog">See below for more details</a>.\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ <h4>Methods</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">getLogger</div>\r
+ <div class="methodsignature"><code>Logger <strong>getLogger</strong>([String <em>loggerName</em>])</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">loggerName</code>\r
+ [<em>optional</em>]\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ <p>\r
+ Returns a logger with the specified name, creating it if a logger with that name does not\r
+ already exist. If no name is specified, a logger is returned with name <code>[anonymous]</code>, and\r
+ subsequent calls to <code>getLogger()</code> (with no logger name specified) will return\r
+ this same logger object.\r
+ </p>\r
+ <p>\r
+ Note that the names <code>[anonymous]</code>, <code>[default]</code>, <code>[null]</code>\r
+ and <code>root</code> are reserved for\r
+ the anonymous logger, default logger, null logger and root logger respectively.\r
+ </p>\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getDefaultLogger</div>\r
+ <div class="methodsignature"><code>Logger <strong>getDefaultLogger</strong>()</code></div>\r
+ <div class="summary">\r
+ Convenience method that returns the default logger. The default logger\r
+ has a single appender: a <code><a href="#popupappender">PopUpAppender</a></code>\r
+ with the default layout, width and height, and with <code>focusPopUp</code> set to false\r
+ and <code>lazyInit</code>, <code>useOldPopUp</code> and\r
+ <code>complainAboutPopUpBlocking</code> all set to true.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getNullLogger</div>\r
+ <div class="methodsignature"><code>Logger <strong>getNullLogger</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns an empty logger with no appenders. Useful for disabling all logging.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getRootLogger</div>\r
+ <div class="methodsignature"><code>Logger <strong>getRootLogger</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns the root logger from which all other loggers derive.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">resetConfiguration</div>\r
+ <div class="methodsignature"><code>void <strong>resetConfiguration</strong>()</code></div>\r
+ <div class="summary">\r
+ Resets the all loggers to their default level.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setEnabled</div>\r
+ <div class="methodsignature"><code>void <strong>setEnabled</strong>(Boolean <em>enabled</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">enabled</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Enables or disables all logging, depending on <code>enabled</code>.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isEnabled</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isEnabled</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns true or false depending on whether logging is enabled.\r
+ </div>\r
+ </li>\r
+ <li class="method" id="log4javascriptaddeventlistener">\r
+ <div class="name">addEventListener</div>\r
+ <div class="methodsignature"><code>void <strong>addEventListener</strong>(String <em>eventType</em>, Function <em>listener</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">eventType</code>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">listener</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ <p>\r
+ Adds a function to be called when an event of the type specified occurs in log4javascript.\r
+ Supported event types are <code>load</code> (occurs once the page has loaded) and\r
+ <code>error</code>.\r
+ </p>\r
+ <p>\r
+ Each listener is pased three paramaters:\r
+ </p>\r
+ <ul>\r
+ <li><code>sender</code>. The object that raised the event (i.e. the log4javascript object);</li>\r
+ <li><code>eventType</code>. The type of the event;</li>\r
+ <li>\r
+ <code>eventArgs</code>. An object containing of event-specific arguments. For the <code>error</code> event,\r
+ this is an object with properties <code>message</code> and <code>exception</code>. For the <code>load</code>\r
+ event this is an empty object.\r
+ </li>\r
+ </ul>\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">removeEventListener</div>\r
+ <div class="methodsignature"><code>void <strong>removeEventListener</strong>(String <em>eventType</em>, Function <em>listener</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">eventType</code>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">listener</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Removes the event listener function supplied for the event of the type specified.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">dispatchEvent</div>\r
+ <div class="methodsignature"><code>void <strong>dispatchEvent</strong>(String <em>eventType</em>, Object <em>eventArgs</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">eventType</code>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">eventArgs</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Raises an event of type <code>eventType</code> on the <code>log4javascript</code> object.\r
+ Each of the listeners for this type of event (registered via <code>addEventListener</code>)\r
+ is called and passed <code>eventArgs</code> as the third parameter.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setEventTypes</div>\r
+ <div class="methodsignature"><code>void <strong>setEventTypes</strong>(Array <em>eventTypes</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">eventTypes</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Used internally to specify the types of events that the <code>log4javascript</code> object can raise.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setShowStackTraces</div>\r
+ <div class="methodsignature"><code>void <strong>setShowStackTraces</strong>(Boolean <em>show</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">show</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Enables or disables displaying of error stack traces, depending on <code>show</code>.\r
+ By default, stack traces are not displayed. (Only works in Firefox)\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">evalInScope</div>\r
+ <div class="methodsignature"><code>Object <strong>evalInScope</strong>(String <em>expr</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">expr</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ This evaluates the given expression in the log4javascript scope, thus allowing\r
+ scripts to access internal log4javascript variables and functions. This was written\r
+ for the purposes of automated testing but could be used by custom extensions to\r
+ log4javascript.\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="levels">\r
+ <h2>Levels</h2>\r
+ <p>\r
+ Levels are available as static properties of the <code>log4javascript.Level</code>\r
+ object. In ascending order of severity:\r
+ </p>\r
+ <ol>\r
+ <li><code>log4javascript.Level.ALL</code></li>\r
+ <li><code>log4javascript.Level.TRACE</code></li>\r
+ <li><code>log4javascript.Level.DEBUG</code></li>\r
+ <li><code>log4javascript.Level.INFO</code></li>\r
+ <li><code>log4javascript.Level.WARN</code></li>\r
+ <li><code>log4javascript.Level.ERROR</code></li>\r
+ <li><code>log4javascript.Level.FATAL</code></li>\r
+ <li><code>log4javascript.Level.OFF</code></li>\r
+ </ol>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="loggers">\r
+ <h2>Loggers</h2>\r
+ <p>\r
+ It is possible to have multiple loggers in log4javascript. For example, you\r
+ may wish to have a logger for debugging purposes that logs messages to a\r
+ pop-up window and a separate logger that reports any client-side application\r
+ errors to the server via Ajax.\r
+ </p>\r
+ <div id="loggerhierarchy">\r
+ <h3>Logger hierarchy and appender additivity</h3>\r
+ <p>\r
+ From version 1.4, log4javascript has hierarchical loggers, implemented in the same way\r
+ as log4j. In summary, you specify a logger's parent logger by means of a dot between the\r
+ parent logger name and the child logger name. Therefore the logger <code>tim.app.security</code>\r
+ inherits from <code>tim.app</code>, which in turn inherits from <code>tim</code> which,\r
+ finally, inherits from the root logger.\r
+ </p>\r
+ <p>\r
+ What inheritance means for a logger is that in the absence of a threshold level set\r
+ specifically on the logger it inherits its level from its parent; also, a logger inherits\r
+ all its parent's appenders (this is known as <em>appender additivity</em> in log4j. This\r
+ behaviour can be enabled or disabled via <code>setAdditivity()</code>. See below). In the\r
+ above example, if the root logger has a level of <code>DEBUG</code> and one appender,\r
+ each of the loggers <code>tim.app.security</code>, <code>tim.app</code> and <code>tim</code> would\r
+ inherit the root level's appender. If, say, <code>tim.app</code>'s threshold level was set\r
+ to <code>WARN</code>, <code>tim</code>'s effective level would remain at <code>DEBUG</code>\r
+ (inherited from the root logger) while <code>tim.app.security</code>'s effective level would\r
+ be <code>WARN</code>, inherited from <code>tim.app</code>. The important thing to note is\r
+ that appenders accumulate down the logger hierarchy while levels are simply inherited from\r
+ the nearest ancestor with a threshold level set.\r
+ </p>\r
+ <p>\r
+ For a detailed explanation of the logger hierarchy, see the\r
+ <a href="http://logging.apache.org/log4j/docs/manual.html" target="_blank"\r
+ title="Log4j manual (opens in new window)">log4j manual</a>.\r
+ </p>\r
+ </div>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ It is not possible to instantiate loggers directly. Instead you must use\r
+ one of the methods of the <code>log4javascript</code> object: <code>getLogger</code>,\r
+ <code>getRootLogger</code>, <code>getDefaultLogger</code> or <code>getNullLogger</code>.\r
+ </li>\r
+ </ul>\r
+ <h4>Logger methods</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">addAppender</div>\r
+ <div class="methodsignature"><code>void <strong>addAppender</strong>(Appender <em>appender</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">appender</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Adds the given appender.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">removeAppender</div>\r
+ <div class="methodsignature"><code>void <strong>removeAppender</strong>(Appender <em>appender</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">appender</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Removes the given appender.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">removeAllAppenders</div>\r
+ <div class="methodsignature"><code>void <strong>removeAllAppenders</strong>()</code></div>\r
+ <div class="summary">\r
+ Clears all appenders for the current logger.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setLevel</div>\r
+ <div class="methodsignature"><code>void <strong>setLevel</strong>(Level <em>level</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">level</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Sets the level. Log messages of a lower level than <code>level</code> will not be logged.\r
+ Default value is <code>DEBUG</code>.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getLevel</div>\r
+ <div class="methodsignature"><code>Level <strong>getLevel</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns the level explicitly set for this logger or <code>null</code> if none has been set.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getEffectiveLevel</div>\r
+ <div class="methodsignature"><code>Level <strong>getEffectiveLevel</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns the level at which the logger is operating. This is either the level explicitly\r
+ set on the logger or, if no level has been set, the effective level of the logger's parent.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setAdditivity</div>\r
+ <div class="methodsignature"><code>void <strong>setAdditivity</strong>(Boolean <em>additivity</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">additivity</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ <p>\r
+ Sets whether appender additivity is enabled (the default) or disabled. If set to false, this\r
+ particular logger will not inherit any appenders form its ancestors. Any descendant of this\r
+ logger, however, will inherit from its ancestors as normal, unless its own additivity is\r
+ explicitly set to false.\r
+ </p>\r
+ <p>\r
+ Default value is <code>true</code>.\r
+ </p>\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getAdditivity</div>\r
+ <div class="methodsignature"><code>Level <strong>getLevel</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether additivity is enabled for this logger.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">log</div>\r
+ <div class="methodsignature"><code>void <strong>log</strong>(Level <em>level</em>, Object <em>params</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">level</code>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">params</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Generic logging method used by wrapper methods such as <code>debug</code>,\r
+ <code>error</code> etc.\r
+ </div>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ The signature of this method has changed in 1.4.\r
+ </li>\r
+ </ul>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">trace</div>\r
+ <div class="methodsignature"><code>void <strong>trace</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">message1[, message2...]</code>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">exception</code>\r
+ [<em>optional</em>]\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Logs one or more messages and optionally an error at level <code>TRACE</code>.\r
+ </div>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ Logging of multiple messages in one call is new in 1.4.\r
+ </li>\r
+ </ul>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">debug</div>\r
+ <div class="methodsignature"><code>void <strong>debug</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">message1[, message2...]</code>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">exception</code>\r
+ [<em>optional</em>]\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Logs one or more messages and optionally an error at level <code>DEBUG</code>.\r
+ </div>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ Logging of multiple messages in one call is new in 1.4.\r
+ </li>\r
+ </ul>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">info</div>\r
+ <div class="methodsignature"><code>void <strong>info</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">message1[, message2...]</code>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">exception</code>\r
+ [<em>optional</em>]\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Logs one or more messages and optionally an error at level <code>INFO</code>.\r
+ </div>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ Logging of multiple messages in one call is new in 1.4.\r
+ </li>\r
+ </ul>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">warn</div>\r
+ <div class="methodsignature"><code>void <strong>warn</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">message1[, message2...]</code>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">exception</code>\r
+ [<em>optional</em>]\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Logs one or more messages and optionally an error at level <code>WARN</code>.\r
+ </div>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ Logging of multiple messages in one call is new in 1.4.\r
+ </li>\r
+ </ul>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">error</div>\r
+ <div class="methodsignature"><code>void <strong>error</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">message1[, message2...]</code>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">exception</code>\r
+ [<em>optional</em>]\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Logs one or more messages and optionally an error at level <code>ERROR</code>.\r
+ </div>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ Logging of multiple messages in one call is new in 1.4.\r
+ </li>\r
+ </ul>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">fatal</div>\r
+ <div class="methodsignature"><code>void <strong>fatal</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">message1[, message2...]</code>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">exception</code>\r
+ [<em>optional</em>]\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Logs one or more messages and optionally an error at level <code>FATAL</code>.\r
+ </div>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ Logging of multiple messages in one call is new in 1.4.\r
+ </li>\r
+ </ul>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isEnabledFor</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isEnabledFor</strong>(Level <em>level</em>, Error <em>exception</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">level</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Returns whether the logger is enabled for the specified level. \r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isTraceEnabled</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isTraceEnabled</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the logger is enabled for <code>TRACE</code> messages.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isDebugEnabled</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isDebugEnabled</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the logger is enabled for <code>DEBUG</code> messages.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isInfoEnabled</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isInfoEnabled</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the logger is enabled for <code>INFO</code> messages.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isWarnEnabled</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isWarnEnabled</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the logger is enabled for <code>WARN</code> messages.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isErrorEnabled</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isErrorEnabled</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the logger is enabled for <code>ERROR</code> messages.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isFatalEnabled</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isFatalEnabled</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the logger is enabled for <code>FATAL</code> messages.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">group</div>\r
+ <div class="methodsignature"><code>void <strong>group</strong>(String <em>name</em>, Boolean <em>initiallyExpanded</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">name</code>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">initiallyExpanded</code>\r
+ [<em>optional</em>]\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Starts a new group of log messages. In appenders that support grouping (currently\r
+ <code><a href="#popupappender">PopUpAppender</a></code> and\r
+ <code><a href="#inpageappender">InPageAppender</a></code>), a group appears as an expandable\r
+ section in the console, labelled with the <code>name</code> specified.\r
+ Specifying <code>initiallyExpanded</code> determines whether the\r
+ group starts off expanded (the default is <code>true</code>). Groups may be nested.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">groupEnd</div>\r
+ <div class="methodsignature"><code>void <strong>groupEnd</strong>()</code></div>\r
+ <div class="summary">\r
+ Ends the current group. If there is no group then this function has no effect.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">time</div>\r
+ <div class="methodsignature"><code>void <strong>time</strong>(String <em>name</em>, Level <em>level</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">name</code>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">level</code>\r
+ [<em>optional</em>]\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Starts a timer with name <code>name</code>. When the timer is ended with a\r
+ call to <code>timeEnd</code> using the same name, the amount of time that\r
+ has elapsed in milliseconds since the timer was started is logged at level\r
+ <code>level</code>. If not level is supplied, the level defaults to <code>INFO</code>.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">timeEnd</div>\r
+ <div class="methodsignature"><code>void <strong>timeEnd</strong>(String <em>name</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">name</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Ends the timer with name <code>name</code> and logs the time elapsed.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">assert</div>\r
+ <div class="methodsignature"><code>void <strong>assert</strong>(Object <em>expr</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">expr</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Asserts the given expression is <code>true</code> or evaluates to <code>true</code>.\r
+ If so, nothing is logged. If not, an error is logged at the <code>ERROR</code> level.\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="appenders">\r
+ <h2>Appenders</h2>\r
+ <div id="appender">\r
+ <h3>Appender</h3>\r
+ <p>\r
+ There are methods common to all appenders, as listed below.\r
+ </p>\r
+ <h4>Methods</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">doAppend</div>\r
+ <div class="methodsignature"><code>void <strong>doAppend</strong>(LoggingEvent <em>loggingEvent</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">loggingEvent</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ <p>\r
+ Checks the logging event's level is at least as severe as the appender's\r
+ threshold and calls the appender's <code>append</code> method if so.\r
+ </p>\r
+ <p>\r
+ This method should not in general be used directly or overridden.\r
+ </p>\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">append</div>\r
+ <div class="methodsignature"><code>void <strong>append</strong>(LoggingEvent <em>loggingEvent</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">loggingEvent</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Appender-specific method to append a log message. Every appender object should implement\r
+ this method.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setLayout</div>\r
+ <div class="methodsignature"><code>void <strong>setLayout</strong>(Layout <em>layout</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">layout</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Sets the appender's layout.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getLayout</div>\r
+ <div class="methodsignature"><code>Layout <strong>getLayout</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns the appender's layout.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setThreshold</div>\r
+ <div class="methodsignature"><code>void <strong>setThreshold</strong>(Level <em>level</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">level</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Sets the appender's threshold. Log messages of level less severe than this\r
+ threshold will not be logged.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getThreshold</div>\r
+ <div class="methodsignature"><code>Level <strong>getThreshold</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns the appender's threshold.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">toString</div>\r
+ <div class="methodsignature"><code>string <strong>toString</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns a string representation of the appender. Every appender object should implement\r
+ this method.\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="alertappender">\r
+ <h3>AlertAppender</h3>\r
+ <p class="editions">Editions: <strong>Standard</strong></p>\r
+ <p>\r
+ Displays a log message as a JavaScript alert.\r
+ </p>\r
+ <h4>Constructor</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">AlertAppender</div>\r
+ <div class="methodsignature"><code><strong>AlertAppender</strong>()</code></div>\r
+ </li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="ajaxappender">\r
+ <h3>AjaxAppender</h3>\r
+ <p class="editions">Editions: <strong>Standard, Production</strong></p>\r
+ <p>\r
+ A flexible appender that asynchronously sends log messages to a server via HTTP\r
+ (Ajax, if you insist, though the 'x' of Ajax only comes into play in any form if you use an\r
+ <code><a href="#xmllayout">XmlLayout</a></code>).\r
+ </p>\r
+ <p>\r
+ The default configuration is to send each log message as a separate HTTP post\r
+ request to the server using an <code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>,\r
+ without waiting for a response before sending any subsequent requests. However,\r
+ an <code>AjaxAppender</code> may be configured to do any one of or combinations of the following:\r
+ </p>\r
+ <ul>\r
+ <li>\r
+ send log messages in batches (if the selected layout supports it - particularly suited\r
+ to <code>AjaxAppender</code> are <code><a href="#jsonlayout">JsonLayout</a></code> and\r
+ <code><a href="#xmllayout">XmlLayout</a></code>, both of which allow batching);\r
+ </li>\r
+ <li>\r
+ wait for a response from a previous request before sending the next log message / batch\r
+ of messages;\r
+ </li>\r
+ <li>\r
+ send all queued log messages at timed intervals.\r
+ </li>\r
+ </ul>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ AjaxAppender relies on the <code>XMLHttpRequest</code> object. It also requires\r
+ the presence of correctly implemented <code>setRequestHeader</code> method on\r
+ this object, which rules out Opera prior to version 8.01. If your browser does not\r
+ support the necessary objects then one alert will display to explain why it\r
+ doesn't work, after which the appender will silently switch off.\r
+ </li>\r
+ <li>\r
+ In AjaxAppender only, <code>setLayout</code> may not be called after the first\r
+ message has been logged.\r
+ </li>\r
+ <li>\r
+ The default layout is <code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>.\r
+ </li>\r
+ <li>\r
+ From version 1.4, log message data is always sent as one or more name/value pairs.\r
+ In the case of <code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>, data\r
+ is sent the same as in previous versions. For other layouts such as\r
+ <code><a href="#jsonlayout">JsonLayout</a></code> and\r
+ <code><a href="#xmllayout">XmlLayout</a></code>, the formatted log message is posted as\r
+ the value of a parameter called <code>data</code>, though this may be changed via\r
+ <code>setPostVarName</code>.\r
+ </li>\r
+ <li>\r
+ From version 1.4, log message timestamps are sent as standard JavaScript times, i.e.\r
+ the number of milliseconds since 00:00:00 UTC on January 1, 1970.\r
+ </li>\r
+ <li>\r
+ <p>\r
+ Also from version 1.4, any outstanding log messages may optionally be sent when the\r
+ main page unloads (i.e. user follows a link, closes the window or refreshes the\r
+ page). This behaviour may be enabled using <code>setSendAllOnUnload</code>; see\r
+ below.\r
+ </p>\r
+ <p>\r
+ This behaviour is dependent on <code>window.onbeforeunload</code>; unfortunately,\r
+ Opera does not always raise this event, so this feature does not work reliably in\r
+ Opera.\r
+ </p>\r
+ </li>\r
+ </ul>\r
+ <h4>Constructor</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">AjaxAppender</div>\r
+ <div class="methodsignature">\r
+ <code><strong>AjaxAppender</strong>(String <em>url</em>)</code>\r
+ </div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">url</code>\r
+ <div>\r
+ The URL to which log messages should be sent. Note that this is subject\r
+ to the usual Ajax restrictions: the URL should be in the same domain as that\r
+ of the page making the request.\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ </li>\r
+ </ul>\r
+ <h4>Methods</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">setSendAllOnUnload</div>\r
+ <div class="methodsignature"><code>void <strong>setSendAllOnUnload</strong>(Boolean <em>sendAllOnUnload</em>)</code></div>\r
+ <div class="summary">\r
+ <p>\r
+ [<em>not available after first message logged</em>]\r
+ </p>\r
+ <p>\r
+ Whether to send all remaining unsent log messages to the server when the page\r
+ unloads.\r
+ </p>\r
+ <p>\r
+ Since version 1.4.3, the default value is <code>false</code>. Previously the\r
+ default was <code>true</code>.\r
+ </p>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ This feature was found not to work prior to version 1.4.3 in WebKit\r
+ browsers (e.g. Google Chrome, Safari). As a result, a workaround was\r
+ implemented in 1.4.3 which has the unfortunate side effect of popping up a\r
+ confirmation dialog to the user if there are any log messages to send when\r
+ the page unloads. As a result, this feature is now obtrusive for the user\r
+ and is therefore disabled by default.\r
+ </li>\r
+ <li>\r
+ This feature does not work in any version of Opera.\r
+ </li>\r
+ </ul>\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isSendAllOnUnload</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isSendAllOnUnload</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether all remaining unsent log messages are sent to the server when the page unloads.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setPostVarName</div>\r
+ <div class="methodsignature"><code>void <strong>setPostVarName</strong>(String <em>postVarName</em>)</code></div>\r
+ <div class="summary">\r
+ <p>\r
+ [<em>not available after first message logged</em>]\r
+ </p>\r
+ <p>\r
+ Sets the post variable name whose value will the formatted log message(s) for\r
+ each request.\r
+ </p>\r
+ <p>\r
+ Default value is <code>data</code>.\r
+ </p>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ This has no effect if the current layout is an\r
+ <code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>.\r
+ </li>\r
+ </ul>\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getPostVarName</div>\r
+ <div class="methodsignature"><code>String <strong>getPostVarName</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns the post variable name whose value will the formatted log message(s) for\r
+ each request.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setTimed</div>\r
+ <div class="methodsignature"><code>void <strong>setTimed</strong>(Boolean <em>timed</em>)</code></div>\r
+ <div class="summary">\r
+ <p>\r
+ [<em>not available after first message logged</em>]\r
+ </p>\r
+ <p>\r
+ Whether to send log messages to the server at regular, timed intervals.\r
+ </p>\r
+ <p>\r
+ Default value is <code>false</code>.\r
+ </p>\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isTimed</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isTimed</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether log messages are sent to the server at regular, timed intervals.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setWaitForResponse</div>\r
+ <div class="methodsignature"><code>void <strong>setWaitForResponse</strong>(Boolean <em>waitForResponse</em>)</code></div>\r
+ <div class="summary">\r
+ <p>\r
+ [<em>not available after first message logged</em>]\r
+ </p>\r
+ <p>\r
+ Sets whether to wait for a response from a previous HTTP request from this\r
+ appender before sending the next log message / batch of messages.\r
+ </p>\r
+ <p>\r
+ Default value is <code>false</code>.\r
+ </p>\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isWaitForResponse</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isWaitForResponse</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the appender waits for a response from a previous HTTP request from this\r
+ appender before sending the next log message / batch of messages.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setBatchSize</div>\r
+ <div class="methodsignature"><code>void <strong>setBatchSize</strong>(Number <em>batchSize</em>)</code></div>\r
+ <div class="summary">\r
+ <p>\r
+ [<em>not available after first message logged</em>]\r
+ </p>\r
+ <p>\r
+ Sets the number of log messages to send in each request. If not specified,\r
+ defaults to <code>1</code>.\r
+ </p>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ Setting this to a number greater than 1 means that the appender will wait\r
+ until it has forwarded that many valid log messages before sending any more.\r
+ This also means that if the page unloads for any reason and <code>sendAllOnUnload</code>\r
+ is not set to <code>true</code>, any log messages waiting in the queue will not be sent.\r
+ </li>\r
+ <li>\r
+ If batching is used in conjunction with timed sending of log messages,\r
+ messages will still be sent in batches of size <code>batchSize</code>,\r
+ regardless of how many log messages are queued by the time the timed\r
+ sending is invoked. Incomplete batches will not be sent except when the\r
+ page unloads, if <code>sendAllOnUnload</code> is set to <code>true</code>.\r
+ </li>\r
+ </ul>\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getBatchSize</div>\r
+ <div class="methodsignature"><code>Number <strong>getBatchSize</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns the number of log messages sent in each request. See above for more details.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setTimerInterval</div>\r
+ <div class="methodsignature"><code>void <strong>setTimerInterval</strong>(Number <em>timerInterval</em>)</code></div>\r
+ <div class="summary">\r
+ <p>\r
+ [<em>not available after first message logged</em>]\r
+ </p>\r
+ <p>\r
+ Sets the length of time in milliseconds between each sending of queued log\r
+ messages.\r
+ </p>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ <code>timerInterval</code> only has an effect in conjunction with\r
+ <code>timed</code> (set by <code>setTimed()</code>. If <code>timed</code>\r
+ is set to false then <code>timerInterval</code> has no effect.\r
+ </li>\r
+ <li>\r
+ Each time the queue of log messages or batches of messages is cleared,\r
+ the countdown to the next sending only starts once the final request\r
+ has been sent (and, if <code>waitForResponse</code> is set to <code>true</code>,\r
+ the final response received). This means that the actual interval at\r
+ which the queue of messages is cleared cannot be fixed.\r
+ </li>\r
+ </ul>\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getTimerInterval</div>\r
+ <div class="methodsignature"><code>Number <strong>getTimerInterval</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns the length of time in milliseconds between each sending of queued log\r
+ messages. See above for more details.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setRequestSuccessCallback</div>\r
+ <div class="methodsignature"><code>void <strong>setRequestSuccessCallback</strong>(Function <em>requestSuccessCallback</em>)</code></div>\r
+ <div class="summary">\r
+ <p>\r
+ Sets the function that is called whenever a successful request is made, called at the\r
+ point at which the response is received. This feature can be used to confirm\r
+ whether a request has been successful and act accordingly.\r
+ </p>\r
+ <p>\r
+ A single parameter, <code>xmlHttp</code>, is passed to the callback function.\r
+ This is the XMLHttpRequest object that performed the request.\r
+ </p>\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setFailCallback</div>\r
+ <div class="methodsignature"><code>void <strong>setFailCallback</strong>(Function <em>failCallback</em>)</code></div>\r
+ <div class="summary">\r
+ <p>\r
+ Sets the function that is called whenever any kind of failure occurs in the appender,\r
+ including browser deficiencies or configuration errors (e.g. supplying a\r
+ non-existent URL to the appender). This feature can be used to handle\r
+ AjaxAppender-specific errors.\r
+ </p>\r
+ <p>\r
+ A single parameter, <code>message</code>, is passed to the callback function.\r
+ This is the error-specific message that caused the failure.\r
+ </p>\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setSessionId</div>\r
+ <div class="methodsignature"><code>void <strong>setSessionId</strong>(String <em>sessionId</em>)</code></div>\r
+ <div class="summary">\r
+ Sets the session id sent to the server each time a request is made.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getSessionId</div>\r
+ <div class="methodsignature"><code>String <strong>getSessionId</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns the session id sent to the server each time a request is made.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">addHeader</div>\r
+ <div class="methodsignature"><code>void <strong>addHeader</strong>(String <em>name</em>,\r
+ String <em>value</em>)</code></div>\r
+ <div class="summary">\r
+ <p>\r
+ Adds an HTTP header that is sent with each request.\r
+ </p>\r
+ <p>\r
+ <strong>Since: 1.4.3</strong>\r
+ </p>\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getHeaders</div>\r
+ <div class="methodsignature"><code>Array <strong>getHeaders</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns an array of the additional headers that are sent with each HTTP request.\r
+ Each array item is an object with properties <code>name</code> and\r
+ <code>value</code>.\r
+ <p>\r
+ <strong>Since: 1.4.3</strong>\r
+ </p>\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">sendAll</div>\r
+ <div class="methodsignature"><code>void <strong>sendAll</strong>()</code></div>\r
+ <div class="summary">\r
+ Sends all log messages in the queue. If log messages are batched then only completed\r
+ batches are sent.\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="popupappender">\r
+ <h3>PopUpAppender</h3>\r
+ <p class="editions">Editions: <strong>Standard</strong></p>\r
+ <p>\r
+ Logs messages to a pop-up console window (note: you will need to disable pop-up\r
+ blockers to use it). The pop-up displays a list of all log messages, and has\r
+ the following features:\r
+ </p>\r
+ <ul>\r
+ <li>log messages are colour-coded by severity;</li>\r
+ <li>log messages are displayed in a monospace font to allow easy readability;</li>\r
+ <li>switchable wrap mode to allow wrapping of long lines</li>\r
+ <li>all whitespace in log messages is honoured (except in wrap mode);</li>\r
+ <li>filters to show and hide messages of a particular level;</li>\r
+ <li>\r
+ search facility that allows searching of log messages as you type, with the\r
+ following features:\r
+ <ul>\r
+ <li>supports regular expressions;</li>\r
+ <li>case sensitive or insensitive matching;</li>\r
+ <li>buttons to navigate through all the matches;</li>\r
+ <li>switch to highlight all matches;</li>\r
+ <li>switch to filter out all log messages that contain no matches;</li>\r
+ <li>switch to enable or disable the search;</li>\r
+ <li>search is dynamically applied to every log message as it is added to the console.</li>\r
+ </ul>\r
+ </li>\r
+ <li>switch to toggle between logging from the top down and from the bottom up;</li>\r
+ <li>switch to turn automatic scrolling when a new message is logged on and off;</li>\r
+ <li>switch to turn off all logging to the pop-up (useful if a timer is generating unwanted log messages);</li>\r
+ <li>optional configurable limit to the number of log message that are displayed. If\r
+ set and this limit is reached, each new log message will cause the oldest one to\r
+ be discarded;</li>\r
+ <li>grouped log messages. Groups may be nested and each has a button to show or hide the log messages in that group;</li>\r
+ <li>clear button to allow user to delete all current log messages.</li>\r
+ <li>\r
+ command prompt with up/down arrow history. Command line functions may be added\r
+ to the appender. Several command line functions are built in:\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="methodsignature"><code><strong>$</strong>(String <em>id</em>)</code></div>\r
+ <div class="summary">\r
+ Prints a string representation of a single element with the id supplied.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="methodsignature"><code><strong>dir</strong>(Object <em>obj</em>)</code></div>\r
+ <div class="summary">\r
+ Prints a list of a properties of the object supplied.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="methodsignature"><code><strong>dirxml</strong>(HTMLElement <em>el</em>)</code></div>\r
+ <div class="summary">\r
+ Prints the XML source code of an HTML or XML element\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="methodsignature"><code><strong>cd</strong>(Object <em>win</em>)</code></div>\r
+ <div class="summary">\r
+ Changes the scope of execution of commands to the named frame or window (either a\r
+ window/frame name or a reference to a window object may be supplied).\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="methodsignature"><code><strong>clear</strong>()</code></div>\r
+ <div class="summary">\r
+ Clears the console.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="methodsignature"><code><strong>keys</strong>(Object <em>obj</em>)</code></div>\r
+ <div class="summary">\r
+ Prints a list of the names of all properties of the object supplied.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="methodsignature"><code><strong>values</strong>(Object <em>obj</em>)</code></div>\r
+ <div class="summary">\r
+ Prints a list of the values of all properties of the object supplied.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="methodsignature"><code><strong>expansionDepth</strong>(Number <em>depth</em>)</code></div>\r
+ <div class="summary">\r
+ Sets the number of levels of expansion of objects that are displayed by\r
+ the command line. The default value is 1.\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ </li>\r
+ </ul>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ <p>\r
+ The default layout for this appender is <code><a href="#patternlayout">PatternLayout</a></code>\r
+ with pattern string\r
+ </p>\r
+ <p>\r
+ <code>%d{HH:mm:ss} %-5p - %m{1}%n</code>\r
+ </p>\r
+ </li>\r
+ </ul>\r
+ <h4>Constructor</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">PopUpAppender</div>\r
+ <div class="methodsignature">\r
+ <code><strong>PopUpAppender</strong>([Boolean <em>lazyInit</em>,\r
+ Boolean <em>initiallyMinimized</em>, Boolean <em>useDocumentWrite</em>,\r
+ Number <em>width</em>, Number <em>height</em>])</code>\r
+ </div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">lazyInit</code>\r
+ [<em>optional</em>]\r
+ <div>\r
+ Set this to <code>true</code> to open the pop-up only when the first log\r
+ message reaches the appender. Otherwise, the pop-up window opens as soon as the\r
+ appender is created. If not specified, defaults to <code>false</code>.\r
+ </div>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">initiallyMinimized</code>\r
+ [<em>optional</em>]\r
+ <div>\r
+ <p>\r
+ Whether the console window should start off hidden / minimized.\r
+ If not specified, defaults to <code>false</code>.\r
+ </p>\r
+ </div>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">useDocumentWrite</code>\r
+ [<em>optional</em>]\r
+ <div>\r
+ <p>\r
+ Specifies how the console window is created. By default, the console window is\r
+ created dynamically using <code>document</code>'s <code>write</code> method. This has the\r
+ advantage of keeping all the code in one single JavaScript file. However, if your\r
+ page sets <code>document.domain</code> then the browser prevents script access to\r
+ a window unless it too has the same value set for <code>document.domain</code>. To\r
+ get round this issue, you can set <code>useDocumentWrite</code> to <code>false</code>\r
+ and log4javascript will instead use the external HTML file <code>console.html</code>\r
+ (or <code>console_uncompressed.html</code> if you're using an uncompressed version of\r
+ log4javascript.js), which must be placed in the same directory as your log4javascript.js file.\r
+ </p>\r
+ <p>\r
+ Note that if <code>useDocumentWrite</code> is set to <code>true</code>, the old pop-up\r
+ window will always be closed and a new one created whenever the page is refreshed, even\r
+ if <code>setUseOldPopUp(true)</code> has been called.\r
+ </p>\r
+ <p>\r
+ In general it's simpler to use the <code>document.write</code> method, so unless your\r
+ page needs to set <code>document.domain</code>, <code>useDocumentWrite</code> should\r
+ be set to <code>true</code>.\r
+ </p>\r
+ <p>\r
+ If not specified, defaults to <code>true</code>.\r
+ </p>\r
+ </div>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">width</code>\r
+ [<em>optional</em>]\r
+ <div>\r
+ The outer width in pixels of the pop-up window. If not specified,\r
+ defaults to <code>600</code>.\r
+ </div>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">height</code>\r
+ [<em>optional</em>]\r
+ <div>\r
+ The outer height in pixels of the pop-up window. If not specified,\r
+ defaults to <code>400</code>.\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ </li>\r
+ </ul>\r
+ <h4>Methods</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">isInitiallyMinimized</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isInitiallyMinimized</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the console window starts off hidden / minimized.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setInitiallyMinimized</div>\r
+ <div class="methodsignature"><code>void <strong>setInitiallyMinimized</strong>(Boolean <em>initiallyMinimized</em>)</code></div>\r
+ <div class="summary">\r
+ [<em>not available after initialization</em>]\r
+ <br />\r
+ Sets whether the console window should start off hidden / minimized.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isFocusPopUp</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isFocusPopUp</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the pop-up window is focussed (i.e. brought it to the front)\r
+ when a new log message is added. Default value is <code>false</code>.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setFocusPopUp</div>\r
+ <div class="methodsignature"><code>void <strong>setFocusPopUp</strong>(Boolean <em>focusPopUp</em>)</code></div>\r
+ <div class="summary">\r
+ Sets whether to focus the pop-up window (i.e. bring it to the front)\r
+ when a new log message is added.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isUseOldPopUp</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isUseOldPopUp</strong>()</code></div>\r
+ <div class="summary">\r
+ <p>\r
+ Returns whether the same pop-up window is used if the main page is\r
+ reloaded. If set to <code>true</code>, when the page is reloaded\r
+ a line is drawn in the pop-up and subsequent log messages are added\r
+ to the same pop-up. Otherwise, a new pop-up window is created that\r
+ replaces the original pop-up. If not specified, defaults to\r
+ <code>true</code>.\r
+ </p>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ In Internet Explorer 5, the browser prevents this from working\r
+ properly, so a new pop-up window is always created when the main\r
+ page reloads. Also, the original pop-up does not get closed.\r
+ </li>\r
+ </ul>\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setUseOldPopUp</div>\r
+ <div class="methodsignature"><code>void <strong>setUseOldPopUp</strong>(Boolean <em>useOldPopUp</em>)</code></div>\r
+ <div class="summary">\r
+ [<em>not available after initialization</em>]\r
+ <br />\r
+ Sets whether to use the same pop-up window if the main page is reloaded.\r
+ See <code>isUseOldPopUp</code> above for details.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isComplainAboutPopUpBlocking</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isComplainAboutPopUpBlocking</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether an alert is shown to the user when the pop-up window\r
+ cannot be created as a result of a pop-up blocker. Default value is <code>true</code>.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setComplainAboutPopUpBlocking</div>\r
+ <div class="methodsignature"><code>void <strong>setComplainAboutPopUpBlocking</strong>(Boolean <em>complainAboutPopUpBlocking</em>)</code></div>\r
+ <div class="summary">\r
+ [<em>not available after initialization</em>]\r
+ <br />\r
+ Sets whether to announce to show an alert to the user when the pop-up window\r
+ cannot be created as a result of a pop-up blocker.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isNewestMessageAtTop</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isNewestMessageAtTop</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether new log messages are displayed at the top of the pop-up window.\r
+ Default value is <code>false</code> (i.e. log messages are appended to the bottom of the window).\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setNewestMessageAtTop</div>\r
+ <div class="methodsignature"><code>void <strong>setNewestMessageAtTop</strong>(Boolean <em>newestMessageAtTop</em>)</code></div>\r
+ <div class="summary">\r
+ Sets whether to display new log messages at the top inside the pop-up window.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isScrollToLatestMessage</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isScrollToLatestMessage</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the pop-up window scrolls to display the latest log message when a new message\r
+ is logged. Default value is <code>true</code>.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setScrollToLatestMessage</div>\r
+ <div class="methodsignature"><code>void <strong>setScrollToLatestMessage</strong>(Boolean <em>scrollToLatestMessage</em>)</code></div>\r
+ <div class="summary">\r
+ Sets whether to scroll the pop-up window to display the latest log message when a new message\r
+ is logged.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isReopenWhenClosed</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isReopenWhenClosed</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the pop-up window reopens automatically after being closed when a new log message is logged.\r
+ Default value is <code>false</code>.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setReopenWhenClosed</div>\r
+ <div class="methodsignature"><code>void <strong>setReopenWhenClosed</strong>(Boolean <em>reopenWhenClosed</em>)</code></div>\r
+ <div class="summary">\r
+ Sets whether to reopen the pop-up window automatically after being closed when a new log message is logged.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getWidth</div>\r
+ <div class="methodsignature"><code>Number <strong>getWidth</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns the outer width in pixels of the pop-up window.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setWidth</div>\r
+ <div class="methodsignature"><code>void <strong>setWidth</strong>(Number <em>width</em>)</code></div>\r
+ <div class="summary">\r
+ [<em>not available after initialization</em>]\r
+ <br />\r
+ Sets the outer width in pixels of the pop-up window.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getHeight</div>\r
+ <div class="methodsignature"><code>Number <strong>getHeight</strong>()</code></div>\r
+ <div class="summary">\r
+ [<em>not available after initialization</em>]\r
+ <br />\r
+ Returns the outer height in pixels of the pop-up window.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setHeight</div>\r
+ <div class="methodsignature"><code>void <strong>setHeight</strong>(Number <em>height</em>)</code></div>\r
+ <div class="summary">\r
+ Sets the outer height in pixels of the pop-up window.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getMaxMessages</div>\r
+ <div class="methodsignature"><code>Number <strong>getMaxMessages</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns the largest number of log messages that are displayed and stored\r
+ by the the console. Once reached, a new log message wil cause the\r
+ oldest message to be discarded. Default value is <code>null</code>, which means no\r
+ limit is applied.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setMaxMessages</div>\r
+ <div class="methodsignature"><code>void <strong>setMaxMessages</strong>(Number <em>maxMessages</em>)</code></div>\r
+ <div class="summary">\r
+ [<em>not available after initialization</em>]\r
+ <br />\r
+ Sets the largest number of messages displayed and stored by the console window. Set\r
+ this to <code>null</code> to make this number unlimited.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isShowCommandLine</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isShowCommandLine</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the console includes a command line.\r
+ Default value is <code>true</code>.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setShowCommandLine</div>\r
+ <div class="methodsignature"><code>void <strong>setShowCommandLine</strong>(Boolean <em>showCommandLine</em>)</code></div>\r
+ <div class="summary">\r
+ Sets whether the console includes a command line.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getCommandLineObjectExpansionDepth</div>\r
+ <div class="methodsignature"><code>Number <strong>getCommandLineObjectExpansionDepth</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns the number of levels to expand when an object value is logged to the console.\r
+ Each property of an object above this threshold will be expanded if it is itself an object\r
+ or array, otherwise its string representation will be displayed. Default value is 1 (i.e.\r
+ the properties of the object logged will be displayed in their string representation but\r
+ not expanded).\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setCommandLineObjectExpansionDepth:</div>\r
+ <div class="methodsignature"><code>void <strong>setCommandLineObjectExpansionDepth</strong>(Number <em>expansionDepth</em>)</code></div>\r
+ <div class="summary">\r
+ Sets the number of levels to expand when an object value is logged to the console.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getCommandWindow</div>\r
+ <div class="methodsignature"><code>Window <strong>getCommandWindow</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns a reference to the window in which commands typed into the command line\r
+ are currently being executed.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setCommandWindow</div>\r
+ <div class="methodsignature"><code>void <strong>setCommandWindow</strong>(Window <em>commandWindow</em>)</code></div>\r
+ <div class="summary">\r
+ Sets the window in which commands typed into the command line are executed.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getCommandLayout</div>\r
+ <div class="methodsignature"><code>Number <strong>getCommandLayout</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns the layout used to format the output for commands typed into the command line.\r
+ The default value is a <code><a href="#patternlayout">PatternLayout</a></code> with\r
+ pattern string <code>%m</code>\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setCommandLayout</div>\r
+ <div class="methodsignature"><code>void <strong>setCommandLayout</strong>(Layout <em>commandLayout</em>)</code></div>\r
+ <div class="summary">\r
+ Sets the layout used to format the output for commands typed into the command line.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">clear</div>\r
+ <div class="methodsignature"><code>void <strong>clear</strong>()</code></div>\r
+ <div class="summary">\r
+ Clears all messages from the console window.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">close</div>\r
+ <div class="methodsignature"><code>void <strong>close</strong>()</code></div>\r
+ <div class="summary">\r
+ Closes the pop-up window.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">show</div>\r
+ <div class="methodsignature"><code>void <strong>show</strong>()</code></div>\r
+ <div class="summary">\r
+ Opens the pop-up window, if not already open.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">hide</div>\r
+ <div class="methodsignature"><code>void <strong>hide</strong>()</code></div>\r
+ <div class="summary">\r
+ Closes the pop-up window.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">focus</div>\r
+ <div class="methodsignature"><code>void <strong>focus</strong>()</code></div>\r
+ <div class="summary">\r
+ Brings the console window to the top and gives it the focus.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">focusCommandLine</div>\r
+ <div class="methodsignature"><code>void <strong>focusCommandLine</strong>()</code></div>\r
+ <div class="summary">\r
+ Brings the console window to the top and gives the focus to the command line.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">focusSearch</div>\r
+ <div class="methodsignature"><code>void <strong>focusSearch</strong>()</code></div>\r
+ <div class="summary">\r
+ Brings the console window to the top and gives the focus to the search box.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">evalCommandAndAppend</div>\r
+ <div class="methodsignature"><code>void <strong>evalCommandAndAppend</strong>(String <em>expr</em>)</code></div>\r
+ <div class="summary">\r
+ Evaluates the expression and appends the result to the console.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">addCommandLineFunction</div>\r
+ <div class="methodsignature"><code>void <strong>addCommandLineFunction</strong>(String <em>functionName</em>, Function <em>commandLineFunction</em>)</code></div>\r
+ <div class="summary">\r
+ <p>\r
+ Adds a function with the name specified to the list of functions available on the command line.\r
+ This feature may be used to add custom functions to the command line.\r
+ </p>\r
+ <p>\r
+ When you call the function on the command line, <code>commandLineFunction</code> is executed with the\r
+ following three parameters:\r
+ </p>\r
+ <ul>\r
+ <li><em>appender</em>. A reference to the appender in which the command was executed;</li>\r
+ <li><em>args</em>.\r
+ An array-like list of parameters passed into the function on the command line\r
+ (actually a reference to the <code>arguments</code> object representing the parameters passed\r
+ into the function by the user);</li>\r
+ <li><em>returnValue</em>. This is an object with two properties that allow the function to control\r
+ how the result is displayed:\r
+ <ul>\r
+ <li><em>appendResult</em>. A boolean value that determines whether the returned value from this\r
+ function is appended to the console. The default value is <code>true</code>;</li>\r
+ <li><em>isError</em>. A boolean value that specifies whether the output of this function\r
+ should be displayed as an error. The default value is <code>false</code>.</li>\r
+ </ul>\r
+ </li>\r
+ </ul>\r
+ <p>\r
+ The value returned by the function is formatted by the command layout and appended to the console.\r
+ </p>\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="inpageappender">\r
+ <h3>InPageAppender</h3>\r
+ <p class="editions">Editions: <strong>Standard</strong></p>\r
+ <p>\r
+ Logs messages to a console window in the page. The console is identical\r
+ to that used by the <code><a href="#popupappender">PopUpAppender</a></code>, except\r
+ for the absence of a 'Close' button.\r
+ </p>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ Prior to log4javascript 1.3, InPageAppender was known as InlineAppender.\r
+ For the sake of backwards compatibility, InlineAppender is still included in\r
+ 1.3 and later as an alias for InPageAppender.\r
+ </li>\r
+ <li>\r
+ <p>\r
+ The default layout for this appender is <code><a href="#patternlayout">PatternLayout</a></code>\r
+ with pattern string\r
+ </p>\r
+ <p>\r
+ <code>%d{HH:mm:ss} %-5p - %m{1}%n</code>\r
+ </p>\r
+ </li>\r
+ </ul>\r
+ <h4>Constructor</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">InPageAppender</div>\r
+ <div class="methodsignature">\r
+ <code><strong>InPageAppender</strong>(HTMLElement <em>container</em>[,\r
+ Boolean <em>lazyInit</em>, Boolean <em>initiallyMinimized</em>,\r
+ Boolean <em>useDocumentWrite</em>, String <em>width</em>, String <em>height</em>])</code>\r
+ </div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">container</code>\r
+ <div>\r
+ The container element for the console window. This should be an HTML element.\r
+ </div>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">lazyInit</code>\r
+ [<em>optional</em>]\r
+ <div>\r
+ Set this to <code>true</code> to create the console only when the first log\r
+ message reaches the appender. Otherwise, the console is initialized as soon as the\r
+ appender is created. If not specified, defaults to <code>true</code>.\r
+ </div>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">initiallyMinimized</code>\r
+ [<em>optional</em>]\r
+ <div>\r
+ <p>\r
+ Whether the console window should start off hidden / minimized.\r
+ If not specified, defaults to <code>false</code>.\r
+ </p>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ In Safari (and possibly other browsers) hiding an <code>iframe</code>\r
+ resets its document, thus destroying the console window.\r
+ </li>\r
+ </ul>\r
+ </div>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">useDocumentWrite</code>\r
+ [<em>optional</em>]\r
+ <div>\r
+ <p>\r
+ Specifies how the console window is created. By default, the console window is\r
+ created dynamically using <code>document</code>'s <code>write</code> method. This has the\r
+ advantage of keeping all the code in one single JavaScript file. However, if your\r
+ page sets <code>document.domain</code> then the browser prevents script access to\r
+ a window unless it too has the same value set for <code>document.domain</code>. To\r
+ get round this issue, you can set <code>useDocumentWrite</code> to <code>false</code>\r
+ and log4javascript will instead use the external HTML file <code>console.html</code>\r
+ (or <code>console_uncompressed.html</code> if you're using an uncompressed version of\r
+ log4javascript.js), which must be placed in the same directory as your log4javascript.js file.\r
+ </p>\r
+ <p>\r
+ In general it's simpler to use the <code>document.write</code> method, so unless your\r
+ page needs to set <code>document.domain</code>, <code>useDocumentWrite</code> should\r
+ be set to <code>true</code>.\r
+ </p>\r
+ <p>\r
+ If not specified, defaults to <code>true</code>.\r
+ </p>\r
+ </div>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">width</code>\r
+ [<em>optional</em>]\r
+ <div>\r
+ The width of the console window. Any valid CSS length may be used. If not\r
+ specified, defaults to <code>100%</code>.\r
+ </div>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">height</code>\r
+ [<em>optional</em>]\r
+ <div>\r
+ The height of the console window. Any valid CSS length may be used. If not\r
+ specified, defaults to <code>250px</code>.\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ </li>\r
+ </ul>\r
+ <h4>Methods</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">addCssProperty</div>\r
+ <div class="methodsignature"><code>void <strong>addCssProperty</strong>(String <em>name</em>, String <em>value</em>)</code></div>\r
+ <div class="summary">\r
+ Sets a CSS style property on the HTML element containing the console iframe.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isVisible</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isVisible</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the console window is currently visible.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isInitiallyMinimized</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isInitiallyMinimized</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the console window starts off hidden / minimized.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setInitiallyMinimized</div>\r
+ <div class="methodsignature"><code>void <strong>setInitiallyMinimized</strong>(Boolean <em>initiallyMinimized</em>)</code></div>\r
+ <div class="summary">\r
+ [<em>not available after initialization</em>]\r
+ <br />\r
+ Sets whether the console window should start off hidden / minimized.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isNewestMessageAtTop</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isNewestMessageAtTop</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether new log messages are displayed at the top of the console window.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setNewestMessageAtTop</div>\r
+ <div class="methodsignature"><code>void <strong>setNewestMessageAtTop</strong>(Boolean <em>newestMessageAtTop</em>)</code></div>\r
+ <div class="summary">\r
+ Sets whether to display new log messages at the top inside the console window.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isScrollToLatestMessage</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isScrollToLatestMessage</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the pop-up window scrolls to display the latest log message when a new message\r
+ is logged.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setScrollToLatestMessage</div>\r
+ <div class="methodsignature"><code>void <strong>setScrollToLatestMessage</strong>(Boolean <em>scrollToLatestMessage</em>)</code></div>\r
+ <div class="summary">\r
+ Sets whether to scroll the console window to display the latest log message when a new message\r
+ is logged.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getWidth</div>\r
+ <div class="methodsignature"><code>String <strong>getWidth</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns the outer width of the console window.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setWidth</div>\r
+ <div class="methodsignature"><code>void <strong>setWidth</strong>(String <em>width</em>)</code></div>\r
+ <div class="summary">\r
+ [<em>not available after initialization</em>]\r
+ <br />\r
+ Sets the outer width of the console window. Any valid CSS length may be used.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getHeight</div>\r
+ <div class="methodsignature"><code>String <strong>getHeight</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns the outer height of the console window.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setHeight</div>\r
+ <div class="methodsignature"><code>void <strong>setHeight</strong>(String <em>height</em>)</code></div>\r
+ <div class="summary">\r
+ [<em>not available after initialization</em>]\r
+ <br />\r
+ Sets the outer height of the console window. Any valid CSS length may be used.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getMaxMessages</div>\r
+ <div class="methodsignature"><code>Number <strong>getMaxMessages</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns the largest number of messages displayed and stored by the console window.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setMaxMessages</div>\r
+ <div class="methodsignature"><code>void <strong>setMaxMessages</strong>(Number <em>maxMessages</em>)</code></div>\r
+ <div class="summary">\r
+ [<em>not available after initialization</em>]\r
+ <br />\r
+ Sets the largest number of messages displayed and stored by the console window. Set\r
+ this to <code>null</code> to make this number unlimited.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isShowCommandLine</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isShowCommandLine</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the console includes a command line.\r
+ Default value is <code>true</code>.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setShowCommandLine</div>\r
+ <div class="methodsignature"><code>void <strong>setShowCommandLine</strong>(Boolean <em>showCommandLine</em>)</code></div>\r
+ <div class="summary">\r
+ Sets whether the console includes a command line.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getCommandLineObjectExpansionDepth</div>\r
+ <div class="methodsignature"><code>Number <strong>getCommandLineObjectExpansionDepth</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns the number of levels to expand when an object value is logged to the console.\r
+ Each property of an object above this threshold will be expanded if it is itself an object\r
+ or array, otherwise its string representation will be displayed. Default value is 1 (i.e.\r
+ the properties of the object logged will be displayed in their string representation but\r
+ not expanded).\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setCommandLineObjectExpansionDepth:</div>\r
+ <div class="methodsignature"><code>void <strong>setCommandLineObjectExpansionDepth</strong>(Number <em>expansionDepth</em>)</code></div>\r
+ <div class="summary">\r
+ Sets the number of levels to expand when an object value is logged to the console.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getCommandWindow</div>\r
+ <div class="methodsignature"><code>Window <strong>getCommandWindow</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns a reference to the window in which commands typed into the command line\r
+ are currently being executed.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setCommandWindow</div>\r
+ <div class="methodsignature"><code>void <strong>setCommandWindow</strong>(Window <em>commandWindow</em>)</code></div>\r
+ <div class="summary">\r
+ Sets the window in which commands typed into the command line are executed.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getCommandLayout</div>\r
+ <div class="methodsignature"><code>Number <strong>getCommandLayout</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns the layout used to format the output for commands typed into the command line.\r
+ The default value is a <code><a href="#patternlayout">PatternLayout</a></code> with\r
+ pattern string <code>%m</code>\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setCommandLayout</div>\r
+ <div class="methodsignature"><code>void <strong>setCommandLayout</strong>(Layout <em>commandLayout</em>)</code></div>\r
+ <div class="summary">\r
+ Sets the layout used to format the output for commands typed into the command line.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">clear</div>\r
+ <div class="methodsignature"><code>void <strong>clear</strong>()</code></div>\r
+ <div class="summary">\r
+ Clears all messages from the console window.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">show</div>\r
+ <div class="methodsignature"><code>void <strong>show</strong>()</code></div>\r
+ <div class="summary">\r
+ <p>\r
+ Shows / unhides the console window.\r
+ </p>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ In Safari (and possibly other browsers), hiding an <code>iframe</code>\r
+ resets its document, thus destroying the console window.\r
+ </li>\r
+ </ul>\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">hide</div>\r
+ <div class="methodsignature"><code>void <strong>hide</strong>()</code></div>\r
+ <div class="summary">\r
+ <p>\r
+ Hides / minimizes the console window.\r
+ </p>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ In Safari (and possibly other browsers), hiding an <code>iframe</code>\r
+ resets its document, thus destroying the console window.\r
+ </li>\r
+ </ul>\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">close</div>\r
+ <div class="methodsignature"><code>void <strong>close</strong>()</code></div>\r
+ <div class="summary">\r
+ Removes the console window iframe from the main document.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">focus</div>\r
+ <div class="methodsignature"><code>void <strong>focus</strong>()</code></div>\r
+ <div class="summary">\r
+ Brings the console window to the top and gives it the focus.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">focusCommandLine</div>\r
+ <div class="methodsignature"><code>void <strong>focusCommandLine</strong>()</code></div>\r
+ <div class="summary">\r
+ Brings the console window to the top and gives the focus to the command line.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">focusSearch</div>\r
+ <div class="methodsignature"><code>void <strong>focusSearch</strong>()</code></div>\r
+ <div class="summary">\r
+ Brings the console window to the top and gives the focus to the search box.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">evalCommandAndAppend</div>\r
+ <div class="methodsignature"><code>void <strong>evalCommandAndAppend</strong>(String <em>expr</em>)</code></div>\r
+ <div class="summary">\r
+ Evaluates the expression and appends the result to the console.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">addCommandLineFunction</div>\r
+ <div class="methodsignature"><code>void <strong>addCommandLineFunction</strong>(String <em>functionName</em>, Function <em>commandLineFunction</em>)</code></div>\r
+ <div class="summary">\r
+ <p>\r
+ Adds a function with the name specified to the list of functions available on the command line.\r
+ This feature may be used to add custom functions to the command line.\r
+ </p>\r
+ <p>\r
+ When you call the function on the command line, <code>commandLineFunction</code> is executed with the\r
+ following three parameters:\r
+ </p>\r
+ <ul>\r
+ <li><em>appender</em>. A reference to the appender in which the command was executed;</li>\r
+ <li><em>args</em>.\r
+ An array-like list of parameters passed into the function on the command line\r
+ (actually a reference to an <code>arguments</code> object);</li>\r
+ <li><em>returnValue</em>. This is an object with two properties that allow the function to control\r
+ how the result is displayed:\r
+ <ul>\r
+ <li><em>appendResult</em>. A boolean value that determines whether the returned value from this\r
+ function is appended to the console. The default value is <code>true</code>;</li>\r
+ <li><em>isError</em>. A boolean value that specifies whether the output of this function\r
+ should be displayed as an error. The default value is <code>false</code>.</li>\r
+ </ul>\r
+ </li>\r
+ </ul>\r
+ <p>\r
+ The value returned by the function is formatted by the command layout and appended to the console.\r
+ </p>\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="browserconsoleappender">\r
+ <h3>BrowserConsoleAppender</h3>\r
+ <p class="editions">Editions: <strong>Standardl</strong></p>\r
+ <p>\r
+ Writes log messages to the browser's built-in console, if present. This only works\r
+ currently in Safari, Opera and Firefox with the excellent\r
+ <a href="http://www.getfirebug.com" title="Firebug home page (opens in new window)"\r
+ target="_blank">Firebug</a> extension installed.\r
+ </p>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ As of log4javascript 1.3, the default threshold for this appender is <code>DEBUG</code>\r
+ as opposed to <code>WARN</code> as it was previously;\r
+ </li>\r
+ <li>\r
+ <p>\r
+ As of version 1.3, log4javascript has explicit support for Firebug's logging. This includes\r
+ the following mapping of log4javascript's log levels onto Firebug's:\r
+ </p>\r
+ <ul>\r
+ <li>log4javascript <code>TRACE</code>, <code>DEBUG</code> -> Firebug <code>debug</code></li>\r
+ <li>log4javascript <code>INFO</code> -> Firebug <code>info</code></li>\r
+ <li>log4javascript <code>WARN</code> -> Firebug <code>warn</code></li>\r
+ <li>log4javascript <code>ERROR</code>, <code>FATAL</code> -> Firebug <code>error</code></li>\r
+ </ul>\r
+ <p>\r
+ ... and the ability to pass objects into Firebug and take advantage of its object inspection.\r
+ This is because the default layout is now <code><a href="#nulllayout">NullLayout</a></code>,\r
+ which performs no formatting on an object.\r
+ </p>\r
+ </li>\r
+ </ul>\r
+ <h4>Constructor</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">BrowserConsoleAppender</div>\r
+ <div class="methodsignature"><code><strong>BrowserConsoleAppender</strong>()</code></div>\r
+ </li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ </div>\r
+ <div id="layouts">\r
+ <h2>Layouts</h2>\r
+ <div id="layout">\r
+ <h3>Layout</h3>\r
+ <p>\r
+ There are a few methods common to all layouts:\r
+ </p>\r
+ <h4>Methods</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">format</div>\r
+ <div class="methodsignature"><code>String <strong>format</strong>(LoggingEvent <em>loggingEvent</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">loggingEvent</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Formats the log message. You should override this method in your own layouts.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">ignoresThrowable</div>\r
+ <div class="methodsignature"><code>Boolean <strong>ignoresThrowable</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the layout ignores an error object in a logging event passed\r
+ to its <code>format</code> method.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getContentType</div>\r
+ <div class="methodsignature"><code>String <strong>getContentType</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns the content type of the output of the layout.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">allowBatching</div>\r
+ <div class="methodsignature"><code>Boolean <strong>allowBatching</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the layout's output is suitable for batching.\r
+ <code><a href="#jsonlayout">JsonLayout</a></code> and <code><a href="#xmllayout">XmlLayout</a></code>\r
+ are the only built-in layouts that return true for this method.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getDataValues</div>\r
+ <div class="methodsignature"><code>Array <strong>getDataValues</strong>(LoggingEvent <em>loggingEvent</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">loggingEvent</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Used internally by log4javascript in constructing formatted output for some layouts.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setKeys</div>\r
+ <div class="methodsignature"><code>void <strong>setKeys</strong>(String <em>loggerKey</em>,\r
+ String <em>timeStampKey</em>, String <em>levelKey</em>, String <em>messageKey</em>,\r
+ String <em>exceptionKey</em>, String <em>urlKey</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">loggerKey</code>\r
+ <div>\r
+ Parameter to use for the log message's logger name. Default is <code>logger</code>.\r
+ </div>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">timeStampKey</code>\r
+ <div>\r
+ Parameter to use for the log message's timestamp. Default is <code>timestamp</code>.\r
+ </div>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">levelKey</code>\r
+ <div>\r
+ Parameter to use for the log message's level. Default is <code>level</code>.\r
+ </div>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">messageKey</code>\r
+ <div>\r
+ Parameter to use for the message itself. Default is <code>message</code>.\r
+ </div>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">exceptionKey</code>\r
+ <div>\r
+ Parameter to use for the log message's error (exception). Default is <code>exception</code>.\r
+ </div>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">urlKey</code>\r
+ <div>\r
+ Parameter to use for the current page URL. Default is <code>url</code>.\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ This method is used to change the default keys used to create formatted name-value pairs\r
+ for the properties of a log message, for layouts that do this. These layouts are\r
+ <code><a href="#jsonlayout">JsonLayout</a></code> and\r
+ <code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setCustomField</div>\r
+ <div class="methodsignature"><code>void <strong>setCustomField</strong>(String <em>name</em>,\r
+ String <em>value</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">name</code>\r
+ <div>\r
+ Name of the custom property you wish to be included in the formmtted output.\r
+ </div>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">value</code>\r
+ <div>\r
+ Value of the custom property you wish to be included in the formatted output.\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Some layouts (<code><a href="#jsonlayout">JsonLayout</a></code>,\r
+ <code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>,\r
+ <code><a href="#patternlayout">PatternLayout</a></code> and\r
+ <code><a href="#xmllayout">XmlLayout</a></code>) allow you to set\r
+ custom fields (e.g. a session id to send to the server) to the\r
+ formatted output. Use this method to set a custom field. If there\r
+ is already a custom field with the specified name, its value will\r
+ be updated with <code>value</code>.\r
+ </div>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ <p>\r
+ From version 1.4, the custom field value may be a function. In this\r
+ case, the function is run at the time the layout's format method is called,\r
+ with the following two parameters:\r
+ </p>\r
+ <ul>\r
+ <li><em>layout</em>. A reference to the layout being used;</li>\r
+ <li><em>loggingEvent</em>. A reference to the logging event being formatted.</li>\r
+ </ul>\r
+ </li>\r
+ </ul>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">hasCustomFields</div>\r
+ <div class="methodsignature"><code>Boolean <strong>hasCustomFields</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the layout has any custom fields.\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="nulllayout">\r
+ <h3>NullLayout</h3>\r
+ <p class="editions">Editions: <strong>All</strong></p>\r
+ <p>\r
+ The most basic layout. NullLayout's <code>format()</code> methods performs no\r
+ formatting at all and simply returns the message logged.\r
+ </p>\r
+ <h4>Constructor</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">NullLayout</div>\r
+ <div class="methodsignature"><code><strong>NullLayout</strong>()</code></div>\r
+ </li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="simplelayout">\r
+ <h3>SimpleLayout</h3>\r
+ <p class="editions">Editions: <strong>Standard, Production</strong></p>\r
+ <p>\r
+ Provides basic formatting. SimpleLayout consists of the level of the log statement,\r
+ followed by " - " and then the log message itself. For example,\r
+ </p>\r
+ <p><code>DEBUG - Hello world</code></p>\r
+ <h4>Constructor</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">SimpleLayout</div>\r
+ <div class="methodsignature"><code><strong>SimpleLayout</strong>()</code></div>\r
+ </li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="patternlayout">\r
+ <h3>PatternLayout</h3>\r
+ <p class="editions">Editions: <strong>All</strong></p>\r
+ <p>\r
+ Provides a flexible way of formatting a log message by means of a conversion pattern\r
+ string. The behaviour of this layout is a full implementation of <code>PatternLayout</code>\r
+ in log4j, with the exception of the set of conversion characters - log4javascript's is\r
+ necessarily a subset of that of log4j with a few additions of its own, since many of\r
+ the conversion characters in log4j only make sense in the context of Java.\r
+ </p>\r
+ <p>\r
+ The conversion pattern consists of literal text interspersed with special strings starting with\r
+ a % symbol called <em>conversion specifiers</em>. A conversion specifier consists of the\r
+ % symbol, a conversion character (possible characters are listed below) and\r
+ <em>format modifiers</em>. For full documentation of the conversion pattern, see\r
+ <a href="http://logging.apache.org/log4j/docs/api/org/apache/log4j/PatternLayout.html" target="_blank">log4j's\r
+ documentation</a>. Below is a list of all conversion characters available in log4javascript.\r
+ </p>\r
+ <h4>Conversion characters</h4>\r
+ <table border="1" cellspacing="0">\r
+ <thead>\r
+ <tr>\r
+ <th>Conversion Character</th>\r
+ <th>Effect</th>\r
+ </tr>\r
+ </thead>\r
+ <tbody>\r
+ <tr>\r
+ <td>a</td>\r
+ <td>\r
+ <p>\r
+ Outputs log messages specified as an array.\r
+ </p>\r
+ <p>\r
+ Behaves exactly like <code>%m</code>, except that multiple log messages are\r
+ assumed to have been specified in the logging call as an array rather than\r
+ as multiple parameters.\r
+ </p>\r
+ <p>\r
+ <strong>Since: 1.4</strong>\r
+ </p>\r
+ </td>\r
+ </tr>\r
+ <tr>\r
+ <td>c</td>\r
+ <td>\r
+ <p>\r
+ Outputs the logger name.\r
+ </p>\r
+ </td>\r
+ </tr>\r
+ <tr>\r
+ <td>d</td>\r
+ <td>\r
+ <p>\r
+ Outputs the date of the logging event. The date conversion specifier\r
+ may be followed by a date format specifier enclosed between braces. For\r
+ example, <code>%d{HH:mm:ss,SSS}</code> or\r
+ <code>%d{dd MMM yyyy HH:mm:ss,SSS}</code>. If no date\r
+ format specifier is given then ISO8601 format is assumed.\r
+ </p>\r
+ <p>\r
+ The date format specifier is the same as that used by Java's\r
+ <code><a href="http://java.sun.com/j2se/1.5.0/docs/api/java/text/SimpleDateFormat.html"\r
+ target="_blank">SimpleDateFormat</a></code>. log4javascript\r
+ includes a full implementation of SimpleDateFormat's\r
+ <code>format</code> method, with the exception of the pattern letter\r
+ 'z', (string representation of the timezone) for which the information\r
+ is not available in JavaScript.\r
+ </p>\r
+ </td>\r
+ </tr>\r
+ <tr>\r
+ <td>f</td>\r
+ <td>\r
+ <p>\r
+ Outputs the value of a custom field set on the layout. If present, the specifier gives\r
+ the index in the array of custom fields to use; otherwise, the first custom field in the\r
+ array is used.\r
+ </p>\r
+ <p>\r
+ <strong>Since: 1.3</strong>\r
+ </p>\r
+ </td>\r
+ </tr>\r
+ <tr>\r
+ <td>m</td>\r
+ <td>\r
+ <p>\r
+ Outputs the log messages of the logging event (i.e. the log\r
+ messages supplied by the client code).\r
+ </p>\r
+ <p>\r
+ As of version 1.4, multiple log messages may be supplied to logging calls.\r
+ <code>%m</code> displays each log message (using the rules below) one after\r
+ another, separated by spaces. \r
+ </p>\r
+ <p>\r
+ As of version 1.3, an object may be specified as the log message and will\r
+ be expanded to show its properties in the output, provided that a specifier\r
+ containing the number of levels to expand is provided. If no specifier is\r
+ provided then the message will be treated as a string regardless of its type.\r
+ For example, <code>%m{1}</code> will display an expansion of the object one\r
+ level deep, i.e. each property of the object will be displayed but if the\r
+ property value is itself an object it will not be expanded and will appear\r
+ as <code>[object Object]</code>.\r
+ </p>\r
+ </td>\r
+ </tr>\r
+ <tr>\r
+ <td>n</td>\r
+ <td>\r
+ <p>\r
+ Outputs a line separator.\r
+ </p>\r
+ </td>\r
+ </tr>\r
+ <tr>\r
+ <td>p</td>\r
+ <td>\r
+ <p>\r
+ Outputs the level of the logging event.\r
+ </p>\r
+ </td>\r
+ </tr>\r
+ <tr>\r
+ <td>r</td>\r
+ <td>\r
+ <p>\r
+ Outputs the number of milliseconds since log4javascript was initialized.\r
+ </p>\r
+ </td>\r
+ </tr>\r
+ <tr>\r
+ <td>%</td>\r
+ <td>\r
+ <p>\r
+ The sequence %% outputs a single percent sign.\r
+ </p>\r
+ </td>\r
+ </tr>\r
+ </tbody>\r
+ </table>\r
+ <h4>Static properties</h4>\r
+ <ul class="propertieslist">\r
+ <li class="property">\r
+ <div class="name">TTCC_CONVERSION_PATTERN</div>\r
+ <div class="summary">\r
+ Built-in conversion pattern, equivalent to <code>%r %p %c - %m%n</code>.\r
+ </div>\r
+ </li>\r
+ <li class="property">\r
+ <div class="name">DEFAULT_CONVERSION_PATTERN</div>\r
+ <div class="summary">\r
+ Built-in conversion pattern, equivalent to <code>%m%n</code>.\r
+ </div>\r
+ </li>\r
+ <li class="property">\r
+ <div class="name">ISO8601_DATEFORMAT</div>\r
+ <div class="summary">\r
+ Built-in date format (and also the default), equivalent to\r
+ <code>yyyy-MM-dd HH:mm:ss,SSS</code>.\r
+ </div>\r
+ </li>\r
+ <li class="property">\r
+ <div class="name">DATETIME_DATEFORMAT</div>\r
+ <div class="summary">\r
+ Built-in date format, equivalent to <code>dd MMM YYYY HH:mm:ss,SSS</code>.\r
+ </div>\r
+ </li>\r
+ <li class="property">\r
+ <div class="name">ABSOLUTETIME_DATEFORMAT</div>\r
+ <div class="summary">\r
+ Built-in date format, equivalent to <code>HH:mm:ss,SSS</code>.\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ <h4>Constructor</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">PatternLayout</div>\r
+ <div class="methodsignature"><code><strong>PatternLayout</strong>(String <em>pattern</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">pattern</code>\r
+ <div>\r
+ The conversion pattern string to use.\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ </li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="xmllayout">\r
+ <h3>XmlLayout</h3>\r
+ <p class="editions">Editions: <strong>Standard, Production</strong></p>\r
+ <p>\r
+ Based on log4j's <code>XmlLayout</code>, this layout formats a log message as a\r
+ fragment of XML. An example of the format of the fragment is as follows:\r
+ </p>\r
+ <pre>\r
+<log4javascript:event logger="[default]" timestamp="1201048234203" level="ERROR">\r
+<log4javascript:message><![CDATA[Big problem!]]></log4javascript:message>\r
+<log4javascript:exception><![CDATA[Nasty error on line number 1\r
+ in file http://log4javascript.org/test.html]]></log4javascript:exception>\r
+</log4javascript:event>\r
+</pre>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ This layout supports batching of log messages when used in an\r
+ <code><a href="#ajaxappender">AjaxAppender</a></code>. A batch of\r
+ messages is simply concatenated to form a string of several XML\r
+ frgaments similar to that above.\r
+ </li>\r
+ <li>\r
+ The <code><log4javascript:exception></code> element is only present if an\r
+ exception was passed into the original log call.\r
+ </li>\r
+ <li>\r
+ As of version 1.4, timestamps are returned as milliseconds since midnight of\r
+ January 1, 1970 rather than seconds as in previous versions. This allows finer\r
+ measurement of the time a logging event occurred and is also the JavaScript\r
+ <code>Date</code> object's standard measurement.\r
+ </li>\r
+ <li>\r
+ Also as of version 1.4, multiple messages may be specified as separate parameters\r
+ in a single logging call. In <code>XmlLayout</code>, multiple messages may be\r
+ formatted as a single combined message or may be formated as several\r
+ <code><log4javascript:message></code> elements inside one\r
+ <code><log4javascript:messages></code> element as shown below:\r
+ <br />\r
+ <pre>\r
+<log4javascript:event logger="[default]" timestamp="1201048234203" level="ERROR">\r
+<log4javascript:messages>\r
+ <log4javascript:message><![CDATA[Big problem!]]></log4javascript:message>\r
+ <log4javascript:message><![CDATA[Value of x when this error\r
+ occurred: 3]]></log4javascript:message>\r
+</log4javascript:messages>\r
+<log4javascript:exception><![CDATA[Nasty error on line number 1\r
+ in file http://log4javascript.org/test.html]]></log4javascript:exception>\r
+</log4javascript:event>\r
+</pre>\r
+ </li>\r
+ <li>\r
+ As of version 1.3, custom fields may be added to the output. Each field will\r
+ add a tag of the following form inside the <code><log4javascript:event></code>\r
+ tag:\r
+ <br />\r
+ <pre>\r
+<log4javascript:customfield name="sessionid"><![CDATA[1234]]></log4javascript:customfield>\r
+</pre>\r
+ </li>\r
+ </ul>\r
+ <h4>Constructor</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">XmlLayout</div>\r
+ <div class="methodsignature"><code><strong>XmlLayout</strong>([Boolean <em>combineMessages</em>])</code></div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">combineMessages</code>\r
+ <div>\r
+ Whether or not to format multiple log messages as a combined single\r
+ <code><log4javascript:message></code> element\r
+ composed of each individual message separated by line breaks or to include\r
+ a <code><log4javascript:message></code> element for each message inside\r
+ one <code><log4javascript:messages></code> element.\r
+ If not specified, defaults to <code>true</code>.\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ </li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="jsonlayout">\r
+ <h3>JsonLayout</h3>\r
+ <p class="editions">Editions: <strong>Standard, Production</strong></p>\r
+ <p>\r
+ Formats a logging event into JavaScript Object Notation (JSON).\r
+ JSON is a subset of JavaScript's object literal syntax, meaning that log\r
+ messages formatted with this layout can be interpreted directly by JavaScript\r
+ and converted into objects. See\r
+ <a href="http://json.org/" target="_blank" title="json.org (opens in new window)">json.org</a> for more details\r
+ about JSON.\r
+ </p>\r
+ <p>Example:</p>\r
+ <pre>\r
+{\r
+ "logger": "[default]",\r
+ "timeStamp": 1201048234203,\r
+ "level": "ERROR",\r
+ "url": "http://log4javascript.org/test.html",\r
+ "message": "Big problem!",\r
+ "exception": "Nasty error on line number 1 in file\r
+ http://log4javascript.org/test.html"\r
+}\r
+</pre>\r
+ <p>\r
+ The <code>exception</code> property is only present if an exception was passed\r
+ into the original log call.\r
+ </p>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ This layout supports batching of log messages when used in an\r
+ <code><a href="#ajaxappender">AjaxAppender</a></code>. When sent singly\r
+ the layout formats the log message as a single JavaScript object literal;\r
+ when sent as a batch, the messages are formatted as an array literal whose\r
+ elements are log message objects.\r
+ </li>\r
+ <li>\r
+ <p>\r
+ As of version 1.3, custom fields may be added to the output. Each field will\r
+ add a property of the following form to the main object literal:\r
+ </p>\r
+ <pre>\r
+ "sessionid": 1234\r
+</pre>\r
+ </li>\r
+ <li>\r
+ From version 1.4, the variable names used for log event properties such as\r
+ the message, timestamp and exception are specified using the <code>setKeys()</code>\r
+ method of <code><a href="#layout">Layout</a></code>.\r
+ </li>\r
+ <li>\r
+ <p>\r
+ Also as of version 1.4, multiple messages may be specified as separate parameters\r
+ in a single logging call. In <code>JsonLayout</code>, multiple messages may be\r
+ formatted as a single combined message or may be formated as an array of messages\r
+ as shown below:\r
+ </p>\r
+ <pre>\r
+{\r
+ "logger": "[default]",\r
+ "timeStamp": 1201048234203,\r
+ "level": "ERROR",\r
+ "url": "http://log4javascript.org/test.html",\r
+ "message": [\r
+ "Big problem!",\r
+ "Value of x when this error occurred: 3"\r
+ ],\r
+ "exception": "Nasty error on line number 1 in file\r
+ http://log4javascript.org/test.html"\r
+}\r
+</pre>\r
+ </li>\r
+ </ul>\r
+ <h4>Constructor</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">JsonLayout</div>\r
+ <div class="methodsignature"><code><strong>JsonLayout</strong>([Boolean <em>readable</em>, Boolean <em>combineMessages</em>])</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">readable</code>\r
+ <div>\r
+ Whether or not to format each log message with line breaks and tabs.\r
+ If not specified, defaults to <code>false</code>.\r
+ </div>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">combineMessages</code>\r
+ <div>\r
+ Whether or not to format multiple log messages as a combined single\r
+ <code>message</code> property composed of each individual message separated by line\r
+ breaks or to format multiple messages as an array.\r
+ If not specified, defaults to <code>true</code>.\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ </li>\r
+ </ul>\r
+ <h4>Methods</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">isReadable</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isReadable</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether or not to each log message is formatted with line breaks and tabs.\r
+ </div>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ <p>\r
+ <code>setReadable</code> has been removed in version 1.4. This property can\r
+ be set via the constructor.\r
+ </p>\r
+ </li>\r
+ </ul>\r
+ </li>\r
+ </ul>\r
+ </div>\r
+ <div id="httppostdatalayout">\r
+ <h3>HttpPostDataLayout</h3>\r
+ <p class="editions">Editions: <strong>Standard, Production</strong></p>\r
+ <p>\r
+ Formats the log message as a simple URL-encoded string from which a simple\r
+ server-side script may extract parameters such as the log message, severity\r
+ and timestamp. This is the default layout for\r
+ <code><a href="#ajaxappender">AjaxAppender</a></code>.\r
+ </p>\r
+ <h4>Constructor</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">HttpPostDataLayout</div>\r
+ <div class="methodsignature"><code><strong>HttpPostDataLayout</strong>()</code></div>\r
+ </li>\r
+ </ul>\r
+ <p><strong>Notes</strong></p>\r
+ <ul>\r
+ <li>\r
+ As of version 1.3, custom fields may be added to the output. Each field will\r
+ be added as a parameter to the post data.\r
+ </li>\r
+ <li>\r
+ From version 1.4, the variable names used for log event properties such as\r
+ the message, timestamp and exception are specified using the <code>setKeys()</code>\r
+ method of <code><a href="#layout">Layout</a></code>.\r
+ </li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ </div>\r
+ <div id="enabling">\r
+ <h2>Enabling / disabling log4javascript</h2>\r
+ <p>\r
+ All logging can be enabled or disabled in log4javascript in a number of ways:\r
+ </p>\r
+ <ul>\r
+ <li>\r
+ At any time, you can call\r
+ <code>log4javascript.setEnabled(<em>enabled</em>)</code>. This will\r
+ enable or disable all logging, depending on whether <code>enabled</code>\r
+ is set to <code>true</code> or <code>false</code>.\r
+ </li>\r
+ <li>\r
+ <p>\r
+ Assign a value to the global variable <code>log4javascript_disabled</code>.\r
+ The idea of this is so that you can enable or disable logging for a whole site by\r
+ including a JavaScript file in all your pages, and allowing this file to be\r
+ included <strong>before</strong> log4javascript.js to guarantee that no logging\r
+ can take place without having to alter log4javascript.js itself. Your included\r
+ .js file would include a single line such as the following:\r
+ </p>\r
+ <p>\r
+ <code>var log4javascript_disabled = true;</code>\r
+ </p>\r
+ </li>\r
+ <li>\r
+ Assign your logger object a value of <code>log4javascript.getNullLogger()</code>.\r
+ </li>\r
+ <li>\r
+ Replace your copy of log4javascript_x.js with stubs/log4javascript_x.js, provided in the\r
+ distribution. This file has a stub version of each of the functions and methods\r
+ in the log4javascript API and can simply be dropped in in place of the main file.\r
+ The compressed version of the stub is typically 15 times smaller than the\r
+ compressed version of the main file.\r
+ </li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="errorhandling">\r
+ <h2>log4javascript error handling</h2>\r
+ <p>\r
+ log4javascript has a single rudimentary logger-like object of its own to handle\r
+ messages generated by log4javascript itself. This logger is called <code>LogLog</code>\r
+ and is accessed via <code>log4javascript.logLog</code>.\r
+ </p>\r
+ <div id="loglog">\r
+ <h4>Methods</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">setQuietMode</div>\r
+ <div class="methodsignature"><code>void <strong>setQuietMode</strong>(Boolean <em>quietMode</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">quietMode</code>\r
+ <div>\r
+ Whether to turn quiet mode on or off.\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Sets whether <code>LogLog</code> is in quiet mode or not. In quiet mode, no\r
+ messages sent to <code>LogLog</code> have any visible effect. By default,\r
+ quiet mode is switched off.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setAlertAllErrors</div>\r
+ <div class="methodsignature"><code>void <strong>setAlertAllErrors</strong>(Boolean <em>alertAllErrors</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">showAllErrors</code>\r
+ <div>\r
+ Whether to show all errors or just the first.\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Sets how many errors <code>LogLog</code> will display alerts for. By default,\r
+ only the first error encountered generates an alert to the user. If you turn\r
+ all errors on by supplying <code>true</code> to this method then all errors\r
+ will generate alerts.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">debug</div>\r
+ <div class="methodsignature"><code>void <strong>debug</strong>(String <em>message</em>[, Error <em>exception</em>])</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">message</code>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">exception</code>\r
+ [<em>optional</em>]\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Logs a debugging message to an in-memory list. This implementation is new in version 1.4.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">displayDebug</div>\r
+ <div class="methodsignature"><code>void <strong>displayDebug</strong>()</code></div>\r
+ <div class="summary">\r
+ Displays an alert of all debugging messages. This method is new in version 1.4.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">warn</div>\r
+ <div class="methodsignature"><code>void <strong>warn</strong>(String <em>message</em>[, Error <em>exception</em>])</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">message</code>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">exception</code>\r
+ [<em>optional</em>]\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Currently has no effect.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">error</div>\r
+ <div class="methodsignature"><code>void <strong>error</strong>(String <em>message</em>[, Error <em>exception</em>])</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">message</code>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">exception</code>\r
+ [<em>optional</em>]\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Generates an alert to the user if and only if the error is the first one\r
+ encountered and <code>setAlertAllErrors(true)</code> has not been called.\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ </div>\r
+ <div id="differences">\r
+ <h2>Differences between log4javascript and log4j</h2>\r
+ <p>\r
+ For the sake of keeping log4javascript as light and useful as possible, many\r
+ of the features of log4j that seem over-complex or inappropriate for\r
+ JavaScript have not been implemented. These include:\r
+ </p>\r
+ <ul>\r
+ <li>Filters</li>\r
+ <li>Configurators</li>\r
+ <li>Renderers</li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ </div>\r
+ <div id="footer">\r
+ <span class="externallinkinfo">\r
+ <strong>NB.</strong> All external links open in a new window.\r
+ </span>\r
+ Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>\r
+ <br />\r
+ log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"\r
+ title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,\r
+ Version 2.0</a>\r
+\r
+ </div>\r
+ </div>\r
+\r
+ </body>\r
+</html>\r
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript 1.4 Lite manual</title>\r
+ <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />\r
+ <meta name="author" content="Tim Down - tim@log4javascript.org" />\r
+ <meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />\r
+ <meta name="robots" content="all" />\r
+ <link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />\r
+ </head>\r
+ <body>\r
+ <div id="container" class="nonav">\r
+ <div id="header">\r
+ <h1><a href="index.html">log4javascript</a></h1>\r
+ </div>\r
+ <div id="content">\r
+ <div id="nav">\r
+ <a class="navitem" href="../index.html">home</a>\r
+ | <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>\r
+ | <a class="navitem" href="index.html">docs</a>\r
+ | <a class="navitem" href="quickstart.html">quick start</a>\r
+ | <a class="navitem" href="../demos/index.html">demos</a>\r
+ | <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>\r
+ | <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>\r
+ </div>\r
+ <h1>log4javascript 1.4 Lite manual</h1>\r
+ <h2>Contents</h2>\r
+ <ul>\r
+ <li><a href="#intro">Introduction</a></li>\r
+ <li><a href="#log4javascript">log4javascript static properties/methods</a></li>\r
+ <li><a href="#levels">Levels</a></li>\r
+ <li><a href="#loggers">Loggers</a></li>\r
+ <li><a href="#enabling">Enabling / disabling log4javascript Lite</a></li>\r
+ </ul>\r
+ <div id="intro">\r
+ <h2>Introduction</h2>\r
+ <p>\r
+ log4javascript Lite is designed to be a basic, lightweight, cross-browser logging tool. It\r
+ provides functions to log messages of different severity to a pop-up window using the exactly\r
+ the same syntax as log4javascript. It is designed for situations when the key requirement is just\r
+ to display logging messages without needing all the features of the standard version of\r
+ log4javascript. \r
+ </p>\r
+ <p>\r
+ Below is the complete list of functions and properties available in log4javascript Lite.\r
+ They make up a small subset of those provided by the standard version of\r
+ log4javascript. Each function is <strong>named and called identically to the equivalent\r
+ function in log4javascript</strong>. Please refer to the\r
+ <a href="manual.html">log4javascript manual</a> for a detailed explanation\r
+ of all the concepts alluded to in this document.\r
+ </p>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="log4javascript">\r
+ <h2>log4javascript static properties/methods</h2>\r
+ <h4>Properties</h4>\r
+ <ul class="propertieslist">\r
+ <li class="property">\r
+ <div class="name">version</div>\r
+ <div class="summary">\r
+ The version number of your copy of log4javascript.\r
+ </div>\r
+ </li>\r
+ <li class="property">\r
+ <div class="name">edition</div>\r
+ <div class="summary">\r
+ The edition of your copy of log4javascript ("log4javascript_lite" in this case").\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ <h4>Methods</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">getDefaultLogger</div>\r
+ <div class="methodsignature"><code>Logger <strong>getDefaultLogger</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns the default and only logger (apart from the null logger). The default logger\r
+ logs to a simple pop-up window.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getNullLogger</div>\r
+ <div class="methodsignature"><code>Logger <strong>getNullLogger</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns an empty logger. Useful for disabling all logging.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setEnabled</div>\r
+ <div class="methodsignature"><code>void <strong>setEnabled</strong>(Boolean <em>enabled</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">enabled</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Enables or disables all logging, depending on <code>enabled</code>.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isEnabled</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isEnabled</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns true or false depending on whether logging is enabled.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">setShowStackTraces</div>\r
+ <div class="methodsignature"><code>void <strong>setShowStackTraces</strong>(Boolean <em>show</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">show</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Enables or disables displaying of error stack traces, depending on <code>show</code>.\r
+ By default, stack traces are not displayed. (Only works in Firefox)\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="levels">\r
+ <h2>Levels</h2>\r
+ <p>\r
+ Levels are available as static properties of the <code>log4javascript.Level</code>\r
+ object. In ascending order of severity:\r
+ </p>\r
+ <ol>\r
+ <li><code>log4javascript.Level.ALL</code></li>\r
+ <li><code>log4javascript.Level.TRACE</code></li>\r
+ <li><code>log4javascript.Level.DEBUG</code></li>\r
+ <li><code>log4javascript.Level.INFO</code></li>\r
+ <li><code>log4javascript.Level.WARN</code></li>\r
+ <li><code>log4javascript.Level.ERROR</code></li>\r
+ <li><code>log4javascript.Level.FATAL</code></li>\r
+ <li><code>log4javascript.Level.NONE</code></li>\r
+ </ol>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="loggers">\r
+ <h2>Loggers</h2>\r
+ <p>\r
+ There are only two loggers in log4javascript Lite: the default logger obtained\r
+ by calling <code>log4javascript.getDefaultLogger()</code> and the empty logger\r
+ returned by <code>log4javascript.getNullLogger()</code>.\r
+ </p>\r
+ <h4>Logger methods</h4>\r
+ <ul class="propertieslist">\r
+ <li class="method">\r
+ <div class="name">setLevel</div>\r
+ <div class="methodsignature"><code>void <strong>setLevel</strong>(Level <em>level</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">level</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Sets the level. Log messages of a lower level than <code>level</code> will not be logged.\r
+ Default value is <code>ALL</code> (unlike in log4javascript, where the default level is\r
+ <code>DEBUG</code>).\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">getLevel</div>\r
+ <div class="methodsignature"><code>Level <strong>getLevel</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns the level for this logger.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">trace</div>\r
+ <div class="methodsignature"><code>void <strong>trace</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">message1[, message2...]</code>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">exception</code>\r
+ [<em>optional</em>]\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Logs one or more messages and optionally an error at level <code>TRACE</code>.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">debug</div>\r
+ <div class="methodsignature"><code>void <strong>debug</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">message1[, message2...]</code>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">exception</code>\r
+ [<em>optional</em>]\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Logs one or more messages and optionally an error at level <code>DEBUG</code>.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">info</div>\r
+ <div class="methodsignature"><code>void <strong>info</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">message1[, message2...]</code>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">exception</code>\r
+ [<em>optional</em>]\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Logs one or more messages and optionally an error at level <code>INFO</code>.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">warn</div>\r
+ <div class="methodsignature"><code>void <strong>warn</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">message1[, message2...]</code>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">exception</code>\r
+ [<em>optional</em>]\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Logs one or more messages and optionally an error at level <code>WARN</code>.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">error</div>\r
+ <div class="methodsignature"><code>void <strong>error</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">message1[, message2...]</code>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">exception</code>\r
+ [<em>optional</em>]\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Logs one or more messages and optionally an error at level <code>ERROR</code>.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">fatal</div>\r
+ <div class="methodsignature"><code>void <strong>fatal</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">message1[, message2...]</code>\r
+ </li>\r
+ <li class="param">\r
+ <code class="paramname">exception</code>\r
+ [<em>optional</em>]\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Logs one or more messages and optionally an error at level <code>FATAL</code>.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isEnabledFor</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isEnabledFor</strong>(Level <em>level</em>, Error <em>exception</em>)</code></div>\r
+ <div class="paramsheading">Parameters:</div>\r
+ <ul class="params">\r
+ <li class="param">\r
+ <code class="paramname">level</code>\r
+ </li>\r
+ </ul>\r
+ <div class="summary">\r
+ Returns whether the logger is enabled for the specified level. \r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isTraceEnabled</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isTraceEnabled</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the logger is enabled for <code>TRACE</code> messages.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isDebugEnabled</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isDebugEnabled</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the logger is enabled for <code>DEBUG</code> messages.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isInfoEnabled</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isInfoEnabled</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the logger is enabled for <code>INFO</code> messages.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isWarnEnabled</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isWarnEnabled</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the logger is enabled for <code>WARN</code> messages.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isErrorEnabled</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isErrorEnabled</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the logger is enabled for <code>ERROR</code> messages.\r
+ </div>\r
+ </li>\r
+ <li class="method">\r
+ <div class="name">isFatalEnabled</div>\r
+ <div class="methodsignature"><code>Boolean <strong>isFatalEnabled</strong>()</code></div>\r
+ <div class="summary">\r
+ Returns whether the logger is enabled for <code>FATAL</code> messages.\r
+ </div>\r
+ </li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ <div id="enabling">\r
+ <h2>Enabling / disabling log4javascript Lite</h2>\r
+ <p>\r
+ All logging can be enabled or disabled in log4javascript Lite in a number of ways:\r
+ </p>\r
+ <ul>\r
+ <li>\r
+ At any time, you can call\r
+ <code>log4javascript.setEnabled(<em>enabled</em>)</code>. This will\r
+ enable or disable all logging, depending on whether <code>enabled</code>\r
+ is set to <code>true</code> or <code>false</code>.\r
+ </li>\r
+ <li>\r
+ Assign your logger object a value of <code>log4javascript.getNullLogger()</code>.\r
+ </li>\r
+ <li>\r
+ Replace your copy of log4javascript_lite.js with stubs/log4javascript_lite.js, provided in the\r
+ distribution. This file has a stub version of each of the functions and methods\r
+ in the log4javascript Lite API and can simply be dropped in in place of the main file.\r
+ </li>\r
+ </ul>\r
+ <p class="linktotop">\r
+ <a href="#container">Top</a>\r
+ </p>\r
+ </div>\r
+ </div>\r
+ <div id="footer">\r
+ <span class="externallinkinfo">\r
+ <strong>NB.</strong> All external links open in a new window.\r
+ </span>\r
+ Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>\r
+ <br />\r
+ log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"\r
+ title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,\r
+ Version 2.0</a>\r
+\r
+ </div>\r
+ </div>\r
+\r
+ </body>\r
+</html>\r
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript quick start tutorial</title>\r
+ <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />\r
+ <meta name="author" content="Tim Down - tim@log4javascript.org" />\r
+ <meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />\r
+ <meta name="robots" content="all" />\r
+ <link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />\r
+ </head>\r
+ <body>\r
+ <div id="container" class="nonav">\r
+ <div id="header">\r
+ <h1><a href="index.html">log4javascript</a></h1>\r
+ </div>\r
+ <div id="content">\r
+ <div id="nav">\r
+ <a class="navitem" href="../index.html">home</a>\r
+ | <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>\r
+ | <a class="navitem" href="index.html">docs</a>\r
+ | <span class="navitem">quick start</span>\r
+ | <a class="navitem" href="../demos/index.html">demos</a>\r
+ | <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>\r
+ | <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>\r
+ </div>\r
+ <h1>log4javascript quick start tutorial</h1>\r
+ <h2>Three step guide</h2>\r
+ <ol>\r
+ <li>\r
+ <h3>Download the code</h3>\r
+ <p>\r
+ Unzip the distribution and copy log4javascript.js into the desired\r
+ location. No other files are necessary.\r
+ </p>\r
+ </li>\r
+ <li>\r
+ <h3>Initialize log4javascript in your web page</h3>\r
+ <p>\r
+ Include log4javascript.js in your page using the code below. This\r
+ code assumes log4javascript is stored in the same directory as\r
+ your web page.\r
+ </p>\r
+ <pre class="code">\r
+<script type="text/javascript" src="log4javascript.js"></script>\r
+<script type="text/javascript">\r
+ var log = log4javascript.getDefaultLogger();\r
+</script>\r
+</pre>\r
+ <p>\r
+ The default logger uses a <code><a href="manual.html#popupappender">PopUpAppender</a></code>\r
+ which opens a pop-up window. By default, this window will open when the first\r
+ log message is written. For this to work, you will need to disable any pop-up blockers\r
+ you may have.\r
+ </p>\r
+ </li>\r
+ <li>\r
+ <h3>Include logging statements in your code</h3>\r
+ <p>\r
+ You have six logging methods at your disposal, depending on the severity\r
+ of the message you wish to log. By default, all messages are logged\r
+ in the pop-up window. The logging methods are:\r
+ </p>\r
+ <ul>\r
+ <li><code>log.trace(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>\r
+ <li><code>log.debug(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>\r
+ <li><code>log.info(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>\r
+ <li><code>log.warn(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>\r
+ <li><code>log.error(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>\r
+ <li><code>log.fatal(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>\r
+ </ul>\r
+ <p>\r
+ And that's it, log away. Below are some examples of common types of logging.\r
+ </p>\r
+ </li>\r
+ </ol>\r
+ <h2>Logging examples</h2>\r
+ <ol>\r
+ <li>\r
+ <h3>A simple logging message string</h3>\r
+ <pre class="code">\r
+ log.info("Hello world");\r
+</pre>\r
+displays\r
+ <pre class="console info">\r
+19:52:03 INFO - Hello world\r
+</pre>\r
+ </li>\r
+ <li>\r
+ <h3>Logging an error with a message</h3>\r
+ <pre class="code">\r
+ try {\r
+ throw new Error("Faking something going wrong!");\r
+ } catch (e) {\r
+ log.error("An error occurred", e);\r
+ }\r
+</pre>\r
+displays\r
+ <pre class="console error">\r
+19:52:32 ERROR - An error occurred\r
+Exception: Faking something going wrong! on line number 80 in file basic.html\r
+</pre>\r
+ </li>\r
+ <li>\r
+ <h3>Logging multiple messages with one logging call</h3>\r
+ <pre class="code">\r
+ var a = "Hello";\r
+ var b = 3;\r
+ log.debug(a, b);\r
+</pre>\r
+displays\r
+ <pre class="console debug">\r
+19:53:05 DEBUG - Hello 3\r
+</pre>\r
+ </li>\r
+ <li>\r
+ <h3>Logging an object</h3>\r
+ <p>Logging an object:</p>\r
+ <pre class="code">\r
+ var obj = new Object();\r
+ obj.name = "Octopus";\r
+ obj.tentacles = 8;\r
+ log.info(obj);\r
+</pre>\r
+displays\r
+ <pre class="console info">\r
+19:53:17 INFO - {\r
+ name: Octopus,\r
+ tentacles: 8\r
+}\r
+</pre>\r
+ </li>\r
+ </ol>\r
+ <h2>Tweaking the default logger</h2>\r
+ <p>\r
+ The default logger is fine as a starting point, but what if you want the default logger\r
+ with a few different options (say, bringing the pop-up to the front whenever a log message is\r
+ logged, or having new log messages appear at the top of the pop-up rather than the bottom)?\r
+ </p>\r
+ <p>\r
+ In this case, you will need to create a new logger, then create a\r
+ <code><a href="manual.html#popupappender">PopUpAppender</a></code>, set options\r
+ on it, and add it to the logger:\r
+ </p>\r
+ <pre class="code">\r
+<script type="text/javascript" src="log4javascript.js"></script>\r
+<script type="text/javascript">\r
+ // Create the logger\r
+ var log = log4javascript.getLogger();\r
+\r
+ // Create a PopUpAppender with default options\r
+ var popUpAppender = new log4javascript.PopUpAppender();\r
+\r
+ // Change the desired configuration options\r
+ popUpAppender.setFocusPopUp(true);\r
+ popUpAppender.setNewestMessageAtTop(true);\r
+\r
+ // Add the appender to the logger\r
+ log.addAppender(popUpAppender);\r
+\r
+ // Test the logger\r
+ log.debug("Hello world!");\r
+</script>\r
+</pre>\r
+ <p>\r
+ <a href="../examples/example_quickstart_1.html" title="View example (opens in new window)"\r
+ target="_blank">See this example in action</a> (opens in new window)\r
+ </p>\r
+ <p>\r
+ Refer to the manual for more information about\r
+ <a href="manual.html#configuration">configuring appenders</a> and more\r
+ details about <code><a href="manual.html#popupappender">PopUpAppender</a></code>.\r
+ </p>\r
+ <h2>Sending log messages to the server</h2>\r
+ <p>\r
+ For this you will need to use an <code><a href="manual.html#ajaxappender">AjaxAppender</a></code>\r
+ as follows:\r
+ </p>\r
+ <pre class="code">\r
+ var ajaxAppender = new log4javascript.AjaxAppender(<em>URL</em>);\r
+ log.addAppender(ajaxAppender);\r
+</pre>\r
+ <p>\r
+ Now your log messages will appear in the pop-up window and be sent\r
+ asynchronously to the URL you specify in the form of HTTP post parameters.\r
+ No server-side code to process these requests is provided with log4javascript.\r
+ </p>\r
+ <p>\r
+ See <code><a href="manual.html#ajaxappender">AjaxAppender</a></code> for more details\r
+ on formatting log messages.\r
+ </p>\r
+ <h2>Changing the format of log messages</h2>\r
+ <p>\r
+ Using a <code><a href="manual.html#layouts">Layout</a></code>, you can\r
+ format log messages however you like. For example:\r
+ </p>\r
+ <pre class="code">\r
+ var log = log4javascript.getLogger("mylogger");\r
+ var popUpAppender = new log4javascript.PopUpAppender();\r
+ var layout = new log4javascript.PatternLayout("[%-5p] %m");\r
+ popUpAppender.setLayout(layout);\r
+</pre>\r
+ <p>A call to</p>\r
+ <pre class="code">\r
+ log.debug("Hello world");\r
+</pre>\r
+ <p>will now result in output in the pop-up window of </p>\r
+ <pre class="console debug">\r
+[DEBUG] Hello world\r
+</pre>\r
+ <p>\r
+ See <code><a href="manual.html#patternlayout">PatternLayout</a></code> for more details\r
+ on formatting log messages.\r
+ </p>\r
+ </div>\r
+ <div id="footer">\r
+ <span class="externallinkinfo">\r
+ <strong>NB.</strong> All external links open in a new window.\r
+ </span>\r
+ Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>\r
+ <br />\r
+ log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"\r
+ title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,\r
+ Version 2.0</a>\r
+\r
+ </div>\r
+ </div>\r
+\r
+ </body>\r
+</html>\r
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript - what's new in version 1.4</title>\r
+ <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />\r
+ <meta name="author" content="Tim Down - tim@log4javascript.org" />\r
+ <meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />\r
+ <meta name="robots" content="all" />\r
+ <link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />\r
+ </head>\r
+ <body>\r
+ <div id="container" class="nonav">\r
+ <div id="header">\r
+ <h1><a href="index.html">log4javascript</a></h1>\r
+ </div>\r
+ <div id="content">\r
+ <div id="nav">\r
+ <a class="navitem" href="../index.html">home</a>\r
+ | <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>\r
+ | <a class="navitem" href="index.html">docs</a>\r
+ | <a class="navitem" href="quickstart.html">quick start</a>\r
+ | <a class="navitem" href="../demos/index.html">demos</a>\r
+ | <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>\r
+ | <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>\r
+ </div>\r
+ <h1>log4javascript - what's new in version 1.4</h1>\r
+ <ul>\r
+ <li>\r
+ log4javascript now comes in three different editions: Standard, Production\r
+ and Lite. <a href="distribution.html">Full details here</a>.\r
+ </li>\r
+ <li>\r
+ Loggers are now hierarchical and work exactly the same as log4j loggers.\r
+ This means that a logger with no level set on it inherits its level from its parent,\r
+ and inherits all of its parents appenders.\r
+ </li>\r
+ <li>\r
+ The logging console used by <code><a href="manual.html#popupappender">PopUpAppender</a></code> and\r
+ <code><a href="manual.html#inpageappender">InPageAppender</a></code>now has a command line, featuring\r
+ a command history navigated with the up and down arrow keys and a number of built-in command line\r
+ functions.\r
+ </li>\r
+ <li>\r
+ It is now possible to specify multiple messages in a single log call.\r
+ </li>\r
+ <li>\r
+ Log messages may be grouped in the logging console.\r
+ </li>\r
+ <li>\r
+ Built-in timers.\r
+ </li>\r
+ <li>\r
+ Improved <code><a href="manual.html#ajaxappender">AjaxAppender</a></code>, with the ability\r
+ to send all pending log calls to the server when navigating away from a page. Timestamps now\r
+ include milliseconds. All log messages or batches of log messages are now posted as\r
+ name-value pairs.\r
+ </li>\r
+ <li>\r
+ Support for IE8 beta 2.\r
+ </li>\r
+ <li>\r
+ Many minor enhancements and bug fixes. See the <a href="../changelog.txt">change log</a> for full\r
+ details.\r
+ </li>\r
+ </ul>\r
+ <p>\r
+ Please note that there are a few minor <a href="backwardsincompatibilities.html">incompatibilities\r
+ with earlier versions of log4javascript</a>.\r
+ </p>\r
+ </div>\r
+ <div id="footer">\r
+ <span class="externallinkinfo">\r
+ <strong>NB.</strong> All external links open in a new window.\r
+ </span>\r
+ Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>\r
+ <br />\r
+ log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"\r
+ title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,\r
+ Version 2.0</a>\r
+\r
+ </div>\r
+ </div>\r
+\r
+ </body>\r
+</html>\r
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript demo redirect</title>\r
+ <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />\r
+ <meta name="author" content="Tim Down - tim@log4javascript.org" />\r
+ <meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />\r
+ <meta name="robots" content="noindex" />\r
+ <meta http-equiv="refresh" content="0; url=../demos/basic.html" />\r
+ </head>\r
+ <body>\r
+ This page has been replaced by <a href="/demos/basic.html">the basic demo page</a>.\r
+ Please use this link if you are not redirected automatically.\r
+ </body>\r
+</html>\r
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript example from manual</title>\r
+ <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />\r
+ <meta name="author" content="Tim Down - tim@log4javascript.org" />\r
+ <meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />\r
+ <meta name="robots" content="all" />\r
+ <script type="text/javascript" src="../js/log4javascript.js"></script>\r
+ <script type="text/javascript">\r
+ //<![CDATA[\r
+ var log = log4javascript.getLogger();\r
+ var popUpAppender = new log4javascript.PopUpAppender();\r
+ var popUpLayout = new log4javascript.PatternLayout("%d{HH:mm:ss} %-5p - %m%n");\r
+ popUpAppender.setLayout(popUpLayout);\r
+ log.addAppender(popUpAppender);\r
+ var ajaxAppender = new log4javascript.AjaxAppender("myloggingservlet.do");\r
+ ajaxAppender.setThreshold(log4javascript.Level.ERROR);\r
+ log.addAppender(ajaxAppender);\r
+ log.debug("Debugging message (appears in pop-up)");\r
+ log.error("Error message (appears in pop-up and in server log)");\r
+ //]]>\r
+ </script>\r
+ </head>\r
+ <body>\r
+ <h1>log4javascript example from manual</h1>\r
+\r
+\r
+ </body>\r
+</html>\r
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript quick start example 1</title>\r
+ <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />\r
+ <meta name="author" content="Tim Down - tim@log4javascript.org" />\r
+ <meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />\r
+ <meta name="robots" content="all" />\r
+ <script type="text/javascript" src="../js/log4javascript.js"></script>\r
+ <script type="text/javascript">\r
+ //<![CDATA[\r
+ // Create the logger\r
+ var log = log4javascript.getLogger(); \r
+ \r
+ // Create a PopUpAppender with default options\r
+ var popUpAppender = new log4javascript.PopUpAppender();\r
+ \r
+ // Change the desired configuration options\r
+ popUpAppender.setFocusPopUp(true);\r
+ popUpAppender.setNewestMessageAtTop(true);\r
+ \r
+ // Add the appender to the logger\r
+ log.addAppender(popUpAppender);\r
+ \r
+ // Test the logger\r
+ log.debug("Hello world!");\r
+ //]]>\r
+ </script>\r
+ </head>\r
+ <body>\r
+ <h1>log4javascript quick start example 1</h1>\r
+ \r
+ \r
+ </body>\r
+</html>\r
--- /dev/null
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+<head>\r
+<title>log4javascript</title>\r
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\r
+<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->\r
+<meta http-equiv="X-UA-Compatible" content="IE=7" />\r
+<script type="text/javascript">var isIe = false, isIePre7 = false;</script>\r
+<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->\r
+<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->\r
+<script type="text/javascript">\r
+//<![CDATA[\r
+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];}}\r
+function LogItem(){}\r
+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();}\r
+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();}\r
+this.unwrappedElementContainer=null;this.wrappedElementContainer=null;this.mainElementContainer=null;}\r
+if(this.group&&removeFromGroup){this.group.removeChild(this,doUpdate);}\r
+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(){}\r
+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=" ";}\r
+SeparatorElementContainer.prototype=new LogItemContainerElement();SeparatorElementContainer.prototype.remove=function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;};function Separator(){this.rendered=false;}\r
+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];}\r
+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();}};}}\r
+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="+";}\r
+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);}\r
+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;}\r
+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();}\r
+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];}\r
+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);}\r
+this.children=[];this.update();if(this===currentGroup){currentGroup=this.group;}\r
+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);}\r
+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(){}\r
+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;}\r
+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;}\r
+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));}\r
+LogEntryMainElementContainer.prototype=new LogEntryElementContainer();function LogEntry(level,formattedMessage){this.level=level;this.formattedMessage=formattedMessage;this.rendered=false;}\r
+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];}\r
+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");}\r
+for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setContent(content,wrappedContent);}\r
+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]);}}\r
+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(){}\r
+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=[];}\r
+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;}}}\r
+logMainContainer=$("log");if(isIePre7){addClass(logMainContainer,"oldIe");}\r
+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;}\r
+break;case 75:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusSearch();cancelKeyEvent(evt);return false;}\r
+break;case 40:case 76:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusCommandLine();cancelKeyEvent(evt);return false;}\r
+break;}};setTimeout(setLogContainerHeight,20);setShowCommandLine(showCommandLine);doSearch();};window.onunload=function(){if(mainWindowExists()){appender.unload();}\r
+appender=null;};function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}\r
+function setLoggingEnabled(enable){loggingEnabled=enable;}\r
+var appender=null;function setAppender(appenderParam){appender=appenderParam;}\r
+function setShowCloseButton(showCloseButton){$("closeButton").style.display=showCloseButton?"inline":"none";}\r
+function setShowHideButton(showHideButton){$("hideButton").style.display=showHideButton?"inline":"none";}\r
+var newestAtTop=false;function LogItemContentReverser(){}\r
+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;}\r
+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]);}}\r
+currentSearch.matches=matches;if(currentMatch){currentMatch.setCurrent();}}else if(scrollToLatest){doScrollToLatest();}}\r
+$("newestAtTop").checked=isNewestAtTop;}\r
+function toggleNewestAtTop(){var isNewestAtTop=$("newestAtTop").checked;setNewestAtTop(isNewestAtTop);}\r
+var scrollToLatest=true;function setScrollToLatest(isScrollToLatest){scrollToLatest=isScrollToLatest;if(scrollToLatest){doScrollToLatest();}\r
+$("scrollToLatest").checked=isScrollToLatest;}\r
+function toggleScrollToLatest(){var isScrollToLatest=$("scrollToLatest").checked;setScrollToLatest(isScrollToLatest);}\r
+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;}}}}\r
+var closeIfOpenerCloses=true;function setCloseIfOpenerCloses(isCloseIfOpenerCloses){closeIfOpenerCloses=isCloseIfOpenerCloses;}\r
+var maxMessages=null;function setMaxMessages(max){maxMessages=max;pruneLogEntries();}\r
+var showCommandLine=false;function setShowCommandLine(isShowCommandLine){showCommandLine=isShowCommandLine;if(loaded){$("commandLine").style.display=showCommandLine?"block":"none";setCommandInputWidth();setLogContainerHeight();}}\r
+function focusCommandLine(){if(loaded){$("command").focus();}}\r
+function focusSearch(){if(loaded){$("searchBox").focus();}}\r
+function getLogItems(){var items=[];for(var i=0,len=logItems.length;i<len;i++){logItems[i].serialize(items);}\r
+return items;}\r
+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;}}\r
+loggingEnabled=loggingReallyEnabled;}\r
+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);}\r
+logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}\r
+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]);}}}\r
+if(currentSearch){if(pruned){if(currentSearch.hasVisibleMatches()){if(currentMatchIndex===null){setCurrentMatchIndex(0);}\r
+displayMatches();}else{displayNoMatches();}}else if(!initiallyHasMatches&¤tSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}}\r
+if(scrollToLatest){doScrollToLatest();}\r
+unrenderedLogItemsExist=false;}\r
+function pruneLogEntries(){if((maxMessages!==null)&&(logEntriesAndSeparators.length>maxMessages)){var numberToDelete=logEntriesAndSeparators.length-maxMessages;var prunedLogEntries=logEntriesAndSeparators.slice(0,numberToDelete);if(currentSearch){currentSearch.removeMatches(prunedLogEntries);}\r
+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);}}\r
+logEntriesAndSeparators=array_removeFromStart(logEntriesAndSeparators,numberToDelete);return true;}\r
+return false;}\r
+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);}\r
+logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}\r
+function groupEnd(){currentGroup=(currentGroup===rootGroup)?rootGroup:currentGroup.group;}\r
+function mainPageReloaded(){currentGroup=rootGroup;var separator=new Separator();logEntriesAndSeparators.push(separator);logItems.push(separator);currentGroup.addChild(separator);}\r
+function closeWindow(){if(appender&&mainWindowExists()){appender.close(true);}else{window.close();}}\r
+function hide(){if(appender&&mainWindowExists()){appender.hide();}}\r
+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();}}\r
+function pollOpener(){if(closeIfOpenerCloses){if(mainWindowExists()){setTimeout(pollOpener,500);}else{closeWindow();}}}\r
+function mainWindowExists(){try{return(mainWindow&&!mainWindow.closed&&mainWindow[windowId]==window);}catch(ex){}\r
+return false;}\r
+var logLevels=["TRACE","DEBUG","INFO","WARN","ERROR","FATAL"];function getCheckBox(logLevel){return $("switch_"+logLevel);}\r
+function getIeWrappedLogContainer(){return $("log_wrapped");}\r
+function getIeUnwrappedLogContainer(){return $("log_unwrapped");}\r
+function applyFilters(){for(var i=0;i<logLevels.length;i++){if(getCheckBox(logLevels[i]).checked){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}\r
+updateSearchFromFilters();}\r
+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]);}}}\r
+function checkAllLevels(){for(var i=0;i<logLevels.length;i++){if(!getCheckBox(logLevels[i]).checked){getCheckBox("ALL").checked=false;return;}}\r
+getCheckBox("ALL").checked=true;}\r
+function clearLog(){rootGroup.clear();currentGroup=rootGroup;logEntries=[];logItems=[];logEntriesAndSeparators=[];doSearch();}\r
+function toggleWrap(){var enable=$("wrap").checked;if(enable){addClass(logMainContainer,"wrap");}else{removeClass(logMainContainer,"wrap");}\r
+refreshCurrentMatch();}\r
+var searchTimer=null;function scheduleSearch(){try{clearTimeout(searchTimer);}catch(ex){}\r
+searchTimer=setTimeout(doSearch,500);}\r
+function Search(searchTerm,isRegex,searchRegex,isCaseSensitive){this.searchTerm=searchTerm;this.isRegex=isRegex;this.searchRegex=searchRegex;this.isCaseSensitive=isCaseSensitive;this.matches=[];}\r
+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;}}}\r
+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);}\r
+return matchesSearch;},getNextVisibleMatchIndex:function(){for(var i=currentMatchIndex+1;i<this.matches.length;i++){if(this.matches[i].isVisible()){return i;}}\r
+for(i=0;i<=currentMatchIndex;i++){if(this.matches[i].isVisible()){return i;}}\r
+return-1;},getPreviousVisibleMatchIndex:function(){for(var i=currentMatchIndex-1;i>=0;i--){if(this.matches[i].isVisible()){return i;}}\r
+for(var i=this.matches.length-1;i>=currentMatchIndex;i--){if(this.matches[i].isVisible()){return i;}}\r
+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+\r
+preEndTag+searchTermReplacementEndTag;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+\r
+matchedText+searchTermReplacementEndTag;}\r
+startIndex=endTokenIndex+endToken.length;}\r
+logEntryContent+=preStartTag+searchString.substr(startIndex)+preEndTag;if(isIe){wrappedLogEntryContent+=searchString.substr(startIndex);}}else{logEntryContent="";wrappedLogEntryContent="";var searchTermReplacementLength=searchTermReplacementStartTag.length+\r
+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+\r
+preStartTag+matchedText+preEndTag+searchTermReplacementEndTag;logEntryContent+=preStartTag+textBeforeMatch+preEndTag+searchTermReplacement;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+\r
+matchedText+searchTermReplacementEndTag;}\r
+startIndex=searchIndex+searchTermLength;}\r
+var textAfterLastMatch=escapeHtml(logEntry.formattedMessage.substr(startIndex));logEntryContent+=preStartTag+textAfterLastMatch+preEndTag;if(isIe){wrappedLogEntryContent+=textAfterLastMatch;}}\r
+logEntry.setContent(logEntryContent,wrappedLogEntryContent);var logEntryMatches=logEntry.getSearchMatches();this.matches=this.matches.concat(logEntryMatches);}else{logEntry.setSearchMatch(false);logEntry.setContent(logEntry.formattedMessage,logEntry.formattedMessage);}\r
+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;}}}}\r
+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;}}}\r
+for(i=0,iLen=matchesToRemove.length;i<iLen;i++){array_remove(this.matches,matchesToRemove[i]);matchesToRemove[i].remove();}\r
+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;}}\r
+setCurrentMatchIndex(newMatchIndex);}}else{currentMatchIndex=null;displayNoMatches();}}};function getPageOffsetTop(el,container){var currentEl=el;var y=0;while(currentEl&¤tEl!=container){y+=currentEl.offsetTop;currentEl=currentEl.offsetParent;}\r
+return y;}\r
+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;}}\r
+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;}}\r
+function Match(logEntryLevel,spanInMainDiv,spanInUnwrappedPre,spanInWrappedDiv){this.logEntryLevel=logEntryLevel;this.spanInMainDiv=spanInMainDiv;if(isIe){this.spanInUnwrappedPre=spanInUnwrappedPre;this.spanInWrappedDiv=spanInWrappedDiv;}\r
+this.mainSpan=isIe?spanInUnwrappedPre:spanInMainDiv;}\r
+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);}\r
+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");}\r
+addClass(document.body,"searching");currentSearch=new Search(searchTerm,isRegex,searchRegex,isCaseSensitive);for(i=0;i<logEntries.length;i++){currentSearch.applyTo(logEntries[i]);}\r
+setLogContainerHeight();if(currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}else{displayNoMatches();}}}\r
+function updateSearchFromFilters(){if(currentSearch){if(currentSearch.hasMatches()){if(currentMatchIndex===null){currentMatchIndex=0;}\r
+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();}}}\r
+function refreshCurrentMatch(){if(currentSearch&¤tSearch.hasVisibleMatches()){setCurrentMatchIndex(currentMatchIndex);}}\r
+function displayMatches(){replaceClass($("searchBox"),"hasmatches","nomatches");$("searchBox").title=""+currentSearch.matches.length+" matches found";$("searchNav").style.display="block";setLogContainerHeight();}\r
+function displayNoMatches(){replaceClass($("searchBox"),"nomatches","hasmatches");$("searchBox").title="No matches found";$("searchNav").style.display="none";setLogContainerHeight();}\r
+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!=="")&¤tSearch&¤tSearch.hasVisibleMatches())?"block":"none";if(enable){removeClass($("search"),"greyedout");addClass(document.body,"searching");if($("searchHighlight").checked){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}\r
+if($("searchFilter").checked){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}\r
+$("searchDisable").checked=!enable;}else{addClass($("search"),"greyedout");removeClass(document.body,"searching");removeClass(logMainContainer,"searchhighlight");removeClass(logMainContainer,"searchfilter");}\r
+setLogContainerHeight();}\r
+function toggleSearchFilter(){var enable=$("searchFilter").checked;if(enable){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}\r
+refreshCurrentMatch();}\r
+function toggleSearchHighlight(){var enable=$("searchHighlight").checked;if(enable){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}}\r
+function clearSearch(){$("searchBox").value="";doSearch();}\r
+function searchNext(){if(currentSearch!==null&¤tMatchIndex!==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);}}}\r
+function searchPrevious(){if(currentSearch!==null&¤tMatchIndex!==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);}}}\r
+function setCurrentMatchIndex(index){currentMatchIndex=index;currentSearch.matches[currentMatchIndex].setCurrent();}\r
+function addClass(el,cssClass){if(!hasClass(el,cssClass)){if(el.className){el.className+=" "+cssClass;}else{el.className=cssClass;}}}\r
+function hasClass(el,cssClass){if(el.className){var classNames=el.className.split(" ");return array_contains(classNames,cssClass);}\r
+return false;}\r
+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];}}\r
+el.className=newClasses.join(" ");}}\r
+function replaceClass(el,newCssClass,oldCssClass){removeClass(el,oldCssClass);addClass(el,newCssClass);}\r
+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]);}}\r
+return matches;}\r
+function $(id){return document.getElementById(id);}\r
+function isDescendant(node,ancestorNode){while(node!=null){if(node===ancestorNode){return true;}\r
+node=node.parentNode;}\r
+return false;}\r
+function isOrphan(node){var currentNode=node;while(currentNode){if(currentNode==document.body){return false;}\r
+currentNode=currentNode.parentNode;}\r
+return true;}\r
+function escapeHtml(str){return str.replace(/&/g,"&").replace(/[<]/g,"<").replace(/>/g,">");}\r
+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;}\r
+return 0;}\r
+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;}\r
+return 0;}\r
+function getToolBarsHeight(){return $("switches").offsetHeight;}\r
+function getChromeHeight(){var height=getToolBarsHeight();if(showCommandLine){height+=$("commandLine").offsetHeight;}\r
+return height;}\r
+function setLogContainerHeight(){if(logMainContainer){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";logMainContainer.style.height=""+\r
+Math.max(0,windowHeight-getChromeHeight())+"px";}}\r
+function setCommandInputWidth(){if(showCommandLine){$("command").style.width=""+Math.max(0,$("commandLineContainer").offsetWidth-\r
+($("evaluateButton").offsetWidth+13))+"px";}}\r
+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];}\r
+return this.length;};}\r
+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;}};}\r
+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];}\r
+this.length=this.length-1;return firstItem;}};}\r
+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];}\r
+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]);}\r
+return itemsDeleted;};}\r
+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;}}\r
+if(index>=0){arr.splice(index,1);return index;}else{return false;}}\r
+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];}\r
+array.length=array.length-numberToRemove;}\r
+return array;}\r
+function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}\r
+return false;}\r
+function getErrorMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}\r
+return""+ex;}\r
+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();}\r
+input.focus();}\r
+function stopPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}}\r
+function getEvent(evt){return evt?evt:event;}\r
+function getTarget(evt){return evt.target?evt.target:evt.srcElement;}\r
+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;}}}\r
+function cancelKeyEvent(evt){evt.returnValue=false;stopPropagation(evt);}\r
+function evalCommandLine(){var expr=$("command").value;evalCommand(expr);$("command").value="";}\r
+function evalLastCommand(){if(lastCommand!=null){evalCommand(lastCommand);}}\r
+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));}}\r
+if(expr!=commandHistory[commandHistory.length-1]){commandHistory.push(expr);if(appender){appender.storeCommandHistory(commandHistory);}}\r
+currentCommandIndex=(expr==commandHistory[currentCommandIndex])?currentCommandIndex+1:commandHistory.length;lastCommand=expr;}\r
+//]]>\r
+</script>\r
+<style type="text/css">\r
+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}\r
+</style>\r
+</head>\r
+<body id="body">\r
+<div id="switchesContainer">\r
+<div id="switches">\r
+<div id="levels" class="toolbar">\r
+Filters:\r
+<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>\r
+<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>\r
+<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>\r
+<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>\r
+<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>\r
+<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>\r
+<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>\r
+</div>\r
+<div id="search" class="toolbar">\r
+<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />\r
+<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />\r
+<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>\r
+<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>\r
+<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>\r
+<div id="searchNav">\r
+<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />\r
+<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />\r
+<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>\r
+<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>\r
+</div>\r
+</div>\r
+<div id="options" class="toolbar">\r
+Options:\r
+<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>\r
+<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>\r
+<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>\r
+<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>\r
+<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages" />\r
+<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />\r
+<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />\r
+</div>\r
+</div>\r
+</div>\r
+<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>\r
+<div id="commandLine" class="toolbar">\r
+<div id="commandLineContainer">\r
+<input type="text" id="command" title="Enter a JavaScript command here and hit return or press 'Evaluate'" />\r
+<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />\r
+</div>\r
+</div>\r
+</body>\r
+</html>\r
--- /dev/null
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript</title>\r
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\r
+ <!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->\r
+ <meta http-equiv="X-UA-Compatible" content="IE=7" />\r
+ <script type="text/javascript">var isIe = false, isIePre7 = false;</script>\r
+ <!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->\r
+ <!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->\r
+ <script type="text/javascript">\r
+ //<![CDATA[\r
+ var loggingEnabled = true;\r
+ var logQueuedEventsTimer = null;\r
+ var logEntries = [];\r
+ var logEntriesAndSeparators = [];\r
+ var logItems = [];\r
+ var renderDelay = 100;\r
+ var unrenderedLogItemsExist = false;\r
+ var rootGroup, currentGroup = null;\r
+ var loaded = false;\r
+ var currentLogItem = null;\r
+ var logMainContainer;\r
+\r
+ function copyProperties(obj, props) {\r
+ for (var i in props) {\r
+ obj[i] = props[i];\r
+ }\r
+ }\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function LogItem() {\r
+ }\r
+\r
+ LogItem.prototype = {\r
+ mainContainer: null,\r
+ wrappedContainer: null,\r
+ unwrappedContainer: null,\r
+ group: null,\r
+\r
+ appendToLog: function() {\r
+ for (var i = 0, len = this.elementContainers.length; i < len; i++) {\r
+ this.elementContainers[i].appendToLog();\r
+ }\r
+ this.group.update();\r
+ },\r
+\r
+ doRemove: function(doUpdate, removeFromGroup) {\r
+ if (this.rendered) {\r
+ for (var i = 0, len = this.elementContainers.length; i < len; i++) {\r
+ this.elementContainers[i].remove();\r
+ }\r
+ this.unwrappedElementContainer = null;\r
+ this.wrappedElementContainer = null;\r
+ this.mainElementContainer = null;\r
+ }\r
+ if (this.group && removeFromGroup) {\r
+ this.group.removeChild(this, doUpdate);\r
+ }\r
+ if (this === currentLogItem) {\r
+ currentLogItem = null;\r
+ }\r
+ },\r
+\r
+ remove: function(doUpdate, removeFromGroup) {\r
+ this.doRemove(doUpdate, removeFromGroup);\r
+ },\r
+\r
+ render: function() {},\r
+\r
+ accept: function(visitor) {\r
+ visitor.visit(this);\r
+ },\r
+\r
+ getUnwrappedDomContainer: function() {\r
+ return this.group.unwrappedElementContainer.contentDiv;\r
+ },\r
+\r
+ getWrappedDomContainer: function() {\r
+ return this.group.wrappedElementContainer.contentDiv;\r
+ },\r
+\r
+ getMainDomContainer: function() {\r
+ return this.group.mainElementContainer.contentDiv;\r
+ }\r
+ };\r
+\r
+ LogItem.serializedItemKeys = {LOG_ENTRY: 0, GROUP_START: 1, GROUP_END: 2};\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function LogItemContainerElement() {\r
+ }\r
+\r
+ LogItemContainerElement.prototype = {\r
+ appendToLog: function() {\r
+ var insertBeforeFirst = (newestAtTop && this.containerDomNode.hasChildNodes());\r
+ if (insertBeforeFirst) {\r
+ this.containerDomNode.insertBefore(this.mainDiv, this.containerDomNode.firstChild);\r
+ } else {\r
+ this.containerDomNode.appendChild(this.mainDiv);\r
+ }\r
+ }\r
+ };\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function SeparatorElementContainer(containerDomNode) {\r
+ this.containerDomNode = containerDomNode;\r
+ this.mainDiv = document.createElement("div");\r
+ this.mainDiv.className = "separator";\r
+ this.mainDiv.innerHTML = " ";\r
+ }\r
+\r
+ SeparatorElementContainer.prototype = new LogItemContainerElement();\r
+\r
+ SeparatorElementContainer.prototype.remove = function() {\r
+ this.mainDiv.parentNode.removeChild(this.mainDiv);\r
+ this.mainDiv = null;\r
+ };\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function Separator() {\r
+ this.rendered = false;\r
+ }\r
+\r
+ Separator.prototype = new LogItem();\r
+\r
+ copyProperties(Separator.prototype, {\r
+ render: function() {\r
+ var containerDomNode = this.group.contentDiv;\r
+ if (isIe) {\r
+ this.unwrappedElementContainer = new SeparatorElementContainer(this.getUnwrappedDomContainer());\r
+ this.wrappedElementContainer = new SeparatorElementContainer(this.getWrappedDomContainer());\r
+ this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];\r
+ } else {\r
+ this.mainElementContainer = new SeparatorElementContainer(this.getMainDomContainer());\r
+ this.elementContainers = [this.mainElementContainer];\r
+ }\r
+ this.content = this.formattedMessage;\r
+ this.rendered = true;\r
+ }\r
+ });\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function GroupElementContainer(group, containerDomNode, isRoot, isWrapped) {\r
+ this.group = group;\r
+ this.containerDomNode = containerDomNode;\r
+ this.isRoot = isRoot;\r
+ this.isWrapped = isWrapped;\r
+ this.expandable = false;\r
+\r
+ if (this.isRoot) {\r
+ if (isIe) {\r
+ this.contentDiv = logMainContainer.appendChild(document.createElement("div"));\r
+ this.contentDiv.id = this.isWrapped ? "log_wrapped" : "log_unwrapped";\r
+ } else {\r
+ this.contentDiv = logMainContainer;\r
+ }\r
+ } else {\r
+ var groupElementContainer = this;\r
+ \r
+ this.mainDiv = document.createElement("div");\r
+ this.mainDiv.className = "group";\r
+\r
+ this.headingDiv = this.mainDiv.appendChild(document.createElement("div"));\r
+ this.headingDiv.className = "groupheading";\r
+\r
+ this.expander = this.headingDiv.appendChild(document.createElement("span"));\r
+ this.expander.className = "expander unselectable greyedout";\r
+ this.expander.unselectable = true;\r
+ var expanderText = this.group.expanded ? "-" : "+";\r
+ this.expanderTextNode = this.expander.appendChild(document.createTextNode(expanderText));\r
+ \r
+ this.headingDiv.appendChild(document.createTextNode(" " + this.group.name));\r
+\r
+ this.contentDiv = this.mainDiv.appendChild(document.createElement("div"));\r
+ var contentCssClass = this.group.expanded ? "expanded" : "collapsed";\r
+ this.contentDiv.className = "groupcontent " + contentCssClass;\r
+\r
+ this.expander.onclick = function() {\r
+ if (groupElementContainer.group.expandable) {\r
+ groupElementContainer.group.toggleExpanded();\r
+ }\r
+ };\r
+ }\r
+ }\r
+\r
+ GroupElementContainer.prototype = new LogItemContainerElement();\r
+\r
+ copyProperties(GroupElementContainer.prototype, {\r
+ toggleExpanded: function() {\r
+ if (!this.isRoot) {\r
+ var oldCssClass, newCssClass, expanderText;\r
+ if (this.group.expanded) {\r
+ newCssClass = "expanded";\r
+ oldCssClass = "collapsed";\r
+ expanderText = "-";\r
+ } else {\r
+ newCssClass = "collapsed";\r
+ oldCssClass = "expanded";\r
+ expanderText = "+";\r
+ }\r
+ replaceClass(this.contentDiv, newCssClass, oldCssClass);\r
+ this.expanderTextNode.nodeValue = expanderText;\r
+ }\r
+ },\r
+\r
+ remove: function() {\r
+ if (!this.isRoot) {\r
+ this.headingDiv = null;\r
+ this.expander.onclick = null;\r
+ this.expander = null;\r
+ this.expanderTextNode = null;\r
+ this.contentDiv = null;\r
+ this.containerDomNode = null;\r
+ this.mainDiv.parentNode.removeChild(this.mainDiv);\r
+ this.mainDiv = null;\r
+ }\r
+ },\r
+\r
+ reverseChildren: function() {\r
+ // Invert the order of the log entries\r
+ var node = null;\r
+\r
+ // Remove all the log container nodes\r
+ var childDomNodes = [];\r
+ while ((node = this.contentDiv.firstChild)) {\r
+ this.contentDiv.removeChild(node);\r
+ childDomNodes.push(node);\r
+ }\r
+\r
+ // Put them all back in reverse order\r
+ while ((node = childDomNodes.pop())) {\r
+ this.contentDiv.appendChild(node);\r
+ }\r
+ },\r
+\r
+ update: function() {\r
+ if (!this.isRoot) {\r
+ if (this.group.expandable) {\r
+ removeClass(this.expander, "greyedout");\r
+ } else {\r
+ addClass(this.expander, "greyedout");\r
+ }\r
+ }\r
+ },\r
+\r
+ clear: function() {\r
+ if (this.isRoot) {\r
+ this.contentDiv.innerHTML = "";\r
+ }\r
+ }\r
+ });\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function Group(name, isRoot, initiallyExpanded) {\r
+ this.name = name;\r
+ this.group = null;\r
+ this.isRoot = isRoot;\r
+ this.initiallyExpanded = initiallyExpanded;\r
+ this.elementContainers = [];\r
+ this.children = [];\r
+ this.expanded = initiallyExpanded;\r
+ this.rendered = false;\r
+ this.expandable = false;\r
+ }\r
+\r
+ Group.prototype = new LogItem();\r
+\r
+ copyProperties(Group.prototype, {\r
+ addChild: function(logItem) {\r
+ this.children.push(logItem);\r
+ logItem.group = this;\r
+ },\r
+\r
+ render: function() {\r
+ if (isIe) {\r
+ var unwrappedDomContainer, wrappedDomContainer;\r
+ if (this.isRoot) {\r
+ unwrappedDomContainer = logMainContainer;\r
+ wrappedDomContainer = logMainContainer;\r
+ } else {\r
+ unwrappedDomContainer = this.getUnwrappedDomContainer();\r
+ wrappedDomContainer = this.getWrappedDomContainer();\r
+ }\r
+ this.unwrappedElementContainer = new GroupElementContainer(this, unwrappedDomContainer, this.isRoot, false);\r
+ this.wrappedElementContainer = new GroupElementContainer(this, wrappedDomContainer, this.isRoot, true);\r
+ this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];\r
+ } else {\r
+ var mainDomContainer = this.isRoot ? logMainContainer : this.getMainDomContainer();\r
+ this.mainElementContainer = new GroupElementContainer(this, mainDomContainer, this.isRoot, false);\r
+ this.elementContainers = [this.mainElementContainer];\r
+ }\r
+ this.rendered = true;\r
+ },\r
+\r
+ toggleExpanded: function() {\r
+ this.expanded = !this.expanded;\r
+ for (var i = 0, len = this.elementContainers.length; i < len; i++) {\r
+ this.elementContainers[i].toggleExpanded();\r
+ }\r
+ },\r
+\r
+ expand: function() {\r
+ if (!this.expanded) {\r
+ this.toggleExpanded();\r
+ }\r
+ },\r
+\r
+ accept: function(visitor) {\r
+ visitor.visitGroup(this);\r
+ },\r
+\r
+ reverseChildren: function() {\r
+ if (this.rendered) {\r
+ for (var i = 0, len = this.elementContainers.length; i < len; i++) {\r
+ this.elementContainers[i].reverseChildren();\r
+ }\r
+ }\r
+ },\r
+\r
+ update: function() {\r
+ var previouslyExpandable = this.expandable;\r
+ this.expandable = (this.children.length !== 0);\r
+ if (this.expandable !== previouslyExpandable) {\r
+ for (var i = 0, len = this.elementContainers.length; i < len; i++) {\r
+ this.elementContainers[i].update();\r
+ }\r
+ }\r
+ },\r
+\r
+ flatten: function() {\r
+ var visitor = new GroupFlattener();\r
+ this.accept(visitor);\r
+ return visitor.logEntriesAndSeparators;\r
+ },\r
+\r
+ removeChild: function(child, doUpdate) {\r
+ array_remove(this.children, child);\r
+ child.group = null;\r
+ if (doUpdate) {\r
+ this.update();\r
+ }\r
+ },\r
+\r
+ remove: function(doUpdate, removeFromGroup) {\r
+ for (var i = 0, len = this.children.length; i < len; i++) {\r
+ this.children[i].remove(false, false);\r
+ }\r
+ this.children = [];\r
+ this.update();\r
+ if (this === currentGroup) {\r
+ currentGroup = this.group;\r
+ }\r
+ this.doRemove(doUpdate, removeFromGroup);\r
+ },\r
+\r
+ serialize: function(items) {\r
+ items.push([LogItem.serializedItemKeys.GROUP_START, this.name]);\r
+ for (var i = 0, len = this.children.length; i < len; i++) {\r
+ this.children[i].serialize(items);\r
+ }\r
+ if (this !== currentGroup) {\r
+ items.push([LogItem.serializedItemKeys.GROUP_END]);\r
+ }\r
+ },\r
+\r
+ clear: function() {\r
+ for (var i = 0, len = this.elementContainers.length; i < len; i++) {\r
+ this.elementContainers[i].clear();\r
+ }\r
+ }\r
+ });\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function LogEntryElementContainer() {\r
+ }\r
+\r
+ LogEntryElementContainer.prototype = new LogItemContainerElement();\r
+\r
+ copyProperties(LogEntryElementContainer.prototype, {\r
+ remove: function() {\r
+ this.doRemove();\r
+ },\r
+\r
+ doRemove: function() {\r
+ this.mainDiv.parentNode.removeChild(this.mainDiv);\r
+ this.mainDiv = null;\r
+ this.contentElement = null;\r
+ this.containerDomNode = null;\r
+ },\r
+\r
+ setContent: function(content, wrappedContent) {\r
+ if (content === this.formattedMessage) {\r
+ this.contentElement.innerHTML = "";\r
+ this.contentElement.appendChild(document.createTextNode(this.formattedMessage));\r
+ } else {\r
+ this.contentElement.innerHTML = content;\r
+ }\r
+ },\r
+\r
+ setSearchMatch: function(isMatch) {\r
+ var oldCssClass = isMatch ? "searchnonmatch" : "searchmatch";\r
+ var newCssClass = isMatch ? "searchmatch" : "searchnonmatch";\r
+ replaceClass(this.mainDiv, newCssClass, oldCssClass);\r
+ },\r
+\r
+ clearSearch: function() {\r
+ removeClass(this.mainDiv, "searchmatch");\r
+ removeClass(this.mainDiv, "searchnonmatch");\r
+ }\r
+ });\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function LogEntryWrappedElementContainer(logEntry, containerDomNode) {\r
+ this.logEntry = logEntry;\r
+ this.containerDomNode = containerDomNode;\r
+ this.mainDiv = document.createElement("div");\r
+ this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));\r
+ this.mainDiv.className = "logentry wrapped " + this.logEntry.level;\r
+ this.contentElement = this.mainDiv;\r
+ }\r
+\r
+ LogEntryWrappedElementContainer.prototype = new LogEntryElementContainer();\r
+\r
+ LogEntryWrappedElementContainer.prototype.setContent = function(content, wrappedContent) {\r
+ if (content === this.formattedMessage) {\r
+ this.contentElement.innerHTML = "";\r
+ this.contentElement.appendChild(document.createTextNode(this.formattedMessage));\r
+ } else {\r
+ this.contentElement.innerHTML = wrappedContent;\r
+ }\r
+ };\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function LogEntryUnwrappedElementContainer(logEntry, containerDomNode) {\r
+ this.logEntry = logEntry;\r
+ this.containerDomNode = containerDomNode;\r
+ this.mainDiv = document.createElement("div");\r
+ this.mainDiv.className = "logentry unwrapped " + this.logEntry.level;\r
+ this.pre = this.mainDiv.appendChild(document.createElement("pre"));\r
+ this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));\r
+ this.pre.className = "unwrapped";\r
+ this.contentElement = this.pre;\r
+ }\r
+\r
+ LogEntryUnwrappedElementContainer.prototype = new LogEntryElementContainer();\r
+\r
+ LogEntryUnwrappedElementContainer.prototype.remove = function() {\r
+ this.doRemove();\r
+ this.pre = null;\r
+ };\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function LogEntryMainElementContainer(logEntry, containerDomNode) {\r
+ this.logEntry = logEntry;\r
+ this.containerDomNode = containerDomNode;\r
+ this.mainDiv = document.createElement("div");\r
+ this.mainDiv.className = "logentry nonielogentry " + this.logEntry.level;\r
+ this.contentElement = this.mainDiv.appendChild(document.createElement("span"));\r
+ this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));\r
+ }\r
+\r
+ LogEntryMainElementContainer.prototype = new LogEntryElementContainer();\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function LogEntry(level, formattedMessage) {\r
+ this.level = level;\r
+ this.formattedMessage = formattedMessage;\r
+ this.rendered = false;\r
+ }\r
+\r
+ LogEntry.prototype = new LogItem();\r
+\r
+ copyProperties(LogEntry.prototype, {\r
+ render: function() {\r
+ var logEntry = this;\r
+ var containerDomNode = this.group.contentDiv;\r
+\r
+ // Support for the CSS attribute white-space in IE for Windows is\r
+ // non-existent pre version 6 and slightly odd in 6, so instead\r
+ // use two different HTML elements\r
+ if (isIe) {\r
+ this.formattedMessage = this.formattedMessage.replace(/\r\n/g, "\r"); // Workaround for IE's treatment of white space\r
+ this.unwrappedElementContainer = new LogEntryUnwrappedElementContainer(this, this.getUnwrappedDomContainer());\r
+ this.wrappedElementContainer = new LogEntryWrappedElementContainer(this, this.getWrappedDomContainer());\r
+ this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];\r
+ } else {\r
+ this.mainElementContainer = new LogEntryMainElementContainer(this, this.getMainDomContainer());\r
+ this.elementContainers = [this.mainElementContainer];\r
+ }\r
+ this.content = this.formattedMessage;\r
+ this.rendered = true;\r
+ },\r
+\r
+ setContent: function(content, wrappedContent) {\r
+ if (content != this.content) {\r
+ if (isIe && (content !== this.formattedMessage)) {\r
+ content = content.replace(/\r\n/g, "\r"); // Workaround for IE's treatment of white space\r
+ }\r
+ for (var i = 0, len = this.elementContainers.length; i < len; i++) {\r
+ this.elementContainers[i].setContent(content, wrappedContent);\r
+ }\r
+ this.content = content;\r
+ }\r
+ },\r
+\r
+ getSearchMatches: function() {\r
+ var matches = [];\r
+ var i, len;\r
+ if (isIe) {\r
+ var unwrappedEls = getElementsByClass(this.unwrappedElementContainer.mainDiv, "searchterm", "span");\r
+ var wrappedEls = getElementsByClass(this.wrappedElementContainer.mainDiv, "searchterm", "span");\r
+ for (i = 0, len = unwrappedEls.length; i < len; i++) {\r
+ matches[i] = new Match(this.level, null, unwrappedEls[i], wrappedEls[i]);\r
+ }\r
+ } else {\r
+ var els = getElementsByClass(this.mainElementContainer.mainDiv, "searchterm", "span");\r
+ for (i = 0, len = els.length; i < len; i++) {\r
+ matches[i] = new Match(this.level, els[i]);\r
+ }\r
+ }\r
+ return matches;\r
+ },\r
+\r
+ setSearchMatch: function(isMatch) {\r
+ for (var i = 0, len = this.elementContainers.length; i < len; i++) {\r
+ this.elementContainers[i].setSearchMatch(isMatch);\r
+ }\r
+ },\r
+\r
+ clearSearch: function() {\r
+ for (var i = 0, len = this.elementContainers.length; i < len; i++) {\r
+ this.elementContainers[i].clearSearch();\r
+ }\r
+ },\r
+\r
+ accept: function(visitor) {\r
+ visitor.visitLogEntry(this);\r
+ },\r
+\r
+ serialize: function(items) {\r
+ items.push([LogItem.serializedItemKeys.LOG_ENTRY, this.level, this.formattedMessage]);\r
+ }\r
+ });\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function LogItemVisitor() {\r
+ }\r
+\r
+ LogItemVisitor.prototype = {\r
+ visit: function(logItem) {\r
+ },\r
+\r
+ visitParent: function(logItem) {\r
+ if (logItem.group) {\r
+ logItem.group.accept(this);\r
+ }\r
+ },\r
+\r
+ visitChildren: function(logItem) {\r
+ for (var i = 0, len = logItem.children.length; i < len; i++) {\r
+ logItem.children[i].accept(this);\r
+ }\r
+ },\r
+\r
+ visitLogEntry: function(logEntry) {\r
+ this.visit(logEntry);\r
+ },\r
+\r
+ visitSeparator: function(separator) {\r
+ this.visit(separator);\r
+ },\r
+\r
+ visitGroup: function(group) {\r
+ this.visit(group);\r
+ }\r
+ };\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function GroupFlattener() {\r
+ this.logEntriesAndSeparators = [];\r
+ }\r
+\r
+ GroupFlattener.prototype = new LogItemVisitor();\r
+\r
+ GroupFlattener.prototype.visitGroup = function(group) {\r
+ this.visitChildren(group);\r
+ };\r
+\r
+ GroupFlattener.prototype.visitLogEntry = function(logEntry) {\r
+ this.logEntriesAndSeparators.push(logEntry);\r
+ };\r
+\r
+ GroupFlattener.prototype.visitSeparator = function(separator) {\r
+ this.logEntriesAndSeparators.push(separator);\r
+ };\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ window.onload = function() {\r
+ // Sort out document.domain\r
+ if (location.search) {\r
+ var queryBits = unescape(location.search).substr(1).split("&"), nameValueBits;\r
+ for (var i = 0, len = queryBits.length; i < len; i++) {\r
+ nameValueBits = queryBits[i].split("=");\r
+ if (nameValueBits[0] == "log4javascript_domain") {\r
+ document.domain = nameValueBits[1];\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ // Create DOM objects\r
+ logMainContainer = $("log");\r
+ if (isIePre7) {\r
+ addClass(logMainContainer, "oldIe");\r
+ }\r
+\r
+ rootGroup = new Group("root", true);\r
+ rootGroup.render();\r
+ currentGroup = rootGroup;\r
+ \r
+ setCommandInputWidth();\r
+ setLogContainerHeight();\r
+ toggleLoggingEnabled();\r
+ toggleSearchEnabled();\r
+ toggleSearchFilter();\r
+ toggleSearchHighlight();\r
+ applyFilters();\r
+ checkAllLevels();\r
+ toggleWrap();\r
+ toggleNewestAtTop();\r
+ toggleScrollToLatest();\r
+ renderQueuedLogItems();\r
+ loaded = true;\r
+ $("command").value = "";\r
+ $("command").autocomplete = "off";\r
+ $("command").onkeydown = function(evt) {\r
+ evt = getEvent(evt);\r
+ if (evt.keyCode == 10 || evt.keyCode == 13) { // Return/Enter\r
+ evalCommandLine();\r
+ stopPropagation(evt);\r
+ } else if (evt.keyCode == 27) { // Escape\r
+ this.value = "";\r
+ this.focus();\r
+ } else if (evt.keyCode == 38 && commandHistory.length > 0) { // Up\r
+ currentCommandIndex = Math.max(0, currentCommandIndex - 1);\r
+ this.value = commandHistory[currentCommandIndex];\r
+ moveCaretToEnd(this);\r
+ } else if (evt.keyCode == 40 && commandHistory.length > 0) { // Down\r
+ currentCommandIndex = Math.min(commandHistory.length - 1, currentCommandIndex + 1);\r
+ this.value = commandHistory[currentCommandIndex];\r
+ moveCaretToEnd(this);\r
+ }\r
+ };\r
+\r
+ // Prevent the keypress moving the caret in Firefox\r
+ $("command").onkeypress = function(evt) {\r
+ evt = getEvent(evt);\r
+ if (evt.keyCode == 38 && commandHistory.length > 0 && evt.preventDefault) { // Up\r
+ evt.preventDefault();\r
+ }\r
+ };\r
+\r
+ // Prevent the keyup event blurring the input in Opera\r
+ $("command").onkeyup = function(evt) {\r
+ evt = getEvent(evt);\r
+ if (evt.keyCode == 27 && evt.preventDefault) { // Up\r
+ evt.preventDefault();\r
+ this.focus();\r
+ }\r
+ };\r
+\r
+ // Add document keyboard shortcuts\r
+ document.onkeydown = function keyEventHandler(evt) {\r
+ evt = getEvent(evt);\r
+ switch (evt.keyCode) {\r
+ case 69: // Ctrl + shift + E: re-execute last command\r
+ if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {\r
+ evalLastCommand();\r
+ cancelKeyEvent(evt);\r
+ return false;\r
+ }\r
+ break;\r
+ case 75: // Ctrl + shift + K: focus search\r
+ if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {\r
+ focusSearch();\r
+ cancelKeyEvent(evt);\r
+ return false;\r
+ }\r
+ break;\r
+ case 40: // Ctrl + shift + down arrow: focus command line\r
+ case 76: // Ctrl + shift + L: focus command line\r
+ if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {\r
+ focusCommandLine();\r
+ cancelKeyEvent(evt);\r
+ return false;\r
+ }\r
+ break;\r
+ }\r
+ };\r
+\r
+ // Workaround to make sure log div starts at the correct size\r
+ setTimeout(setLogContainerHeight, 20);\r
+\r
+ setShowCommandLine(showCommandLine);\r
+ doSearch();\r
+ };\r
+\r
+ window.onunload = function() {\r
+ if (mainWindowExists()) {\r
+ appender.unload();\r
+ }\r
+ appender = null;\r
+ };\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function toggleLoggingEnabled() {\r
+ setLoggingEnabled($("enableLogging").checked);\r
+ }\r
+\r
+ function setLoggingEnabled(enable) {\r
+ loggingEnabled = enable;\r
+ }\r
+\r
+ var appender = null;\r
+\r
+ function setAppender(appenderParam) {\r
+ appender = appenderParam;\r
+ }\r
+\r
+ function setShowCloseButton(showCloseButton) {\r
+ $("closeButton").style.display = showCloseButton ? "inline" : "none";\r
+ }\r
+\r
+ function setShowHideButton(showHideButton) {\r
+ $("hideButton").style.display = showHideButton ? "inline" : "none";\r
+ }\r
+\r
+ var newestAtTop = false;\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function LogItemContentReverser() {\r
+ }\r
+ \r
+ LogItemContentReverser.prototype = new LogItemVisitor();\r
+ \r
+ LogItemContentReverser.prototype.visitGroup = function(group) {\r
+ group.reverseChildren();\r
+ this.visitChildren(group);\r
+ };\r
+\r
+ /*----------------------------------------------------------------*/\r
+\r
+ function setNewestAtTop(isNewestAtTop) {\r
+ var oldNewestAtTop = newestAtTop;\r
+ var i, iLen, j, jLen;\r
+ newestAtTop = Boolean(isNewestAtTop);\r
+ if (oldNewestAtTop != newestAtTop) {\r
+ var visitor = new LogItemContentReverser();\r
+ rootGroup.accept(visitor);\r
+\r
+ // Reassemble the matches array\r
+ if (currentSearch) {\r
+ var currentMatch = currentSearch.matches[currentMatchIndex];\r
+ var matchIndex = 0;\r
+ var matches = [];\r
+ var actOnLogEntry = function(logEntry) {\r
+ var logEntryMatches = logEntry.getSearchMatches();\r
+ for (j = 0, jLen = logEntryMatches.length; j < jLen; j++) {\r
+ matches[matchIndex] = logEntryMatches[j];\r
+ if (currentMatch && logEntryMatches[j].equals(currentMatch)) {\r
+ currentMatchIndex = matchIndex;\r
+ }\r
+ matchIndex++;\r
+ }\r
+ };\r
+ if (newestAtTop) {\r
+ for (i = logEntries.length - 1; i >= 0; i--) {\r
+ actOnLogEntry(logEntries[i]);\r
+ }\r
+ } else {\r
+ for (i = 0, iLen = logEntries.length; i < iLen; i++) {\r
+ actOnLogEntry(logEntries[i]);\r
+ }\r
+ }\r
+ currentSearch.matches = matches;\r
+ if (currentMatch) {\r
+ currentMatch.setCurrent();\r
+ }\r
+ } else if (scrollToLatest) {\r
+ doScrollToLatest();\r
+ }\r
+ }\r
+ $("newestAtTop").checked = isNewestAtTop;\r
+ }\r
+\r
+ function toggleNewestAtTop() {\r
+ var isNewestAtTop = $("newestAtTop").checked;\r
+ setNewestAtTop(isNewestAtTop);\r
+ }\r
+\r
+ var scrollToLatest = true;\r
+\r
+ function setScrollToLatest(isScrollToLatest) {\r
+ scrollToLatest = isScrollToLatest;\r
+ if (scrollToLatest) {\r
+ doScrollToLatest();\r
+ }\r
+ $("scrollToLatest").checked = isScrollToLatest;\r
+ }\r
+\r
+ function toggleScrollToLatest() {\r
+ var isScrollToLatest = $("scrollToLatest").checked;\r
+ setScrollToLatest(isScrollToLatest);\r
+ }\r
+\r
+ function doScrollToLatest() {\r
+ var l = logMainContainer;\r
+ if (typeof l.scrollTop != "undefined") {\r
+ if (newestAtTop) {\r
+ l.scrollTop = 0;\r
+ } else {\r
+ var latestLogEntry = l.lastChild;\r
+ if (latestLogEntry) {\r
+ l.scrollTop = l.scrollHeight;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ var closeIfOpenerCloses = true;\r
+\r
+ function setCloseIfOpenerCloses(isCloseIfOpenerCloses) {\r
+ closeIfOpenerCloses = isCloseIfOpenerCloses;\r
+ }\r
+\r
+ var maxMessages = null;\r
+\r
+ function setMaxMessages(max) {\r
+ maxMessages = max;\r
+ pruneLogEntries();\r
+ }\r
+\r
+ var showCommandLine = false;\r
+\r
+ function setShowCommandLine(isShowCommandLine) {\r
+ showCommandLine = isShowCommandLine;\r
+ if (loaded) {\r
+ $("commandLine").style.display = showCommandLine ? "block" : "none";\r
+ setCommandInputWidth();\r
+ setLogContainerHeight();\r
+ }\r
+ }\r
+\r
+ function focusCommandLine() {\r
+ if (loaded) {\r
+ $("command").focus();\r
+ }\r
+ }\r
+\r
+ function focusSearch() {\r
+ if (loaded) {\r
+ $("searchBox").focus();\r
+ }\r
+ }\r
+\r
+ function getLogItems() {\r
+ var items = [];\r
+ for (var i = 0, len = logItems.length; i < len; i++) {\r
+ logItems[i].serialize(items);\r
+ }\r
+ return items;\r
+ }\r
+\r
+ function setLogItems(items) {\r
+ var loggingReallyEnabled = loggingEnabled;\r
+ // Temporarily turn logging on\r
+ loggingEnabled = true;\r
+ for (var i = 0, len = items.length; i < len; i++) {\r
+ switch (items[i][0]) {\r
+ case LogItem.serializedItemKeys.LOG_ENTRY:\r
+ log(items[i][1], items[i][2]);\r
+ break;\r
+ case LogItem.serializedItemKeys.GROUP_START:\r
+ group(items[i][1]);\r
+ break;\r
+ case LogItem.serializedItemKeys.GROUP_END:\r
+ groupEnd();\r
+ break;\r
+ }\r
+ }\r
+ loggingEnabled = loggingReallyEnabled;\r
+ }\r
+\r
+ function log(logLevel, formattedMessage) {\r
+ if (loggingEnabled) {\r
+ var logEntry = new LogEntry(logLevel, formattedMessage);\r
+ logEntries.push(logEntry);\r
+ logEntriesAndSeparators.push(logEntry);\r
+ logItems.push(logEntry);\r
+ currentGroup.addChild(logEntry);\r
+ if (loaded) {\r
+ if (logQueuedEventsTimer !== null) {\r
+ clearTimeout(logQueuedEventsTimer);\r
+ }\r
+ logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);\r
+ unrenderedLogItemsExist = true;\r
+ }\r
+ }\r
+ }\r
+\r
+ function renderQueuedLogItems() {\r
+ logQueuedEventsTimer = null;\r
+ var pruned = pruneLogEntries();\r
+\r
+ // Render any unrendered log entries and apply the current search to them\r
+ var initiallyHasMatches = currentSearch ? currentSearch.hasMatches() : false;\r
+ for (var i = 0, len = logItems.length; i < len; i++) {\r
+ if (!logItems[i].rendered) {\r
+ logItems[i].render();\r
+ logItems[i].appendToLog();\r
+ if (currentSearch && (logItems[i] instanceof LogEntry)) {\r
+ currentSearch.applyTo(logItems[i]);\r
+ }\r
+ }\r
+ }\r
+ if (currentSearch) {\r
+ if (pruned) {\r
+ if (currentSearch.hasVisibleMatches()) {\r
+ if (currentMatchIndex === null) {\r
+ setCurrentMatchIndex(0);\r
+ }\r
+ displayMatches();\r
+ } else {\r
+ displayNoMatches();\r
+ }\r
+ } else if (!initiallyHasMatches && currentSearch.hasVisibleMatches()) {\r
+ setCurrentMatchIndex(0);\r
+ displayMatches();\r
+ }\r
+ }\r
+ if (scrollToLatest) {\r
+ doScrollToLatest();\r
+ }\r
+ unrenderedLogItemsExist = false;\r
+ }\r
+\r
+ function pruneLogEntries() {\r
+ if ((maxMessages !== null) && (logEntriesAndSeparators.length > maxMessages)) {\r
+ var numberToDelete = logEntriesAndSeparators.length - maxMessages;\r
+ var prunedLogEntries = logEntriesAndSeparators.slice(0, numberToDelete);\r
+ if (currentSearch) {\r
+ currentSearch.removeMatches(prunedLogEntries);\r
+ }\r
+ var group;\r
+ for (var i = 0; i < numberToDelete; i++) {\r
+ group = logEntriesAndSeparators[i].group;\r
+ array_remove(logItems, logEntriesAndSeparators[i]);\r
+ array_remove(logEntries, logEntriesAndSeparators[i]);\r
+ logEntriesAndSeparators[i].remove(true, true);\r
+ if (group.children.length === 0 && group !== currentGroup && group !== rootGroup) {\r
+ array_remove(logItems, group);\r
+ group.remove(true, true);\r
+ }\r
+ }\r
+ logEntriesAndSeparators = array_removeFromStart(logEntriesAndSeparators, numberToDelete);\r
+ return true;\r
+ }\r
+ return false;\r
+ }\r
+\r
+ function group(name, startExpanded) {\r
+ if (loggingEnabled) {\r
+ initiallyExpanded = (typeof startExpanded === "undefined") ? true : Boolean(startExpanded);\r
+ var newGroup = new Group(name, false, initiallyExpanded);\r
+ currentGroup.addChild(newGroup);\r
+ currentGroup = newGroup;\r
+ logItems.push(newGroup);\r
+ if (loaded) {\r
+ if (logQueuedEventsTimer !== null) {\r
+ clearTimeout(logQueuedEventsTimer);\r
+ }\r
+ logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);\r
+ unrenderedLogItemsExist = true;\r
+ }\r
+ }\r
+ }\r
+\r
+ function groupEnd() {\r
+ currentGroup = (currentGroup === rootGroup) ? rootGroup : currentGroup.group;\r
+ }\r
+\r
+ function mainPageReloaded() {\r
+ currentGroup = rootGroup;\r
+ var separator = new Separator();\r
+ logEntriesAndSeparators.push(separator);\r
+ logItems.push(separator);\r
+ currentGroup.addChild(separator);\r
+ }\r
+\r
+ function closeWindow() {\r
+ if (appender && mainWindowExists()) {\r
+ appender.close(true);\r
+ } else {\r
+ window.close();\r
+ }\r
+ }\r
+\r
+ function hide() {\r
+ if (appender && mainWindowExists()) {\r
+ appender.hide();\r
+ }\r
+ }\r
+\r
+ var mainWindow = window;\r
+ var windowId = "log4javascriptConsoleWindow_" + new Date().getTime() + "_" + ("" + Math.random()).substr(2);\r
+\r
+ function setMainWindow(win) {\r
+ mainWindow = win;\r
+ mainWindow[windowId] = window;\r
+ // If this is a pop-up, poll the opener to see if it's closed\r
+ if (opener && closeIfOpenerCloses) {\r
+ pollOpener();\r
+ }\r
+ }\r
+\r
+ function pollOpener() {\r
+ if (closeIfOpenerCloses) {\r
+ if (mainWindowExists()) {\r
+ setTimeout(pollOpener, 500);\r
+ } else {\r
+ closeWindow();\r
+ }\r
+ }\r
+ }\r
+\r
+ function mainWindowExists() {\r
+ try {\r
+ return (mainWindow && !mainWindow.closed &&\r
+ mainWindow[windowId] == window);\r
+ } catch (ex) {}\r
+ return false;\r
+ }\r
+\r
+ var logLevels = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"];\r
+\r
+ function getCheckBox(logLevel) {\r
+ return $("switch_" + logLevel);\r
+ }\r
+\r
+ function getIeWrappedLogContainer() {\r
+ return $("log_wrapped");\r
+ }\r
+\r
+ function getIeUnwrappedLogContainer() {\r
+ return $("log_unwrapped");\r
+ }\r
+\r
+ function applyFilters() {\r
+ for (var i = 0; i < logLevels.length; i++) {\r
+ if (getCheckBox(logLevels[i]).checked) {\r
+ addClass(logMainContainer, logLevels[i]);\r
+ } else {\r
+ removeClass(logMainContainer, logLevels[i]);\r
+ }\r
+ }\r
+ updateSearchFromFilters();\r
+ }\r
+\r
+ function toggleAllLevels() {\r
+ var turnOn = $("switch_ALL").checked;\r
+ for (var i = 0; i < logLevels.length; i++) {\r
+ getCheckBox(logLevels[i]).checked = turnOn;\r
+ if (turnOn) {\r
+ addClass(logMainContainer, logLevels[i]);\r
+ } else {\r
+ removeClass(logMainContainer, logLevels[i]);\r
+ }\r
+ }\r
+ }\r
+\r
+ function checkAllLevels() {\r
+ for (var i = 0; i < logLevels.length; i++) {\r
+ if (!getCheckBox(logLevels[i]).checked) {\r
+ getCheckBox("ALL").checked = false;\r
+ return;\r
+ }\r
+ }\r
+ getCheckBox("ALL").checked = true;\r
+ }\r
+\r
+ function clearLog() {\r
+ rootGroup.clear();\r
+ currentGroup = rootGroup;\r
+ logEntries = [];\r
+ logItems = [];\r
+ logEntriesAndSeparators = [];\r
+ doSearch();\r
+ }\r
+\r
+ function toggleWrap() {\r
+ var enable = $("wrap").checked;\r
+ if (enable) {\r
+ addClass(logMainContainer, "wrap");\r
+ } else {\r
+ removeClass(logMainContainer, "wrap");\r
+ }\r
+ refreshCurrentMatch();\r
+ }\r
+\r
+ /* ------------------------------------------------------------------- */\r
+\r
+ // Search\r
+\r
+ var searchTimer = null;\r
+\r
+ function scheduleSearch() {\r
+ try {\r
+ clearTimeout(searchTimer);\r
+ } catch (ex) {\r
+ // Do nothing\r
+ }\r
+ searchTimer = setTimeout(doSearch, 500);\r
+ }\r
+\r
+ function Search(searchTerm, isRegex, searchRegex, isCaseSensitive) {\r
+ this.searchTerm = searchTerm;\r
+ this.isRegex = isRegex;\r
+ this.searchRegex = searchRegex;\r
+ this.isCaseSensitive = isCaseSensitive;\r
+ this.matches = [];\r
+ }\r
+\r
+ Search.prototype = {\r
+ hasMatches: function() {\r
+ return this.matches.length > 0;\r
+ },\r
+\r
+ hasVisibleMatches: function() {\r
+ if (this.hasMatches()) {\r
+ for (var i = 0; i < this.matches.length; i++) {\r
+ if (this.matches[i].isVisible()) {\r
+ return true;\r
+ }\r
+ }\r
+ }\r
+ return false;\r
+ },\r
+\r
+ match: function(logEntry) {\r
+ var entryText = String(logEntry.formattedMessage);\r
+ var matchesSearch = false;\r
+ if (this.isRegex) {\r
+ matchesSearch = this.searchRegex.test(entryText);\r
+ } else if (this.isCaseSensitive) {\r
+ matchesSearch = (entryText.indexOf(this.searchTerm) > -1);\r
+ } else {\r
+ matchesSearch = (entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1);\r
+ }\r
+ return matchesSearch;\r
+ },\r
+\r
+ getNextVisibleMatchIndex: function() {\r
+ for (var i = currentMatchIndex + 1; i < this.matches.length; i++) {\r
+ if (this.matches[i].isVisible()) {\r
+ return i;\r
+ }\r
+ }\r
+ // Start again from the first match\r
+ for (i = 0; i <= currentMatchIndex; i++) {\r
+ if (this.matches[i].isVisible()) {\r
+ return i;\r
+ }\r
+ }\r
+ return -1;\r
+ },\r
+\r
+ getPreviousVisibleMatchIndex: function() {\r
+ for (var i = currentMatchIndex - 1; i >= 0; i--) {\r
+ if (this.matches[i].isVisible()) {\r
+ return i;\r
+ }\r
+ }\r
+ // Start again from the last match\r
+ for (var i = this.matches.length - 1; i >= currentMatchIndex; i--) {\r
+ if (this.matches[i].isVisible()) {\r
+ return i;\r
+ }\r
+ }\r
+ return -1;\r
+ },\r
+\r
+ applyTo: function(logEntry) {\r
+ var doesMatch = this.match(logEntry);\r
+ if (doesMatch) {\r
+ logEntry.group.expand();\r
+ logEntry.setSearchMatch(true);\r
+ var logEntryContent;\r
+ var wrappedLogEntryContent;\r
+ var searchTermReplacementStartTag = "<span class=\"searchterm\">";\r
+ var searchTermReplacementEndTag = "<" + "/span>";\r
+ var preTagName = isIe ? "pre" : "span";\r
+ var preStartTag = "<" + preTagName + " class=\"pre\">";\r
+ var preEndTag = "<" + "/" + preTagName + ">";\r
+ var startIndex = 0;\r
+ var searchIndex, matchedText, textBeforeMatch;\r
+ if (this.isRegex) {\r
+ var flags = this.isCaseSensitive ? "g" : "gi";\r
+ var capturingRegex = new RegExp("(" + this.searchRegex.source + ")", flags);\r
+\r
+ // Replace the search term with temporary tokens for the start and end tags\r
+ var rnd = ("" + Math.random()).substr(2);\r
+ var startToken = "%%s" + rnd + "%%";\r
+ var endToken = "%%e" + rnd + "%%";\r
+ logEntryContent = logEntry.formattedMessage.replace(capturingRegex, startToken + "$1" + endToken);\r
+\r
+ // Escape the HTML to get rid of angle brackets\r
+ logEntryContent = escapeHtml(logEntryContent);\r
+\r
+ // Substitute the proper HTML back in for the search match\r
+ var result;\r
+ var searchString = logEntryContent;\r
+ logEntryContent = "";\r
+ wrappedLogEntryContent = "";\r
+ while ((searchIndex = searchString.indexOf(startToken, startIndex)) > -1) {\r
+ var endTokenIndex = searchString.indexOf(endToken, searchIndex);\r
+ matchedText = searchString.substring(searchIndex + startToken.length, endTokenIndex);\r
+ textBeforeMatch = searchString.substring(startIndex, searchIndex);\r
+ logEntryContent += preStartTag + textBeforeMatch + preEndTag;\r
+ logEntryContent += searchTermReplacementStartTag + preStartTag + matchedText +\r
+ preEndTag + searchTermReplacementEndTag;\r
+ if (isIe) {\r
+ wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +\r
+ matchedText + searchTermReplacementEndTag;\r
+ }\r
+ startIndex = endTokenIndex + endToken.length;\r
+ }\r
+ logEntryContent += preStartTag + searchString.substr(startIndex) + preEndTag;\r
+ if (isIe) {\r
+ wrappedLogEntryContent += searchString.substr(startIndex);\r
+ }\r
+ } else {\r
+ logEntryContent = "";\r
+ wrappedLogEntryContent = "";\r
+ var searchTermReplacementLength = searchTermReplacementStartTag.length +\r
+ this.searchTerm.length + searchTermReplacementEndTag.length;\r
+ var searchTermLength = this.searchTerm.length;\r
+ var searchTermLowerCase = this.searchTerm.toLowerCase();\r
+ var logTextLowerCase = logEntry.formattedMessage.toLowerCase();\r
+ while ((searchIndex = logTextLowerCase.indexOf(searchTermLowerCase, startIndex)) > -1) {\r
+ matchedText = escapeHtml(logEntry.formattedMessage.substr(searchIndex, this.searchTerm.length));\r
+ textBeforeMatch = escapeHtml(logEntry.formattedMessage.substring(startIndex, searchIndex));\r
+ var searchTermReplacement = searchTermReplacementStartTag +\r
+ preStartTag + matchedText + preEndTag + searchTermReplacementEndTag;\r
+ logEntryContent += preStartTag + textBeforeMatch + preEndTag + searchTermReplacement;\r
+ if (isIe) {\r
+ wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +\r
+ matchedText + searchTermReplacementEndTag;\r
+ }\r
+ startIndex = searchIndex + searchTermLength;\r
+ }\r
+ var textAfterLastMatch = escapeHtml(logEntry.formattedMessage.substr(startIndex));\r
+ logEntryContent += preStartTag + textAfterLastMatch + preEndTag;\r
+ if (isIe) {\r
+ wrappedLogEntryContent += textAfterLastMatch;\r
+ }\r
+ }\r
+ logEntry.setContent(logEntryContent, wrappedLogEntryContent);\r
+ var logEntryMatches = logEntry.getSearchMatches();\r
+ this.matches = this.matches.concat(logEntryMatches);\r
+ } else {\r
+ logEntry.setSearchMatch(false);\r
+ logEntry.setContent(logEntry.formattedMessage, logEntry.formattedMessage);\r
+ }\r
+ return doesMatch;\r
+ },\r
+\r
+ removeMatches: function(logEntries) {\r
+ var matchesToRemoveCount = 0;\r
+ var currentMatchRemoved = false;\r
+ var matchesToRemove = [];\r
+ var i, iLen, j, jLen;\r
+\r
+ // Establish the list of matches to be removed\r
+ for (i = 0, iLen = this.matches.length; i < iLen; i++) {\r
+ for (j = 0, jLen = logEntries.length; j < jLen; j++) {\r
+ if (this.matches[i].belongsTo(logEntries[j])) {\r
+ matchesToRemove.push(this.matches[i]);\r
+ if (i === currentMatchIndex) {\r
+ currentMatchRemoved = true;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ // Set the new current match index if the current match has been deleted\r
+ // This will be the first match that appears after the first log entry being\r
+ // deleted, if one exists; otherwise, it's the first match overall\r
+ var newMatch = currentMatchRemoved ? null : this.matches[currentMatchIndex];\r
+ if (currentMatchRemoved) {\r
+ for (i = currentMatchIndex, iLen = this.matches.length; i < iLen; i++) {\r
+ if (this.matches[i].isVisible() && !array_contains(matchesToRemove, this.matches[i])) {\r
+ newMatch = this.matches[i];\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ // Remove the matches\r
+ for (i = 0, iLen = matchesToRemove.length; i < iLen; i++) {\r
+ array_remove(this.matches, matchesToRemove[i]);\r
+ matchesToRemove[i].remove();\r
+ }\r
+\r
+ // Set the new match, if one exists\r
+ if (this.hasVisibleMatches()) {\r
+ if (newMatch === null) {\r
+ setCurrentMatchIndex(0);\r
+ } else {\r
+ // Get the index of the new match\r
+ var newMatchIndex = 0;\r
+ for (i = 0, iLen = this.matches.length; i < iLen; i++) {\r
+ if (newMatch === this.matches[i]) {\r
+ newMatchIndex = i;\r
+ break;\r
+ }\r
+ }\r
+ setCurrentMatchIndex(newMatchIndex);\r
+ }\r
+ } else {\r
+ currentMatchIndex = null;\r
+ displayNoMatches();\r
+ }\r
+ }\r
+ };\r
+\r
+ function getPageOffsetTop(el, container) {\r
+ var currentEl = el;\r
+ var y = 0;\r
+ while (currentEl && currentEl != container) {\r
+ y += currentEl.offsetTop;\r
+ currentEl = currentEl.offsetParent;\r
+ }\r
+ return y;\r
+ }\r
+\r
+ function scrollIntoView(el) {\r
+ var logContainer = logMainContainer;\r
+ // Check if the whole width of the element is visible and centre if not\r
+ if (!$("wrap").checked) {\r
+ var logContainerLeft = logContainer.scrollLeft;\r
+ var logContainerRight = logContainerLeft + logContainer.offsetWidth;\r
+ var elLeft = el.offsetLeft;\r
+ var elRight = elLeft + el.offsetWidth;\r
+ if (elLeft < logContainerLeft || elRight > logContainerRight) {\r
+ logContainer.scrollLeft = elLeft - (logContainer.offsetWidth - el.offsetWidth) / 2;\r
+ }\r
+ }\r
+ // Check if the whole height of the element is visible and centre if not\r
+ var logContainerTop = logContainer.scrollTop;\r
+ var logContainerBottom = logContainerTop + logContainer.offsetHeight;\r
+ var elTop = getPageOffsetTop(el) - getToolBarsHeight();\r
+ var elBottom = elTop + el.offsetHeight;\r
+ if (elTop < logContainerTop || elBottom > logContainerBottom) {\r
+ logContainer.scrollTop = elTop - (logContainer.offsetHeight - el.offsetHeight) / 2;\r
+ }\r
+ }\r
+\r
+ function Match(logEntryLevel, spanInMainDiv, spanInUnwrappedPre, spanInWrappedDiv) {\r
+ this.logEntryLevel = logEntryLevel;\r
+ this.spanInMainDiv = spanInMainDiv;\r
+ if (isIe) {\r
+ this.spanInUnwrappedPre = spanInUnwrappedPre;\r
+ this.spanInWrappedDiv = spanInWrappedDiv;\r
+ }\r
+ this.mainSpan = isIe ? spanInUnwrappedPre : spanInMainDiv;\r
+ }\r
+\r
+ Match.prototype = {\r
+ equals: function(match) {\r
+ return this.mainSpan === match.mainSpan;\r
+ },\r
+\r
+ setCurrent: function() {\r
+ if (isIe) {\r
+ addClass(this.spanInUnwrappedPre, "currentmatch");\r
+ addClass(this.spanInWrappedDiv, "currentmatch");\r
+ // Scroll the visible one into view\r
+ var elementToScroll = $("wrap").checked ? this.spanInWrappedDiv : this.spanInUnwrappedPre;\r
+ scrollIntoView(elementToScroll);\r
+ } else {\r
+ addClass(this.spanInMainDiv, "currentmatch");\r
+ scrollIntoView(this.spanInMainDiv);\r
+ }\r
+ },\r
+\r
+ belongsTo: function(logEntry) {\r
+ if (isIe) {\r
+ return isDescendant(this.spanInUnwrappedPre, logEntry.unwrappedPre);\r
+ } else {\r
+ return isDescendant(this.spanInMainDiv, logEntry.mainDiv);\r
+ }\r
+ },\r
+\r
+ setNotCurrent: function() {\r
+ if (isIe) {\r
+ removeClass(this.spanInUnwrappedPre, "currentmatch");\r
+ removeClass(this.spanInWrappedDiv, "currentmatch");\r
+ } else {\r
+ removeClass(this.spanInMainDiv, "currentmatch");\r
+ }\r
+ },\r
+\r
+ isOrphan: function() {\r
+ return isOrphan(this.mainSpan);\r
+ },\r
+\r
+ isVisible: function() {\r
+ return getCheckBox(this.logEntryLevel).checked;\r
+ },\r
+\r
+ remove: function() {\r
+ if (isIe) {\r
+ this.spanInUnwrappedPre = null;\r
+ this.spanInWrappedDiv = null;\r
+ } else {\r
+ this.spanInMainDiv = null;\r
+ }\r
+ }\r
+ };\r
+\r
+ var currentSearch = null;\r
+ var currentMatchIndex = null;\r
+\r
+ function doSearch() {\r
+ var searchBox = $("searchBox");\r
+ var searchTerm = searchBox.value;\r
+ var isRegex = $("searchRegex").checked;\r
+ var isCaseSensitive = $("searchCaseSensitive").checked;\r
+ var i;\r
+\r
+ if (searchTerm === "") {\r
+ $("searchReset").disabled = true;\r
+ $("searchNav").style.display = "none";\r
+ removeClass(document.body, "searching");\r
+ removeClass(searchBox, "hasmatches");\r
+ removeClass(searchBox, "nomatches");\r
+ for (i = 0; i < logEntries.length; i++) {\r
+ logEntries[i].clearSearch();\r
+ logEntries[i].setContent(logEntries[i].formattedMessage, logEntries[i].formattedMessage);\r
+ }\r
+ currentSearch = null;\r
+ setLogContainerHeight();\r
+ } else {\r
+ $("searchReset").disabled = false;\r
+ $("searchNav").style.display = "block";\r
+ var searchRegex;\r
+ var regexValid;\r
+ if (isRegex) {\r
+ try {\r
+ searchRegex = isCaseSensitive ? new RegExp(searchTerm, "g") : new RegExp(searchTerm, "gi");\r
+ regexValid = true;\r
+ replaceClass(searchBox, "validregex", "invalidregex");\r
+ searchBox.title = "Valid regex";\r
+ } catch (ex) {\r
+ regexValid = false;\r
+ replaceClass(searchBox, "invalidregex", "validregex");\r
+ searchBox.title = "Invalid regex: " + (ex.message ? ex.message : (ex.description ? ex.description : "unknown error"));\r
+ return;\r
+ }\r
+ } else {\r
+ searchBox.title = "";\r
+ removeClass(searchBox, "validregex");\r
+ removeClass(searchBox, "invalidregex");\r
+ }\r
+ addClass(document.body, "searching");\r
+ currentSearch = new Search(searchTerm, isRegex, searchRegex, isCaseSensitive);\r
+ for (i = 0; i < logEntries.length; i++) {\r
+ currentSearch.applyTo(logEntries[i]);\r
+ }\r
+ setLogContainerHeight();\r
+\r
+ // Highlight the first search match\r
+ if (currentSearch.hasVisibleMatches()) {\r
+ setCurrentMatchIndex(0);\r
+ displayMatches();\r
+ } else {\r
+ displayNoMatches();\r
+ }\r
+ }\r
+ }\r
+\r
+ function updateSearchFromFilters() {\r
+ if (currentSearch) {\r
+ if (currentSearch.hasMatches()) {\r
+ if (currentMatchIndex === null) {\r
+ currentMatchIndex = 0;\r
+ }\r
+ var currentMatch = currentSearch.matches[currentMatchIndex];\r
+ if (currentMatch.isVisible()) {\r
+ displayMatches();\r
+ setCurrentMatchIndex(currentMatchIndex);\r
+ } else {\r
+ currentMatch.setNotCurrent();\r
+ // Find the next visible match, if one exists\r
+ var nextVisibleMatchIndex = currentSearch.getNextVisibleMatchIndex();\r
+ if (nextVisibleMatchIndex > -1) {\r
+ setCurrentMatchIndex(nextVisibleMatchIndex);\r
+ displayMatches();\r
+ } else {\r
+ displayNoMatches();\r
+ }\r
+ }\r
+ } else {\r
+ displayNoMatches();\r
+ }\r
+ }\r
+ }\r
+\r
+ function refreshCurrentMatch() {\r
+ if (currentSearch && currentSearch.hasVisibleMatches()) {\r
+ setCurrentMatchIndex(currentMatchIndex);\r
+ }\r
+ }\r
+\r
+ function displayMatches() {\r
+ replaceClass($("searchBox"), "hasmatches", "nomatches");\r
+ $("searchBox").title = "" + currentSearch.matches.length + " matches found";\r
+ $("searchNav").style.display = "block";\r
+ setLogContainerHeight();\r
+ }\r
+\r
+ function displayNoMatches() {\r
+ replaceClass($("searchBox"), "nomatches", "hasmatches");\r
+ $("searchBox").title = "No matches found";\r
+ $("searchNav").style.display = "none";\r
+ setLogContainerHeight();\r
+ }\r
+\r
+ function toggleSearchEnabled(enable) {\r
+ enable = (typeof enable == "undefined") ? !$("searchDisable").checked : enable;\r
+ $("searchBox").disabled = !enable;\r
+ $("searchReset").disabled = !enable;\r
+ $("searchRegex").disabled = !enable;\r
+ $("searchNext").disabled = !enable;\r
+ $("searchPrevious").disabled = !enable;\r
+ $("searchCaseSensitive").disabled = !enable;\r
+ $("searchNav").style.display = (enable && ($("searchBox").value !== "") &&\r
+ currentSearch && currentSearch.hasVisibleMatches()) ?\r
+ "block" : "none";\r
+ if (enable) {\r
+ removeClass($("search"), "greyedout");\r
+ addClass(document.body, "searching");\r
+ if ($("searchHighlight").checked) {\r
+ addClass(logMainContainer, "searchhighlight");\r
+ } else {\r
+ removeClass(logMainContainer, "searchhighlight");\r
+ }\r
+ if ($("searchFilter").checked) {\r
+ addClass(logMainContainer, "searchfilter");\r
+ } else {\r
+ removeClass(logMainContainer, "searchfilter");\r
+ }\r
+ $("searchDisable").checked = !enable;\r
+ } else {\r
+ addClass($("search"), "greyedout");\r
+ removeClass(document.body, "searching");\r
+ removeClass(logMainContainer, "searchhighlight");\r
+ removeClass(logMainContainer, "searchfilter");\r
+ }\r
+ setLogContainerHeight();\r
+ }\r
+\r
+ function toggleSearchFilter() {\r
+ var enable = $("searchFilter").checked;\r
+ if (enable) {\r
+ addClass(logMainContainer, "searchfilter");\r
+ } else {\r
+ removeClass(logMainContainer, "searchfilter");\r
+ }\r
+ refreshCurrentMatch();\r
+ }\r
+\r
+ function toggleSearchHighlight() {\r
+ var enable = $("searchHighlight").checked;\r
+ if (enable) {\r
+ addClass(logMainContainer, "searchhighlight");\r
+ } else {\r
+ removeClass(logMainContainer, "searchhighlight");\r
+ }\r
+ }\r
+\r
+ function clearSearch() {\r
+ $("searchBox").value = "";\r
+ doSearch();\r
+ }\r
+\r
+ function searchNext() {\r
+ if (currentSearch !== null && currentMatchIndex !== null) {\r
+ currentSearch.matches[currentMatchIndex].setNotCurrent();\r
+ var nextMatchIndex = currentSearch.getNextVisibleMatchIndex();\r
+ if (nextMatchIndex > currentMatchIndex || confirm("Reached the end of the page. Start from the top?")) {\r
+ setCurrentMatchIndex(nextMatchIndex);\r
+ }\r
+ }\r
+ }\r
+\r
+ function searchPrevious() {\r
+ if (currentSearch !== null && currentMatchIndex !== null) {\r
+ currentSearch.matches[currentMatchIndex].setNotCurrent();\r
+ var previousMatchIndex = currentSearch.getPreviousVisibleMatchIndex();\r
+ if (previousMatchIndex < currentMatchIndex || confirm("Reached the start of the page. Continue from the bottom?")) {\r
+ setCurrentMatchIndex(previousMatchIndex);\r
+ }\r
+ }\r
+ }\r
+\r
+ function setCurrentMatchIndex(index) {\r
+ currentMatchIndex = index;\r
+ currentSearch.matches[currentMatchIndex].setCurrent();\r
+ }\r
+\r
+ /* ------------------------------------------------------------------------- */\r
+\r
+ // CSS Utilities\r
+\r
+ function addClass(el, cssClass) {\r
+ if (!hasClass(el, cssClass)) {\r
+ if (el.className) {\r
+ el.className += " " + cssClass;\r
+ } else {\r
+ el.className = cssClass;\r
+ }\r
+ }\r
+ }\r
+\r
+ function hasClass(el, cssClass) {\r
+ if (el.className) {\r
+ var classNames = el.className.split(" ");\r
+ return array_contains(classNames, cssClass);\r
+ }\r
+ return false;\r
+ }\r
+\r
+ function removeClass(el, cssClass) {\r
+ if (hasClass(el, cssClass)) {\r
+ // Rebuild the className property\r
+ var existingClasses = el.className.split(" ");\r
+ var newClasses = [];\r
+ for (var i = 0, len = existingClasses.length; i < len; i++) {\r
+ if (existingClasses[i] != cssClass) {\r
+ newClasses[newClasses.length] = existingClasses[i];\r
+ }\r
+ }\r
+ el.className = newClasses.join(" ");\r
+ }\r
+ }\r
+\r
+ function replaceClass(el, newCssClass, oldCssClass) {\r
+ removeClass(el, oldCssClass);\r
+ addClass(el, newCssClass);\r
+ }\r
+\r
+ /* ------------------------------------------------------------------------- */\r
+\r
+ // Other utility functions\r
+\r
+ function getElementsByClass(el, cssClass, tagName) {\r
+ var elements = el.getElementsByTagName(tagName);\r
+ var matches = [];\r
+ for (var i = 0, len = elements.length; i < len; i++) {\r
+ if (hasClass(elements[i], cssClass)) {\r
+ matches.push(elements[i]);\r
+ }\r
+ }\r
+ return matches;\r
+ }\r
+\r
+ // Syntax borrowed from Prototype library\r
+ function $(id) {\r
+ return document.getElementById(id);\r
+ }\r
+\r
+ function isDescendant(node, ancestorNode) {\r
+ while (node != null) {\r
+ if (node === ancestorNode) {\r
+ return true;\r
+ }\r
+ node = node.parentNode;\r
+ }\r
+ return false;\r
+ }\r
+\r
+ function isOrphan(node) {\r
+ var currentNode = node;\r
+ while (currentNode) {\r
+ if (currentNode == document.body) {\r
+ return false;\r
+ }\r
+ currentNode = currentNode.parentNode;\r
+ }\r
+ return true;\r
+ }\r
+\r
+ function escapeHtml(str) {\r
+ return str.replace(/&/g, "&").replace(/[<]/g, "<").replace(/>/g, ">");\r
+ }\r
+\r
+ function getWindowWidth() {\r
+ if (window.innerWidth) {\r
+ return window.innerWidth;\r
+ } else if (document.documentElement && document.documentElement.clientWidth) {\r
+ return document.documentElement.clientWidth;\r
+ } else if (document.body) {\r
+ return document.body.clientWidth;\r
+ }\r
+ return 0;\r
+ }\r
+\r
+ function getWindowHeight() {\r
+ if (window.innerHeight) {\r
+ return window.innerHeight;\r
+ } else if (document.documentElement && document.documentElement.clientHeight) {\r
+ return document.documentElement.clientHeight;\r
+ } else if (document.body) {\r
+ return document.body.clientHeight;\r
+ }\r
+ return 0;\r
+ }\r
+\r
+ function getToolBarsHeight() {\r
+ return $("switches").offsetHeight;\r
+ }\r
+\r
+ function getChromeHeight() {\r
+ var height = getToolBarsHeight();\r
+ if (showCommandLine) {\r
+ height += $("commandLine").offsetHeight;\r
+ }\r
+ return height;\r
+ }\r
+\r
+ function setLogContainerHeight() {\r
+ if (logMainContainer) {\r
+ var windowHeight = getWindowHeight();\r
+ $("body").style.height = getWindowHeight() + "px";\r
+ logMainContainer.style.height = "" +\r
+ Math.max(0, windowHeight - getChromeHeight()) + "px";\r
+ }\r
+ }\r
+\r
+ function setCommandInputWidth() {\r
+ if (showCommandLine) {\r
+ $("command").style.width = "" + Math.max(0, $("commandLineContainer").offsetWidth -\r
+ ($("evaluateButton").offsetWidth + 13)) + "px";\r
+ }\r
+ }\r
+\r
+ window.onresize = function() {\r
+ setCommandInputWidth();\r
+ setLogContainerHeight();\r
+ };\r
+\r
+ if (!Array.prototype.push) {\r
+ Array.prototype.push = function() {\r
+ for (var i = 0, len = arguments.length; i < len; i++){\r
+ this[this.length] = arguments[i];\r
+ }\r
+ return this.length;\r
+ };\r
+ }\r
+\r
+ if (!Array.prototype.pop) {\r
+ Array.prototype.pop = function() {\r
+ if (this.length > 0) {\r
+ var val = this[this.length - 1];\r
+ this.length = this.length - 1;\r
+ return val;\r
+ }\r
+ };\r
+ }\r
+\r
+ if (!Array.prototype.shift) {\r
+ Array.prototype.shift = function() {\r
+ if (this.length > 0) {\r
+ var firstItem = this[0];\r
+ for (var i = 0, len = this.length - 1; i < len; i++) {\r
+ this[i] = this[i + 1];\r
+ }\r
+ this.length = this.length - 1;\r
+ return firstItem;\r
+ }\r
+ };\r
+ }\r
+\r
+ if (!Array.prototype.splice) {\r
+ Array.prototype.splice = function(startIndex, deleteCount) {\r
+ var itemsAfterDeleted = this.slice(startIndex + deleteCount);\r
+ var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);\r
+ this.length = startIndex;\r
+ // Copy the arguments into a proper Array object\r
+ var argumentsArray = [];\r
+ for (var i = 0, len = arguments.length; i < len; i++) {\r
+ argumentsArray[i] = arguments[i];\r
+ }\r
+ var itemsToAppend = (argumentsArray.length > 2) ?\r
+ itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;\r
+ for (i = 0, len = itemsToAppend.length; i < len; i++) {\r
+ this.push(itemsToAppend[i]);\r
+ }\r
+ return itemsDeleted;\r
+ };\r
+ }\r
+\r
+ function array_remove(arr, val) {\r
+ var index = -1;\r
+ for (var i = 0, len = arr.length; i < len; i++) {\r
+ if (arr[i] === val) {\r
+ index = i;\r
+ break;\r
+ }\r
+ }\r
+ if (index >= 0) {\r
+ arr.splice(index, 1);\r
+ return index;\r
+ } else {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ function array_removeFromStart(array, numberToRemove) {\r
+ if (Array.prototype.splice) {\r
+ array.splice(0, numberToRemove);\r
+ } else {\r
+ for (var i = numberToRemove, len = array.length; i < len; i++) {\r
+ array[i - numberToRemove] = array[i];\r
+ }\r
+ array.length = array.length - numberToRemove;\r
+ }\r
+ return array;\r
+ }\r
+\r
+ function array_contains(arr, val) {\r
+ for (var i = 0, len = arr.length; i < len; i++) {\r
+ if (arr[i] == val) {\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+\r
+ function getErrorMessage(ex) {\r
+ if (ex.message) {\r
+ return ex.message;\r
+ } else if (ex.description) {\r
+ return ex.description;\r
+ }\r
+ return "" + ex;\r
+ }\r
+\r
+ function moveCaretToEnd(input) {\r
+ if (input.setSelectionRange) {\r
+ input.focus();\r
+ var length = input.value.length;\r
+ input.setSelectionRange(length, length);\r
+ } else if (input.createTextRange) {\r
+ var range = input.createTextRange();\r
+ range.collapse(false);\r
+ range.select();\r
+ }\r
+ input.focus();\r
+ }\r
+\r
+ function stopPropagation(evt) {\r
+ if (evt.stopPropagation) {\r
+ evt.stopPropagation();\r
+ } else if (typeof evt.cancelBubble != "undefined") {\r
+ evt.cancelBubble = true;\r
+ }\r
+ }\r
+\r
+ function getEvent(evt) {\r
+ return evt ? evt : event;\r
+ }\r
+\r
+ function getTarget(evt) {\r
+ return evt.target ? evt.target : evt.srcElement;\r
+ }\r
+\r
+ function getRelatedTarget(evt) {\r
+ if (evt.relatedTarget) {\r
+ return evt.relatedTarget;\r
+ } else if (evt.srcElement) {\r
+ switch(evt.type) {\r
+ case "mouseover":\r
+ return evt.fromElement;\r
+ case "mouseout":\r
+ return evt.toElement;\r
+ default:\r
+ return evt.srcElement;\r
+ }\r
+ }\r
+ }\r
+\r
+ function cancelKeyEvent(evt) {\r
+ evt.returnValue = false;\r
+ stopPropagation(evt);\r
+ }\r
+\r
+ function evalCommandLine() {\r
+ var expr = $("command").value;\r
+ evalCommand(expr);\r
+ $("command").value = "";\r
+ }\r
+\r
+ function evalLastCommand() {\r
+ if (lastCommand != null) {\r
+ evalCommand(lastCommand);\r
+ }\r
+ }\r
+\r
+ var lastCommand = null;\r
+ var commandHistory = [];\r
+ var currentCommandIndex = 0;\r
+\r
+ function evalCommand(expr) {\r
+ if (appender) {\r
+ appender.evalCommandAndAppend(expr);\r
+ } else {\r
+ var prefix = ">>> " + expr + "\r\n";\r
+ try {\r
+ log("INFO", prefix + eval(expr));\r
+ } catch (ex) {\r
+ log("ERROR", prefix + "Error: " + getErrorMessage(ex));\r
+ }\r
+ }\r
+ // Update command history\r
+ if (expr != commandHistory[commandHistory.length - 1]) {\r
+ commandHistory.push(expr);\r
+ // Update the appender\r
+ if (appender) {\r
+ appender.storeCommandHistory(commandHistory);\r
+ }\r
+ }\r
+ currentCommandIndex = (expr == commandHistory[currentCommandIndex]) ? currentCommandIndex + 1 : commandHistory.length;\r
+ lastCommand = expr;\r
+ }\r
+ //]]>\r
+ </script>\r
+ <style type="text/css">\r
+ body {\r
+ background-color: white;\r
+ color: black;\r
+ padding: 0;\r
+ margin: 0;\r
+ font-family: tahoma, verdana, arial, helvetica, sans-serif;\r
+ overflow: hidden;\r
+ }\r
+\r
+ div#switchesContainer input {\r
+ margin-bottom: 0;\r
+ }\r
+\r
+ div.toolbar {\r
+ border-top: solid #ffffff 1px;\r
+ border-bottom: solid #aca899 1px;\r
+ background-color: #f1efe7;\r
+ padding: 3px 5px;\r
+ font-size: 68.75%;\r
+ }\r
+\r
+ div.toolbar, div#search input {\r
+ font-family: tahoma, verdana, arial, helvetica, sans-serif;\r
+ }\r
+\r
+ div.toolbar input.button {\r
+ padding: 0 5px;\r
+ font-size: 100%;\r
+ }\r
+\r
+ div.toolbar input.hidden {\r
+ display: none;\r
+ }\r
+\r
+ div#switches input#clearButton {\r
+ margin-left: 20px;\r
+ }\r
+\r
+ div#levels label {\r
+ font-weight: bold;\r
+ }\r
+\r
+ div#levels label, div#options label {\r
+ margin-right: 5px;\r
+ }\r
+\r
+ div#levels label#wrapLabel {\r
+ font-weight: normal;\r
+ }\r
+\r
+ div#search label {\r
+ margin-right: 10px;\r
+ }\r
+\r
+ div#search label.searchboxlabel {\r
+ margin-right: 0;\r
+ }\r
+\r
+ div#search input {\r
+ font-size: 100%;\r
+ }\r
+\r
+ div#search input.validregex {\r
+ color: green;\r
+ }\r
+\r
+ div#search input.invalidregex {\r
+ color: red;\r
+ }\r
+\r
+ div#search input.nomatches {\r
+ color: white;\r
+ background-color: #ff6666;\r
+ }\r
+\r
+ div#search input.nomatches {\r
+ color: white;\r
+ background-color: #ff6666;\r
+ }\r
+\r
+ div#searchNav {\r
+ display: none;\r
+ }\r
+\r
+ div#commandLine {\r
+ display: none;\r
+ }\r
+\r
+ div#commandLine input#command {\r
+ font-size: 100%;\r
+ font-family: Courier New, Courier;\r
+ }\r
+\r
+ div#commandLine input#evaluateButton {\r
+ }\r
+\r
+ *.greyedout {\r
+ color: gray !important;\r
+ border-color: gray !important;\r
+ }\r
+\r
+ *.greyedout *.alwaysenabled { color: black; }\r
+\r
+ *.unselectable {\r
+ -khtml-user-select: none;\r
+ -moz-user-select: none;\r
+ user-select: none;\r
+ }\r
+\r
+ div#log {\r
+ font-family: Courier New, Courier;\r
+ font-size: 75%;\r
+ width: 100%;\r
+ overflow: auto;\r
+ clear: both;\r
+ position: relative;\r
+ }\r
+\r
+ div.group {\r
+ border-color: #cccccc;\r
+ border-style: solid;\r
+ border-width: 1px 0 1px 1px;\r
+ overflow: visible;\r
+ }\r
+\r
+ div.oldIe div.group, div.oldIe div.group *, div.oldIe *.logentry {\r
+ height: 1%;\r
+ }\r
+\r
+ div.group div.groupheading span.expander {\r
+ border: solid black 1px;\r
+ font-family: Courier New, Courier;\r
+ font-size: 0.833em;\r
+ background-color: #eeeeee;\r
+ position: relative;\r
+ top: -1px;\r
+ color: black;\r
+ padding: 0 2px;\r
+ cursor: pointer;\r
+ cursor: hand;\r
+ height: 1%;\r
+ }\r
+\r
+ div.group div.groupcontent {\r
+ margin-left: 10px;\r
+ padding-bottom: 2px;\r
+ overflow: visible;\r
+ }\r
+\r
+ div.group div.expanded {\r
+ display: block;\r
+ }\r
+\r
+ div.group div.collapsed {\r
+ display: none;\r
+ }\r
+\r
+ *.logentry {\r
+ overflow: visible;\r
+ display: none;\r
+ white-space: pre;\r
+ }\r
+\r
+ span.pre {\r
+ white-space: pre;\r
+ }\r
+ \r
+ pre.unwrapped {\r
+ display: inline !important;\r
+ }\r
+\r
+ pre.unwrapped pre.pre, div.wrapped pre.pre {\r
+ display: inline;\r
+ }\r
+\r
+ div.wrapped pre.pre {\r
+ white-space: normal;\r
+ }\r
+\r
+ div.wrapped {\r
+ display: none;\r
+ }\r
+\r
+ body.searching *.logentry span.currentmatch {\r
+ color: white !important;\r
+ background-color: green !important;\r
+ }\r
+\r
+ body.searching div.searchhighlight *.logentry span.searchterm {\r
+ color: black;\r
+ background-color: yellow;\r
+ }\r
+\r
+ div.wrap *.logentry {\r
+ white-space: normal !important;\r
+ border-width: 0 0 1px 0;\r
+ border-color: #dddddd;\r
+ border-style: dotted;\r
+ }\r
+\r
+ div.wrap #log_wrapped, #log_unwrapped {\r
+ display: block;\r
+ }\r
+\r
+ div.wrap #log_unwrapped, #log_wrapped {\r
+ display: none;\r
+ }\r
+\r
+ div.wrap *.logentry span.pre {\r
+ overflow: visible;\r
+ white-space: normal;\r
+ }\r
+\r
+ div.wrap *.logentry pre.unwrapped {\r
+ display: none;\r
+ }\r
+\r
+ div.wrap *.logentry span.wrapped {\r
+ display: inline;\r
+ }\r
+\r
+ div.searchfilter *.searchnonmatch {\r
+ display: none !important;\r
+ }\r
+\r
+ div#log *.TRACE, label#label_TRACE {\r
+ color: #666666;\r
+ }\r
+\r
+ div#log *.DEBUG, label#label_DEBUG {\r
+ color: green;\r
+ }\r
+\r
+ div#log *.INFO, label#label_INFO {\r
+ color: #000099;\r
+ }\r
+\r
+ div#log *.WARN, label#label_WARN {\r
+ color: #999900;\r
+ }\r
+\r
+ div#log *.ERROR, label#label_ERROR {\r
+ color: red;\r
+ }\r
+\r
+ div#log *.FATAL, label#label_FATAL {\r
+ color: #660066;\r
+ }\r
+\r
+ div.TRACE#log *.TRACE,\r
+ div.DEBUG#log *.DEBUG,\r
+ div.INFO#log *.INFO,\r
+ div.WARN#log *.WARN,\r
+ div.ERROR#log *.ERROR,\r
+ div.FATAL#log *.FATAL {\r
+ display: block;\r
+ }\r
+\r
+ div#log div.separator {\r
+ background-color: #cccccc;\r
+ margin: 5px 0;\r
+ line-height: 1px;\r
+ }\r
+ </style>\r
+ </head>\r
+\r
+ <body id="body">\r
+ <div id="switchesContainer">\r
+ <div id="switches">\r
+ <div id="levels" class="toolbar">\r
+ Filters:\r
+ <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>\r
+ <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>\r
+ <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>\r
+ <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>\r
+ <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>\r
+ <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>\r
+ <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>\r
+ </div>\r
+ <div id="search" class="toolbar">\r
+ <label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />\r
+ <input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />\r
+ <input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>\r
+ <input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>\r
+ <input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>\r
+ <div id="searchNav">\r
+ <input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />\r
+ <input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />\r
+ <input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>\r
+ <input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>\r
+ </div>\r
+ </div>\r
+ <div id="options" class="toolbar">\r
+ Options:\r
+ <input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>\r
+ <input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>\r
+ <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>\r
+ <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>\r
+ <input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages" />\r
+ <input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />\r
+ <input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />\r
+ </div>\r
+ </div>\r
+ </div>\r
+ <div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>\r
+ <div id="commandLine" class="toolbar">\r
+ <div id="commandLineContainer">\r
+ <input type="text" id="command" title="Enter a JavaScript command here and hit return or press 'Evaluate'" />\r
+ <input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />\r
+ </div>\r
+ </div>\r
+ </body>\r
+</html>\r
--- /dev/null
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+<head>\r
+<title>log4javascript</title>\r
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\r
+<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->\r
+<meta http-equiv="X-UA-Compatible" content="IE=7" />\r
+<script type="text/javascript">\r
+//<![CDATA[\r
+var loggingEnabled=true;var messagesBeforeDocLoaded=[];function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}\r
+function setLoggingEnabled(enable){loggingEnabled=enable;}\r
+function scrollToLatestEntry(){var l=getLogContainer();if(typeof l.scrollTop!="undefined"){var latestLogEntry=l.lastChild;if(latestLogEntry){l.scrollTop=l.scrollHeight;}}}\r
+function log(logLevel,formattedMessage){if(loggingEnabled){if(loaded){doLog(logLevel,formattedMessage);}else{messagesBeforeDocLoaded.push([logLevel,formattedMessage]);}}}\r
+function doLog(logLevel,formattedMessage){var logEntry=document.createElement("div");logEntry.appendChild(document.createTextNode(formattedMessage));logEntry.className="logentry "+logLevel.name;getLogContainer().appendChild(logEntry);scrollToLatestEntry();}\r
+function mainPageReloaded(){var separator=document.createElement("div");separator.className="separator";separator.innerHTML=" ";getLogContainer().appendChild(separator);}\r
+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]);}\r
+messagesBeforeDocLoaded=[];loaded=true;setTimeout(setLogContainerHeight,20);};function getLogContainer(){return $("log");}\r
+function clearLog(){getLogContainer().innerHTML="";}\r
+function $(id){return document.getElementById(id);}\r
+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;}\r
+return 0;}\r
+function getChromeHeight(){return $("toolbar").offsetHeight;}\r
+function setLogContainerHeight(){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";getLogContainer().style.height=""+\r
+Math.max(0,windowHeight-getChromeHeight())+"px";}\r
+window.onresize=function(){setLogContainerHeight();};\r
+//]]>\r
+</script>\r
+<style type="text/css">\r
+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}\r
+</style>\r
+</head>\r
+<body id="body">\r
+<div id="toolbar">\r
+Options:\r
+<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" class="stateful" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Enable logging</label>\r
+<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="stateful button" title="Clear all log messages" />\r
+<input type="button" id="closeButton" value="Close" onclick="window.close()" class="stateful button" title="Close the window" />\r
+</div>\r
+<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>\r
+</body>\r
+</html>
\ No newline at end of file
--- /dev/null
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript</title>\r
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\r
+ <!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->\r
+ <meta http-equiv="X-UA-Compatible" content="IE=7" />\r
+ <script type="text/javascript">\r
+ //<![CDATA[\r
+ var loggingEnabled = true;\r
+ var messagesBeforeDocLoaded = [];\r
+\r
+ function toggleLoggingEnabled() {\r
+ setLoggingEnabled($("enableLogging").checked);\r
+ }\r
+\r
+ function setLoggingEnabled(enable) {\r
+ loggingEnabled = enable;\r
+ }\r
+\r
+ function scrollToLatestEntry() {\r
+ var l = getLogContainer();\r
+ if (typeof l.scrollTop != "undefined") {\r
+ var latestLogEntry = l.lastChild;\r
+ if (latestLogEntry) {\r
+ l.scrollTop = l.scrollHeight;\r
+ }\r
+ }\r
+ }\r
+\r
+ function log(logLevel, formattedMessage) {\r
+ if (loggingEnabled) {\r
+ if (loaded) {\r
+ doLog(logLevel, formattedMessage);\r
+ } else {\r
+ messagesBeforeDocLoaded.push([logLevel, formattedMessage]);\r
+ }\r
+ }\r
+ }\r
+\r
+ function doLog(logLevel, formattedMessage) {\r
+ var logEntry = document.createElement("div");\r
+ logEntry.appendChild(document.createTextNode(formattedMessage));\r
+ logEntry.className = "logentry " + logLevel.name;\r
+ getLogContainer().appendChild(logEntry);\r
+ scrollToLatestEntry();\r
+ }\r
+\r
+ function mainPageReloaded() {\r
+ var separator = document.createElement("div");\r
+ separator.className = "separator";\r
+ separator.innerHTML = " ";\r
+ getLogContainer().appendChild(separator);\r
+ }\r
+\r
+ var loaded = false;\r
+ var logLevels = ["DEBUG", "INFO", "WARN", "ERROR", "FATAL"];\r
+\r
+ window.onload = function() {\r
+ setLogContainerHeight();\r
+ toggleLoggingEnabled();\r
+ for (var i = 0; i < messagesBeforeDocLoaded.length; i++) {\r
+ doLog(messagesBeforeDocLoaded[i][0], messagesBeforeDocLoaded[i][1]);\r
+ }\r
+ messagesBeforeDocLoaded = [];\r
+ loaded = true;\r
+\r
+ // Workaround to make sure log div starts at the correct size\r
+ setTimeout(setLogContainerHeight, 20);\r
+ };\r
+\r
+ function getLogContainer() {\r
+ return $("log");\r
+ }\r
+\r
+ function clearLog() {\r
+ getLogContainer().innerHTML = "";\r
+ }\r
+\r
+ /* ------------------------------------------------------------------------- */\r
+\r
+ // Other utility functions\r
+\r
+ // Syntax borrowed from Prototype library\r
+ function $(id) {\r
+ return document.getElementById(id);\r
+ }\r
+\r
+ function getWindowHeight() {\r
+ if (window.innerHeight) {\r
+ return window.innerHeight;\r
+ } else if (document.documentElement && document.documentElement.clientHeight) {\r
+ return document.documentElement.clientHeight;\r
+ } else if (document.body) {\r
+ return document.body.clientHeight;\r
+ }\r
+ return 0;\r
+ }\r
+\r
+ function getChromeHeight() {\r
+ return $("toolbar").offsetHeight;\r
+ }\r
+\r
+ function setLogContainerHeight() {\r
+ var windowHeight = getWindowHeight();\r
+ $("body").style.height = getWindowHeight() + "px";\r
+ getLogContainer().style.height = "" +\r
+ Math.max(0, windowHeight - getChromeHeight()) + "px";\r
+ }\r
+\r
+ window.onresize = function() {\r
+ setLogContainerHeight();\r
+ };\r
+\r
+ //]]>\r
+ </script>\r
+ <style type="text/css">\r
+ body {\r
+ background-color: white;\r
+ color: black;\r
+ padding: 0;\r
+ margin: 0;\r
+ font-family: tahoma, verdana, arial, helvetica, sans-serif;\r
+ overflow: hidden;\r
+ }\r
+ \r
+ div#toolbar {\r
+ border-top: solid #ffffff 1px;\r
+ border-bottom: solid #aca899 1px;\r
+ background-color: #f1efe7;\r
+ padding: 3px 5px;\r
+ font-size: 68.75%;\r
+ }\r
+\r
+ div#toolbar input.button {\r
+ padding: 0 5px;\r
+ font-size: 100%;\r
+ }\r
+\r
+ div#log {\r
+ font-family: Courier New, Courier;\r
+ font-size: 75%;\r
+ width: 100%;\r
+ overflow: auto;\r
+ clear: both;\r
+ }\r
+\r
+ *.logentry {\r
+ overflow: visible;\r
+ white-space: pre;\r
+ }\r
+\r
+ *.TRACE {\r
+ color: #666666;\r
+ }\r
+\r
+ *.DEBUG {\r
+ color: green;\r
+ }\r
+\r
+ *.INFO {\r
+ color: #000099;\r
+ }\r
+\r
+ *.WARN {\r
+ color: #999900;\r
+ }\r
+\r
+ *.ERROR {\r
+ color: red;\r
+ }\r
+\r
+ *.FATAL {\r
+ color: #660066;\r
+ }\r
+\r
+ div#log div.separator {\r
+ background-color: #cccccc;\r
+ margin: 5px 0;\r
+ line-height: 1px;\r
+ }\r
+ </style>\r
+ </head>\r
+\r
+ <body id="body">\r
+ <div id="toolbar">\r
+ Options:\r
+ <input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" class="stateful" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Enable logging</label>\r
+ <input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="stateful button" title="Clear all log messages" />\r
+ <input type="button" id="closeButton" value="Close" onclick="window.close()" class="stateful button" title="Close the window" />\r
+ </div>\r
+ <div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>\r
+ </body>\r
+</html>
\ No newline at end of file
--- /dev/null
+/**\r
+ * Copyright 2013 Tim Down.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+\r
+if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}\r
+return this.length;};}\r
+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];}\r
+this.length=this.length-1;return firstItem;}};}\r
+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];}\r
+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]);}\r
+return itemsDeleted;};}\r
+var log4javascript=(function(){function isUndefined(obj){return typeof obj=="undefined";}\r
+function EventSupport(){}\r
+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+"'");}\r
+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+"'");}\r
+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()+"_"+\r
+Math.floor(Math.random()*100000000);var emptyFunction=function(){};var newLine="\r\n";var pageLoaded=false;function Log4JavaScript(){}\r
+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);}}\r
+function getExceptionMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}else{return toStr(ex);}}\r
+function getUrlFileName(url){var lastSlashIndex=Math.max(url.lastIndexOf("/"),url.lastIndexOf("\\"));return url.substr(lastSlashIndex+1);}\r
+function getExceptionStringRep(ex){if(ex){var exStr="Exception: "+getExceptionMessage(ex);try{if(ex.lineNumber){exStr+=" on line number "+ex.lineNumber;}\r
+if(ex.fileName){exStr+=" in file "+getUrlFileName(ex.fileName);}}catch(localEx){logLog.warn("Unable to obtain file and line information for error");}\r
+if(showStackTraces&&ex.stack){exStr+=newLine+"Stack trace:"+newLine+ex.stack;}\r
+return exStr;}\r
+return null;}\r
+function bool(obj){return Boolean(obj);}\r
+function trim(str){return str.replace(/^\s+/,"").replace(/\s+$/,"");}\r
+function splitIntoLines(text){var text2=text.replace(/\r\n/g,"\n").replace(/\r/g,"\n");return text2.split("\n");}\r
+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;}}\r
+if(index>=0){arr.splice(index,1);return true;}else{return false;}}\r
+function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}\r
+return false;}\r
+function extractBooleanFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return bool(param);}}\r
+function extractStringFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return String(param);}}\r
+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;}}}\r
+function extractFunctionFromParam(param,defaultValue){if(typeof param=="function"){return param;}else{return defaultValue;}}\r
+function isError(err){return(err instanceof Error);}\r
+if(!Function.prototype.apply){Function.prototype.apply=function(obj,args){var methodName="__apply__";if(typeof obj[methodName]!="undefined"){methodName+=String(Math.random()).substr(2);}\r
+obj[methodName]=this;var argsStrings=[];for(var i=0,len=args.length;i<len;i++){argsStrings[i]="args["+i+"]";}\r
+var script="obj."+methodName+"("+argsStrings.join(",")+")";var returnValue=eval(script);delete obj[methodName];return returnValue;};}\r
+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];}\r
+return this.apply(obj,args);};}\r
+function getListenersPropertyName(eventName){return"__log4javascript_listeners__"+eventName;}\r
+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);}};}\r
+node[propertyName].push(listener);}}\r
+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);}}}\r
+function getEvent(evt,win){win=win?win:window;return evt?evt:win.event;}\r
+function stopEventPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}\r
+evt.returnValue=false;}\r
+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);}\r
+alert(alertMessage);}}}};log4javascript.logLog=logLog;log4javascript.setEventTypes(["load","error"]);function handleError(message,exception){logLog.error(message,exception);log4javascript.dispatchEvent("error",{"message":message,"exception":exception});}\r
+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();}\r
+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 ('"+\r
+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);}\r
+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;}\r
+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--;}\r
+var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];}\r
+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 "+\r
+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 "+\r
+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]);}\r
+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+"]";};}\r
+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 "+\r
+toStr(loggerName)+" supplied, returning anonymous logger");}\r
+if(loggerName==rootLoggerName){handleError("log4javascript.getLogger: root logger may not be obtained by name");}\r
+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;}\r
+parentLogger.addChild(logger);}\r
+return loggers[loggerName];};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=log4javascript.getLogger(defaultLoggerName);var a=new log4javascript.PopUpAppender();defaultLogger.addAppender(a);}\r
+return defaultLogger;};var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger(nullLoggerName);nullLogger.setLevel(Level.OFF);}\r
+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]);}\r
+if(loggingEvent.exception){dataValues.push([this.exceptionKey,getExceptionStringRep(loggingEvent.exception)]);}\r
+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);}\r
+dataValues.push([this.customFields[i].name,val]);}}\r
+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;}}\r
+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 "+\r
+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 "+\r
+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=[];}\r
+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=[];}\r
+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=[];}\r
+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(/\]\]>/,"]]>]]><![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["+\r
+layout.escapeCdata(message)+"]]></log4javascript:message>";}\r
+var str="<log4javascript:event logger=\""+loggingEvent.logger.name+"\" timestamp=\""+this.getTimeStampValue(loggingEvent)+"\"";if(!this.isTimeStampsInMilliseconds()){str+=" milliseconds=\""+loggingEvent.milliseconds+"\"";}\r
+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;}\r
+str+="</log4javascript:messages>"+newLine;}\r
+if(this.hasCustomFields()){for(i=0,len=this.customFields.length;i<len;i++){str+="<log4javascript:customfield name=\""+\r
+this.customFields[i].name+"\"><![CDATA["+\r
+this.customFields[i].value.toString()+"]]></log4javascript:customfield>"+newLine;}}\r
+if(loggingEvent.exception){str+="<log4javascript:exception><![CDATA["+\r
+getExceptionStringRep(loggingEvent.exception)+"]]></log4javascript:exception>"+newLine;}\r
+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");}\r
+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=[];}\r
+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+=",";}\r
+formattedValue+=layout.lineBreak;}\r
+formattedValue+=prefix+"]";}else if(valType!=="number"&&valType!=="boolean"){formattedValue="\""+escapeNewLines(toStr(val).replace(/\"/g,"\\\""))+"\"";}else{formattedValue=val;}\r
+return formattedValue;}\r
+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+=",";}\r
+str+=this.lineBreak;}\r
+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;}\r
+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));}\r
+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="";}\r
+function formatString(text){var lines=splitIntoLines(text);for(var j=1,jLen=lines.length;j<jLen;j++){lines[j]=indentation+lines[j];}\r
+return lines.join(newLine);}\r
+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);}\r
+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: "+\r
+getExceptionStringRep(ex)+"");}}\r
+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: "+\r
+getExceptionStringRep(ex));}}\r
+expansion+=childLines.join(","+newLine)+newLine+indentation+"}";return expansion;}else{return formatString(toStr(obj));}}\r
+return doFormat(obj,depth,indentation);}\r
+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;}\r
+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--;}\r
+return weekInYear;};Date.prototype.getWeekInMonth=function(minimalDaysInFirstWeek){if(isUndefined(this.minimalDaysInFirstWeek)){minimalDaysInFirstWeek=DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;}\r
+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++;}\r
+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;}\r
+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;}\r
+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);}\r
+break;case MONTH:if(numberOfLetters>=3){formattedString+=formatText(monthNames[rawData],numberOfLetters,numberOfLetters);}else{formattedString+=formatNumber(rawData+1,numberOfLetters);}\r
+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;}}\r
+searchString=searchString.substr(result.index+result[0].length);}\r
+return formattedString;};})();log4javascript.SimpleDateFormat=SimpleDateFormat;function PatternLayout(pattern){if(pattern){this.pattern=pattern;}else{this.pattern=PatternLayout.DEFAULT_CONVERSION_PATTERN;}\r
+this.customFields=[];}\r
+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 '"+\r
+specifier+"' for conversion character '"+conversionCharacter+"' - should be a number");depth=0;}}\r
+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+=" ";}\r
+if(depth===0){replacement+=messages[i];}else{replacement+=formatObjectExpansion(messages[i],depth);}}\r
+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;}\r
+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;}}\r
+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 '"+\r
+specifier+"' for conversion character 'f' - should be a number");}else if(fieldIndex===0){handleError("PatternLayout.format: invalid specifier '"+\r
+specifier+"' for conversion character 'f' - must be greater than zero");}else if(fieldIndex>this.customFields.length){handleError("PatternLayout.format: invalid specifier '"+\r
+specifier+"' for conversion character 'f' - there aren't that many custom fields");}else{fieldIndex=fieldIndex-1;}}\r
+var val=this.customFields[fieldIndex].value;if(typeof val=="function"){val=val(this,loggingEvent);}\r
+replacement=val;}\r
+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;}\r
+var l;if(truncation){l=parseInt(truncation.substr(1),10);var strLen=replacement.length;if(l<strLen){replacement=replacement.substring(strLen-l,strLen);}}\r
+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;}}}\r
+formattedString+=replacement;}\r
+searchString=searchString.substr(result.index+result[0].length);}\r
+return formattedString;};PatternLayout.prototype.ignoresThrowable=function(){return true;};PatternLayout.prototype.toString=function(){return"PatternLayout";};log4javascript.PatternLayout=PatternLayout;function AlertAppender(){}\r
+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();}\r
+alert(formattedMessage);};AlertAppender.prototype.toString=function(){return"AlertAppender";};log4javascript.AlertAppender=AlertAppender;function BrowserConsoleAppender(){}\r
+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();}\r
+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){}}\r
+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;}\r
+function AjaxAppender(url){var appender=this;var isSupported=true;if(!url){handleError("AjaxAppender: URL must be specified in constructor");isSupported=false;}\r
+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 '"+\r
+configOptionName+"' may not be set after the appender has been initialized");return false;}\r
+return true;}\r
+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));}\r
+sending=false;if(timed){scheduleSending();}}}}\r
+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=[];}}\r
+if(batchedLoggingEvents.length>0){queuedRequests.push(batchedLoggingEvents);}\r
+sendingAnything=(queuedRequests.length>0);waitForResponse=false;timed=false;sendAll();}\r
+return sendingAnything;}\r
+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();}\r
+formattedMessages.push(currentFormattedMessage);}\r
+if(batchedLoggingEvents.length==1){postData=formattedMessages.join("");}else{postData=appender.getLayout().batchHeader+\r
+formattedMessages.join(appender.getLayout().batchSeparator)+\r
+appender.getLayout().batchFooter;}\r
+if(contentType==appender.defaults.contentType){postData=appender.getLayout().returnsPostData?postData:urlEncode(postVarName)+"="+urlEncode(postData);if(postData.length>0){postData+="&";}\r
+postData+="layout="+urlEncode(appender.getLayout().toString());}\r
+return postData;}\r
+function scheduleSending(){window.setTimeout(sendAll,timerInterval);}\r
+function xmlHttpErrorHandler(){var msg="AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}}\r
+function sendRequest(postData,successCallback){try{var xmlHttp=getXmlHttp(xmlHttpErrorHandler);if(isSupported){if(xmlHttp.overrideMimeType){xmlHttp.overrideMimeType(appender.getLayout().getContentType());}\r
+xmlHttp.onreadystatechange=function(){if(xmlHttp.readyState==4){if(isHttpRequestSuccessful(xmlHttp)){if(requestSuccessCallback){requestSuccessCallback(xmlHttp);}\r
+if(successCallback){successCallback(xmlHttp);}}else{var msg="AjaxAppender.append: XMLHttpRequest request to URL "+\r
+url+" returned status code "+xmlHttp.status;handleError(msg);if(failCallback){failCallback(msg);}}\r
+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);}\r
+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);}\r
+return;}\r
+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));}}}\r
+this.append=function(loggingEvent){if(isSupported){if(!initialized){init();}\r
+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);}\r
+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();}\r
+if(sendAllRemaining()){return"Sending log messages";}};}\r
+if(timed){scheduleSending();}}}\r
+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="";}\r
+document.cookie=escape(name)+"="+escape(value)+expires+path;}\r
+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);}\r
+if(c.indexOf(nameEquals)===0){return unescape(c.substring(nameEquals.length,c.length));}}\r
+return null;}\r
+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);}}\r
+return null;}\r
+function isLoaded(win){try{return bool(win.loaded);}catch(ex){return false;}}\r
+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=" ";}','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&¤tSearch.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&¤tEl!=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&¤tSearch.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!=="")&¤tSearch&¤tSearch.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&¤tMatchIndex!==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&¤tMatchIndex!==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,"&").replace(/[<]/g,"<").replace(/>/g,">");}','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;}\r
+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;}\r
+QueuedLoggingEvent.prototype.append=function(){getConsoleWindow().log(this.levelName,this.formattedMessage);};function QueuedGroup(name,initiallyExpanded){this.name=name;this.initiallyExpanded=initiallyExpanded;}\r
+QueuedGroup.prototype.append=function(){getConsoleWindow().group(this.name,this.initiallyExpanded);};function QueuedGroupEnd(){}\r
+QueuedGroupEnd.prototype.append=function(){getConsoleWindow().groupEnd();};var checkAndAppend=function(){safeToAppend();if(!initialized){init();}else if(consoleClosed&&reopenWhenClosed){createWindow();}\r
+if(safeToAppend()){appendQueuedLoggingEvents();}};this.append=function(loggingEvent){if(isSupported){var formattedMessage=appender.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();}\r
+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();}\r
+if(focusConsoleWindow){getConsoleWindow().focus();}};this.setAddedToLogger=function(logger){this.loggers.push(logger);if(enabled&&!lazyInit){init();}};this.clear=function(){if(consoleWindowExists()){getConsoleWindow().clearLog();}\r
+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");}\r
+var commandLineFunctionsHash={};for(i=0,len=commandLineFunctions.length;i<len;i++){commandLineFunctionsHash[commandLineFunctions[i][0]]=commandLineFunctions[i][1];}\r
+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]);}\r
+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);}\r
+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;}\r
+if(commandReturnValue.appendResult){var message=">>> "+expr;if(!isUndefined(commandOutput)){message+=newLine+commandOutput;}\r
+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]);}\r
+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;}\r
+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);}\r
+if(windowTest(getConsoleWindow())){clearInterval(poll);successCallback();}}catch(ex){clearInterval(poll);isSupported=false;handleError(errorMessage,ex);}}\r
+var poll=setInterval(doPoll,interval);};var getConsoleUrl=function(){var documentDomainSet=(document.domain!=location.hostname);return useDocumentWrite?"":getBaseUrl()+"console.html"+\r
+(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();}\r
+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();}\r
+consoleWindowLoadHandler();consoleWindowLoaded=true;appendQueuedLoggingEvents();}catch(ex){isSupported=false;handleError(initErrorMessage,ex);}}\r
+function writeToDocument(){try{var windowTest=function(win){return isLoaded(win);};if(useDocumentWrite){writeHtml(getConsoleWindow().document);}\r
+if(windowTest(getConsoleWindow())){finalInit();}else{pollConsoleWindow(windowTest,100,finalInit,initErrorMessage);}}catch(ex){isSupported=false;handleError(initErrorMessage,ex);}}\r
+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];}\r
+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);}\r
+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;}\r
+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);}\r
+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;}\r
+return consoleWindowLoaded;}\r
+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";}\r
+var windowName="PopUp_"+location.host.replace(/[^a-z0-9]/gi,"_")+"_"+consoleAppenderId+frameInfo;if(!useOldPopUp||!useDocumentWrite){windowName=windowName+"_"+uniqueId;}\r
+var checkPopUpClosed=function(win){if(consoleClosed){return true;}else{try{return bool(win)&&win.closed;}catch(ex){}}\r
+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");}\r
+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);}\r
+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;}\r
+if(!consoleWindowLoaded&&isLoaded(popUp)){consoleWindowLoaded=true;}}\r
+return isSupported&&consoleWindowLoaded&&!consoleClosed;};}\r
+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);}\r
+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);}\r
+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]=" ";}\r
+str+=spaces.join("");}\r
+return str;}\r
+(function(){function dir(obj){var maxLen=0;for(var p in obj){maxLen=Math.max(toStr(p).length,maxLen);}\r
+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)+"]";}\r
+propList.push(propNameStr+propVal);}\r
+return propList.join(newLine);}\r
+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="";}\r
+startNewLine=!!startNewLine;preformatted=!!preformatted;var xhtml;function isWhitespace(node){return((node.nodeType==nodeTypes.TEXT_NODE)&&/^[ \t\r\n]*$/.test(node.nodeValue));}\r
+function fixAttributeValue(attrValue){return attrValue.toString().replace(/&/g,"&").replace(/</g,"<").replace(/"/g,""");}\r
+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]));}\r
+styleValue=props.join(";");}\r
+return styleValue;}\r
+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();}}\r
+return"";}\r
+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+":";}\r
+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;}\r
+xhtml+=" "+currentAttr.nodeName.toLowerCase()+"=\"";xhtml+=fixAttributeValue(currentAttr.nodeValue);xhtml+="\"";}\r
+if(rootNode.style.cssText){var styleValue=getStyleAttributeValue(rootNode);if(styleValue!==""){xhtml+=" style=\""+getStyleAttributeValue(rootNode)+"\"";}}\r
+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);}\r
+var endTag=lt+"/"+tagName+gt;xhtml+=childStartNewLine?newLine+indentation+endTag:endTag;}\r
+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]);}\r
+xhtml=trimmedLines.join(newLine+indentation);}\r
+if(startNewLine){xhtml=newLine+indentation+xhtml;}}\r
+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);}\r
+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);}\r
+return xhtml;}}\r
+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]);}\r
+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]);}\r
+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();}}}\r
+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);}\r
+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));}}\r
+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;}});}\r
+function init(){createCommandLineFunctions();}\r
+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);}\r
+log4javascript.setDocumentReady();};}}\r
+window.log4javascript=log4javascript;return log4javascript;})();\r
--- /dev/null
+/**\r
+ * Copyright 2013 Tim Down.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+\r
+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];}\r
+this.length--;return firstItem;}};}\r
+var log4javascript;(function(){var newLine="\r\n";function Log4JavaScript(){}\r
+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);}}\r
+function getUrlFileName(url){var lastSlashIndex=Math.max(url.lastIndexOf("/"),url.lastIndexOf("\\"));return url.substr(lastSlashIndex+1);}\r
+function getExceptionStringRep(ex){if(ex){var exStr="Exception: "+getExceptionMessage(ex);try{if(ex.lineNumber){exStr+=" on line number "+ex.lineNumber;}\r
+if(ex.fileName){exStr+=" in file "+getUrlFileName(ex.fileName);}}catch(localEx){}\r
+if(showStackTraces&&ex.stack){exStr+=newLine+"Stack trace:"+newLine+ex.stack;}\r
+return exStr;}\r
+return null;}\r
+function isError(err){return(err instanceof Error);}\r
+function bool(obj){return Boolean(obj);}\r
+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=" ";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;}}\r
+function finalInit(){popUpLoaded=true;appendQueuedLoggingEvents();}\r
+function writeHtml(doc){var lines=getConsoleHtmlLines();doc.open();for(var i=0,len=lines.length;i<len;i++){doc.writeln(lines[i]);}\r
+doc.close();}\r
+function pollConsoleWindow(){function pollConsoleWindowLoaded(){if(popUpLoaded){clearInterval(poll);}else if(bool(popUp)&&isLoaded(popUp)){clearInterval(poll);finalInit();}}\r
+var poll=setInterval(pollConsoleWindowLoaded,100);}\r
+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.");}}\r
+initialized=true;}\r
+function safeToAppend(){if(!popUpsBlocked&&!popUpClosed){if(popUp.closed){popUpClosed=true;return false;}\r
+if(!popUpLoaded&&popUp.loaded){popUpLoaded=true;}}\r
+return!popUpsBlocked&&popUpLoaded&&!popUpClosed;}\r
+function padWithZeroes(num,len){var str=""+num;while(str.length<len){str="0"+str;}\r
+return str;}\r
+function padWithSpaces(str,len){while(str.length<len){str+=" ";}\r
+return str;}\r
+this.append=function(loggingEvent){if(!initialized){init();}\r
+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)+":"+\r
+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;}\r
+popUp.log(currentLoggingEvent.level,formattedMessage);}\r
+if(focusPopUp){popUp.focus();}}}}\r
+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--;}\r
+var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];}\r
+var loggingEvent=new LoggingEvent(this,new Date(),level,messages,exception);appender.append(loggingEvent);}};this.setLevel=function(level){loggerLevel=level;};this.getLevel=function(){return loggerLevel;};}\r
+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();}\r
+return defaultLogger;};log4javascript.getLogger=log4javascript.getDefaultLogger;var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger();nullLogger.setLevel(Level.OFF);}\r
+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;})();\r
--- /dev/null
+/**\r
+ * Copyright 2013 Tim Down.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+if (!Array.prototype.shift) {\r
+ Array.prototype.shift = function() {\r
+ if (this.length > 0) {\r
+ var firstItem = this[0];\r
+ for (var i = 0, len = this.length - 1; i < len; i++) {\r
+ this[i] = this[i + 1];\r
+ }\r
+ this.length--;\r
+ return firstItem;\r
+ }\r
+ };\r
+}\r
+\r
+var log4javascript;\r
+\r
+(function() {\r
+ var newLine = "\r\n";\r
+ function Log4JavaScript() {}\r
+ log4javascript = new Log4JavaScript();\r
+ log4javascript.version = "1.4.6";\r
+ log4javascript.edition = "log4javascript_lite";\r
+\r
+ function getExceptionMessage(ex) {\r
+ if (ex.message) {\r
+ return ex.message;\r
+ } else if (ex.description) {\r
+ return ex.description;\r
+ } else {\r
+ return String(ex);\r
+ }\r
+ }\r
+\r
+ // Gets the portion of the URL after the last slash\r
+ function getUrlFileName(url) {\r
+ var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\"));\r
+ return url.substr(lastSlashIndex + 1);\r
+ }\r
+\r
+ // Returns a nicely formatted representation of an error\r
+ function getExceptionStringRep(ex) {\r
+ if (ex) {\r
+ var exStr = "Exception: " + getExceptionMessage(ex);\r
+ try {\r
+ if (ex.lineNumber) {\r
+ exStr += " on line number " + ex.lineNumber;\r
+ }\r
+ if (ex.fileName) {\r
+ exStr += " in file " + getUrlFileName(ex.fileName);\r
+ }\r
+ } catch (localEx) {\r
+ }\r
+ if (showStackTraces && ex.stack) {\r
+ exStr += newLine + "Stack trace:" + newLine + ex.stack;\r
+ }\r
+ return exStr;\r
+ }\r
+ return null;\r
+ }\r
+\r
+ function isError(err) {\r
+ return (err instanceof Error);\r
+ }\r
+\r
+ function bool(obj) {\r
+ return Boolean(obj);\r
+ }\r
+\r
+ var enabled = (typeof log4javascript_disabled != "undefined") &&\r
+ log4javascript_disabled ? false : true;\r
+\r
+ log4javascript.setEnabled = function(enable) {\r
+ enabled = bool(enable);\r
+ };\r
+\r
+ log4javascript.isEnabled = function() {\r
+ return enabled;\r
+ };\r
+\r
+ var showStackTraces = false;\r
+\r
+ log4javascript.setShowStackTraces = function(show) {\r
+ showStackTraces = bool(show);\r
+ };\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Levels\r
+\r
+ var Level = function(level, name) {\r
+ this.level = level;\r
+ this.name = name;\r
+ };\r
+\r
+ Level.prototype = {\r
+ toString: function() {\r
+ return this.name;\r
+ },\r
+ equals: function(level) {\r
+ return this.level == level.level;\r
+ },\r
+ isGreaterOrEqual: function(level) {\r
+ return this.level >= level.level;\r
+ }\r
+ };\r
+\r
+ Level.ALL = new Level(Number.MIN_VALUE, "ALL");\r
+ Level.TRACE = new Level(10000, "TRACE");\r
+ Level.DEBUG = new Level(20000, "DEBUG");\r
+ Level.INFO = new Level(30000, "INFO");\r
+ Level.WARN = new Level(40000, "WARN");\r
+ Level.ERROR = new Level(50000, "ERROR");\r
+ Level.FATAL = new Level(60000, "FATAL");\r
+ Level.OFF = new Level(Number.MAX_VALUE, "OFF");\r
+\r
+ log4javascript.Level = Level;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Appenders\r
+\r
+ function Appender() {\r
+ var getConsoleHtmlLines = function() {\r
+ return [\r
+'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',\r
+'<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">',\r
+' <head>',\r
+' <title>log4javascript</title>',\r
+' <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',\r
+' <!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->',\r
+' <meta http-equiv="X-UA-Compatible" content="IE=7" />',\r
+' <script type="text/javascript">',\r
+' //<![CDATA[',\r
+' var loggingEnabled = true;',\r
+' var messagesBeforeDocLoaded = [];',\r
+'',\r
+' function toggleLoggingEnabled() {',\r
+' setLoggingEnabled($("enableLogging").checked);',\r
+' }',\r
+'',\r
+' function setLoggingEnabled(enable) {',\r
+' loggingEnabled = enable;',\r
+' }',\r
+'',\r
+' function scrollToLatestEntry() {',\r
+' var l = getLogContainer();',\r
+' if (typeof l.scrollTop != "undefined") {',\r
+' var latestLogEntry = l.lastChild;',\r
+' if (latestLogEntry) {',\r
+' l.scrollTop = l.scrollHeight;',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function log(logLevel, formattedMessage) {',\r
+' if (loggingEnabled) {',\r
+' if (loaded) {',\r
+' doLog(logLevel, formattedMessage);',\r
+' } else {',\r
+' messagesBeforeDocLoaded.push([logLevel, formattedMessage]);',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function doLog(logLevel, formattedMessage) {',\r
+' var logEntry = document.createElement("div");',\r
+' logEntry.appendChild(document.createTextNode(formattedMessage));',\r
+' logEntry.className = "logentry " + logLevel.name;',\r
+' getLogContainer().appendChild(logEntry);',\r
+' scrollToLatestEntry();',\r
+' }',\r
+'',\r
+' function mainPageReloaded() {',\r
+' var separator = document.createElement("div");',\r
+' separator.className = "separator";',\r
+' separator.innerHTML = " ";',\r
+' getLogContainer().appendChild(separator);',\r
+' }',\r
+'',\r
+' var loaded = false;',\r
+' var logLevels = ["DEBUG", "INFO", "WARN", "ERROR", "FATAL"];',\r
+'',\r
+' window.onload = function() {',\r
+' setLogContainerHeight();',\r
+' toggleLoggingEnabled();',\r
+' for (var i = 0; i < messagesBeforeDocLoaded.length; i++) {',\r
+' doLog(messagesBeforeDocLoaded[i][0], messagesBeforeDocLoaded[i][1]);',\r
+' }',\r
+' messagesBeforeDocLoaded = [];',\r
+' loaded = true;',\r
+'',\r
+' // Workaround to make sure log div starts at the correct size',\r
+' setTimeout(setLogContainerHeight, 20);',\r
+' };',\r
+'',\r
+' function getLogContainer() {',\r
+' return $("log");',\r
+' }',\r
+'',\r
+' function clearLog() {',\r
+' getLogContainer().innerHTML = "";',\r
+' }',\r
+'',\r
+' /* ------------------------------------------------------------------------- */',\r
+'',\r
+' // Other utility functions',\r
+'',\r
+' // Syntax borrowed from Prototype library',\r
+' function $(id) {',\r
+' return document.getElementById(id);',\r
+' }',\r
+'',\r
+' function getWindowHeight() {',\r
+' if (window.innerHeight) {',\r
+' return window.innerHeight;',\r
+' } else if (document.documentElement && document.documentElement.clientHeight) {',\r
+' return document.documentElement.clientHeight;',\r
+' } else if (document.body) {',\r
+' return document.body.clientHeight;',\r
+' }',\r
+' return 0;',\r
+' }',\r
+'',\r
+' function getChromeHeight() {',\r
+' return $("toolbar").offsetHeight;',\r
+' }',\r
+'',\r
+' function setLogContainerHeight() {',\r
+' var windowHeight = getWindowHeight();',\r
+' $("body").style.height = getWindowHeight() + "px";',\r
+' getLogContainer().style.height = "" +',\r
+' Math.max(0, windowHeight - getChromeHeight()) + "px";',\r
+' }',\r
+'',\r
+' window.onresize = function() {',\r
+' setLogContainerHeight();',\r
+' };',\r
+'',\r
+' //]]>',\r
+' </script>',\r
+' <style type="text/css">',\r
+' body {',\r
+' background-color: white;',\r
+' color: black;',\r
+' padding: 0;',\r
+' margin: 0;',\r
+' font-family: tahoma, verdana, arial, helvetica, sans-serif;',\r
+' overflow: hidden;',\r
+' }',\r
+' ',\r
+' div#toolbar {',\r
+' border-top: solid #ffffff 1px;',\r
+' border-bottom: solid #aca899 1px;',\r
+' background-color: #f1efe7;',\r
+' padding: 3px 5px;',\r
+' font-size: 68.75%;',\r
+' }',\r
+'',\r
+' div#toolbar input.button {',\r
+' padding: 0 5px;',\r
+' font-size: 100%;',\r
+' }',\r
+'',\r
+' div#log {',\r
+' font-family: Courier New, Courier;',\r
+' font-size: 75%;',\r
+' width: 100%;',\r
+' overflow: auto;',\r
+' clear: both;',\r
+' }',\r
+'',\r
+' *.logentry {',\r
+' overflow: visible;',\r
+' white-space: pre;',\r
+' }',\r
+'',\r
+' *.TRACE {',\r
+' color: #666666;',\r
+' }',\r
+'',\r
+' *.DEBUG {',\r
+' color: green;',\r
+' }',\r
+'',\r
+' *.INFO {',\r
+' color: #000099;',\r
+' }',\r
+'',\r
+' *.WARN {',\r
+' color: #999900;',\r
+' }',\r
+'',\r
+' *.ERROR {',\r
+' color: red;',\r
+' }',\r
+'',\r
+' *.FATAL {',\r
+' color: #660066;',\r
+' }',\r
+'',\r
+' div#log div.separator {',\r
+' background-color: #cccccc;',\r
+' margin: 5px 0;',\r
+' line-height: 1px;',\r
+' }',\r
+' </style>',\r
+' </head>',\r
+'',\r
+' <body id="body">',\r
+' <div id="toolbar">',\r
+' Options:',\r
+' <input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" class="stateful" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Enable logging</label>',\r
+' <input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="stateful button" title="Clear all log messages" />',\r
+' <input type="button" id="closeButton" value="Close" onclick="window.close()" class="stateful button" title="Close the window" />',\r
+' </div>',\r
+' <div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>',\r
+' </body>',\r
+'</html>'\r
+];\r
+ };\r
+\r
+ var popUp = null;\r
+ var popUpsBlocked = false;\r
+ var popUpClosed = false;\r
+ var popUpLoaded = false;\r
+ var complainAboutPopUpBlocking = true;\r
+ var initialized = false;\r
+ var isSupported = true;\r
+ var width = 600;\r
+ var height = 400;\r
+ var focusPopUp = false;\r
+ var queuedLoggingEvents = new Array();\r
+\r
+ function isLoaded(win) {\r
+ try {\r
+ return bool(win.loaded);\r
+ } catch (ex) {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ function finalInit() {\r
+ popUpLoaded = true;\r
+ appendQueuedLoggingEvents();\r
+ }\r
+\r
+ function writeHtml(doc) {\r
+ var lines = getConsoleHtmlLines();\r
+ doc.open();\r
+ for (var i = 0, len = lines.length; i < len; i++) {\r
+ doc.writeln(lines[i]);\r
+ }\r
+ doc.close();\r
+ }\r
+\r
+ function pollConsoleWindow() {\r
+ function pollConsoleWindowLoaded() {\r
+ if (popUpLoaded) {\r
+ clearInterval(poll);\r
+ } else if (bool(popUp) && isLoaded(popUp)) {\r
+ clearInterval(poll);\r
+ finalInit();\r
+ }\r
+ }\r
+\r
+ // Poll the pop-up since the onload event is not reliable\r
+ var poll = setInterval(pollConsoleWindowLoaded, 100);\r
+ }\r
+\r
+ function init() {\r
+ var windowProperties = "width=" + width + ",height=" + height + ",status,resizable";\r
+ var windowName = "log4javascriptLitePopUp" + location.host.replace(/[^a-z0-9]/gi, "_");\r
+\r
+ popUp = window.open("", windowName, windowProperties);\r
+ popUpClosed = false;\r
+ if (popUp) {\r
+ if (isLoaded(popUp)) {\r
+ popUp.mainPageReloaded();\r
+ finalInit();\r
+ } else {\r
+ writeHtml(popUp.document);\r
+\r
+ // Check if the pop-up window object is available\r
+ if (isLoaded(popUp)) {\r
+ finalInit();\r
+ } else {\r
+ pollConsoleWindow();\r
+ }\r
+ }\r
+ } else {\r
+ isSupported = false;\r
+ if (complainAboutPopUpBlocking) {\r
+ alert("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");\r
+ }\r
+ }\r
+ initialized = true;\r
+ }\r
+\r
+ function safeToAppend() {\r
+ if (!popUpsBlocked && !popUpClosed) {\r
+ if (popUp.closed) {\r
+ popUpClosed = true;\r
+ return false;\r
+ }\r
+ if (!popUpLoaded && popUp.loaded) {\r
+ popUpLoaded = true;\r
+ }\r
+ }\r
+ return !popUpsBlocked && popUpLoaded && !popUpClosed;\r
+ }\r
+\r
+ function padWithZeroes(num, len) {\r
+ var str = "" + num;\r
+ while (str.length < len) {\r
+ str = "0" + str;\r
+ }\r
+ return str;\r
+ }\r
+\r
+ function padWithSpaces(str, len) {\r
+ while (str.length < len) {\r
+ str += " ";\r
+ }\r
+ return str;\r
+ }\r
+\r
+ this.append = function(loggingEvent) {\r
+ if (!initialized) {\r
+ init();\r
+ }\r
+ queuedLoggingEvents.push(loggingEvent);\r
+ if (safeToAppend()) {\r
+ appendQueuedLoggingEvents();\r
+ }\r
+ };\r
+\r
+ function appendQueuedLoggingEvents() {\r
+ if (safeToAppend()) {\r
+ while (queuedLoggingEvents.length > 0) {\r
+ var currentLoggingEvent = queuedLoggingEvents.shift();\r
+ var date = currentLoggingEvent.timeStamp;\r
+ var formattedDate = padWithZeroes(date.getHours(), 2) + ":" +\r
+ padWithZeroes(date.getMinutes(), 2) + ":" + padWithZeroes(date.getSeconds(), 2);\r
+ var formattedMessage = formattedDate + " " + padWithSpaces(currentLoggingEvent.level.name, 5) +\r
+ " - " + currentLoggingEvent.getCombinedMessages();\r
+ var throwableStringRep = currentLoggingEvent.getThrowableStrRep();\r
+ if (throwableStringRep) {\r
+ formattedMessage += newLine + throwableStringRep;\r
+ }\r
+ popUp.log(currentLoggingEvent.level, formattedMessage);\r
+ }\r
+ if (focusPopUp) {\r
+ popUp.focus();\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ log4javascript.Appender = Appender;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Loggers\r
+\r
+ function Logger() {\r
+ var appender = new Appender();\r
+ var loggerLevel = Level.ALL;\r
+\r
+ this.log = function(level, params) {\r
+ if (enabled && level.isGreaterOrEqual(this.getLevel())) {\r
+ // Check whether last param is an exception\r
+ var exception;\r
+ var finalParamIndex = params.length - 1;\r
+ var lastParam = params[params.length - 1];\r
+ if (params.length > 1 && isError(lastParam)) {\r
+ exception = lastParam;\r
+ finalParamIndex--;\r
+ }\r
+\r
+ // Construct genuine array for the params\r
+ var messages = [];\r
+ for (var i = 0; i <= finalParamIndex; i++) {\r
+ messages[i] = params[i];\r
+ }\r
+\r
+ var loggingEvent = new LoggingEvent(\r
+ this, new Date(), level, messages, exception);\r
+\r
+ appender.append(loggingEvent);\r
+ }\r
+ };\r
+\r
+ this.setLevel = function(level) {\r
+ loggerLevel = level;\r
+ };\r
+\r
+ this.getLevel = function() {\r
+ return loggerLevel;\r
+ };\r
+ }\r
+\r
+ Logger.prototype = {\r
+ trace: function() {\r
+ this.log(Level.TRACE, arguments);\r
+ },\r
+\r
+ debug: function() {\r
+ this.log(Level.DEBUG, arguments);\r
+ },\r
+\r
+ info: function() {\r
+ this.log(Level.INFO, arguments);\r
+ },\r
+\r
+ warn: function() {\r
+ this.log(Level.WARN, arguments);\r
+ },\r
+\r
+ error: function() {\r
+ this.log(Level.ERROR, arguments);\r
+ },\r
+\r
+ fatal: function() {\r
+ this.log(Level.FATAL, arguments);\r
+ },\r
+\r
+ isEnabledFor: function(level) {\r
+ return level.isGreaterOrEqual(this.getLevel());\r
+ },\r
+\r
+ isTraceEnabled: function() {\r
+ return this.isEnabledFor(Level.TRACE);\r
+ },\r
+\r
+ isDebugEnabled: function() {\r
+ return this.isEnabledFor(Level.DEBUG);\r
+ },\r
+\r
+ isInfoEnabled: function() {\r
+ return this.isEnabledFor(Level.INFO);\r
+ },\r
+\r
+ isWarnEnabled: function() {\r
+ return this.isEnabledFor(Level.WARN);\r
+ },\r
+\r
+ isErrorEnabled: function() {\r
+ return this.isEnabledFor(Level.ERROR);\r
+ },\r
+\r
+ isFatalEnabled: function() {\r
+ return this.isEnabledFor(Level.FATAL);\r
+ }\r
+ };\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Logger access methods\r
+\r
+ var defaultLogger = null;\r
+ log4javascript.getDefaultLogger = function() {\r
+ if (!defaultLogger) {\r
+ defaultLogger = new Logger();\r
+ }\r
+ return defaultLogger;\r
+ };\r
+\r
+ log4javascript.getLogger = log4javascript.getDefaultLogger;\r
+\r
+ var nullLogger = null;\r
+ log4javascript.getNullLogger = function() {\r
+ if (!nullLogger) {\r
+ nullLogger = new Logger();\r
+ nullLogger.setLevel(Level.OFF);\r
+ }\r
+ return nullLogger;\r
+ };\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Logging events\r
+\r
+ var LoggingEvent = function(logger, timeStamp, level, messages,\r
+ exception) {\r
+ this.logger = logger;\r
+ this.timeStamp = timeStamp;\r
+ this.level = level;\r
+ this.messages = messages;\r
+ this.exception = exception;\r
+ };\r
+\r
+ LoggingEvent.prototype = {\r
+ getThrowableStrRep: function() {\r
+ return this.exception ?\r
+ getExceptionStringRep(this.exception) : "";\r
+ },\r
+\r
+ getCombinedMessages: function() {\r
+ return (this.messages.length === 1) ? this.messages[0] :\r
+ this.messages.join(newLine);\r
+ }\r
+ };\r
+\r
+ log4javascript.LoggingEvent = LoggingEvent;\r
+\r
+ // Ensure that the log4javascript object is available in the window. This\r
+ // is necessary for log4javascript to be available in IE if loaded using\r
+ // Dojo's module system\r
+ window.log4javascript = log4javascript;\r
+})();
\ No newline at end of file
--- /dev/null
+/**\r
+ * Copyright 2013 Tim Down.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+\r
+if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}\r
+return this.length;};}\r
+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];}\r
+this.length=this.length-1;return firstItem;}};}\r
+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];}\r
+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]);}\r
+return itemsDeleted;};}\r
+var log4javascript=(function(){function isUndefined(obj){return typeof obj=="undefined";}\r
+function EventSupport(){}\r
+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+"'");}\r
+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+"'");}\r
+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()+"_"+\r
+Math.floor(Math.random()*100000000);var emptyFunction=function(){};var newLine="\r\n";var pageLoaded=false;function Log4JavaScript(){}\r
+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);}}\r
+function getExceptionMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}else{return toStr(ex);}}\r
+function getUrlFileName(url){var lastSlashIndex=Math.max(url.lastIndexOf("/"),url.lastIndexOf("\\"));return url.substr(lastSlashIndex+1);}\r
+function getExceptionStringRep(ex){if(ex){var exStr="Exception: "+getExceptionMessage(ex);try{if(ex.lineNumber){exStr+=" on line number "+ex.lineNumber;}\r
+if(ex.fileName){exStr+=" in file "+getUrlFileName(ex.fileName);}}catch(localEx){logLog.warn("Unable to obtain file and line information for error");}\r
+if(showStackTraces&&ex.stack){exStr+=newLine+"Stack trace:"+newLine+ex.stack;}\r
+return exStr;}\r
+return null;}\r
+function bool(obj){return Boolean(obj);}\r
+function trim(str){return str.replace(/^\s+/,"").replace(/\s+$/,"");}\r
+function splitIntoLines(text){var text2=text.replace(/\r\n/g,"\n").replace(/\r/g,"\n");return text2.split("\n");}\r
+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;}}\r
+if(index>=0){arr.splice(index,1);return true;}else{return false;}}\r
+function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}\r
+return false;}\r
+function extractBooleanFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return bool(param);}}\r
+function extractStringFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return String(param);}}\r
+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;}}}\r
+function extractFunctionFromParam(param,defaultValue){if(typeof param=="function"){return param;}else{return defaultValue;}}\r
+function isError(err){return(err instanceof Error);}\r
+if(!Function.prototype.apply){Function.prototype.apply=function(obj,args){var methodName="__apply__";if(typeof obj[methodName]!="undefined"){methodName+=String(Math.random()).substr(2);}\r
+obj[methodName]=this;var argsStrings=[];for(var i=0,len=args.length;i<len;i++){argsStrings[i]="args["+i+"]";}\r
+var script="obj."+methodName+"("+argsStrings.join(",")+")";var returnValue=eval(script);delete obj[methodName];return returnValue;};}\r
+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];}\r
+return this.apply(obj,args);};}\r
+function getListenersPropertyName(eventName){return"__log4javascript_listeners__"+eventName;}\r
+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);}};}\r
+node[propertyName].push(listener);}}\r
+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);}}}\r
+function getEvent(evt,win){win=win?win:window;return evt?evt:win.event;}\r
+function stopEventPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}\r
+evt.returnValue=false;}\r
+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);}\r
+alert(alertMessage);}}}};log4javascript.logLog=logLog;log4javascript.setEventTypes(["load","error"]);function handleError(message,exception){logLog.error(message,exception);log4javascript.dispatchEvent("error",{"message":message,"exception":exception});}\r
+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();}\r
+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 ('"+\r
+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);}\r
+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;}\r
+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--;}\r
+var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];}\r
+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 "+\r
+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 "+\r
+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]);}\r
+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+"]";};}\r
+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 "+\r
+toStr(loggerName)+" supplied, returning anonymous logger");}\r
+if(loggerName==rootLoggerName){handleError("log4javascript.getLogger: root logger may not be obtained by name");}\r
+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;}\r
+parentLogger.addChild(logger);}\r
+return loggers[loggerName];};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=log4javascript.getLogger(defaultLoggerName);var a=new log4javascript.PopUpAppender();defaultLogger.addAppender(a);}\r
+return defaultLogger;};var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger(nullLoggerName);nullLogger.setLevel(Level.OFF);}\r
+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]);}\r
+if(loggingEvent.exception){dataValues.push([this.exceptionKey,getExceptionStringRep(loggingEvent.exception)]);}\r
+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);}\r
+dataValues.push([this.customFields[i].name,val]);}}\r
+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;}}\r
+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 "+\r
+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 "+\r
+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=[];}\r
+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=[];}\r
+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=[];}\r
+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(/\]\]>/,"]]>]]><![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["+\r
+layout.escapeCdata(message)+"]]></log4javascript:message>";}\r
+var str="<log4javascript:event logger=\""+loggingEvent.logger.name+"\" timestamp=\""+this.getTimeStampValue(loggingEvent)+"\"";if(!this.isTimeStampsInMilliseconds()){str+=" milliseconds=\""+loggingEvent.milliseconds+"\"";}\r
+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;}\r
+str+="</log4javascript:messages>"+newLine;}\r
+if(this.hasCustomFields()){for(i=0,len=this.customFields.length;i<len;i++){str+="<log4javascript:customfield name=\""+\r
+this.customFields[i].name+"\"><![CDATA["+\r
+this.customFields[i].value.toString()+"]]></log4javascript:customfield>"+newLine;}}\r
+if(loggingEvent.exception){str+="<log4javascript:exception><![CDATA["+\r
+getExceptionStringRep(loggingEvent.exception)+"]]></log4javascript:exception>"+newLine;}\r
+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");}\r
+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=[];}\r
+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+=",";}\r
+formattedValue+=layout.lineBreak;}\r
+formattedValue+=prefix+"]";}else if(valType!=="number"&&valType!=="boolean"){formattedValue="\""+escapeNewLines(toStr(val).replace(/\"/g,"\\\""))+"\"";}else{formattedValue=val;}\r
+return formattedValue;}\r
+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+=",";}\r
+str+=this.lineBreak;}\r
+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;}\r
+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));}\r
+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="";}\r
+function formatString(text){var lines=splitIntoLines(text);for(var j=1,jLen=lines.length;j<jLen;j++){lines[j]=indentation+lines[j];}\r
+return lines.join(newLine);}\r
+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);}\r
+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: "+\r
+getExceptionStringRep(ex)+"");}}\r
+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: "+\r
+getExceptionStringRep(ex));}}\r
+expansion+=childLines.join(","+newLine)+newLine+indentation+"}";return expansion;}else{return formatString(toStr(obj));}}\r
+return doFormat(obj,depth,indentation);}\r
+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;}\r
+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--;}\r
+return weekInYear;};Date.prototype.getWeekInMonth=function(minimalDaysInFirstWeek){if(isUndefined(this.minimalDaysInFirstWeek)){minimalDaysInFirstWeek=DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;}\r
+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++;}\r
+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;}\r
+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;}\r
+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);}\r
+break;case MONTH:if(numberOfLetters>=3){formattedString+=formatText(monthNames[rawData],numberOfLetters,numberOfLetters);}else{formattedString+=formatNumber(rawData+1,numberOfLetters);}\r
+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;}}\r
+searchString=searchString.substr(result.index+result[0].length);}\r
+return formattedString;};})();log4javascript.SimpleDateFormat=SimpleDateFormat;function PatternLayout(pattern){if(pattern){this.pattern=pattern;}else{this.pattern=PatternLayout.DEFAULT_CONVERSION_PATTERN;}\r
+this.customFields=[];}\r
+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 '"+\r
+specifier+"' for conversion character '"+conversionCharacter+"' - should be a number");depth=0;}}\r
+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+=" ";}\r
+if(depth===0){replacement+=messages[i];}else{replacement+=formatObjectExpansion(messages[i],depth);}}\r
+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;}\r
+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;}}\r
+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 '"+\r
+specifier+"' for conversion character 'f' - should be a number");}else if(fieldIndex===0){handleError("PatternLayout.format: invalid specifier '"+\r
+specifier+"' for conversion character 'f' - must be greater than zero");}else if(fieldIndex>this.customFields.length){handleError("PatternLayout.format: invalid specifier '"+\r
+specifier+"' for conversion character 'f' - there aren't that many custom fields");}else{fieldIndex=fieldIndex-1;}}\r
+var val=this.customFields[fieldIndex].value;if(typeof val=="function"){val=val(this,loggingEvent);}\r
+replacement=val;}\r
+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;}\r
+var l;if(truncation){l=parseInt(truncation.substr(1),10);var strLen=replacement.length;if(l<strLen){replacement=replacement.substring(strLen-l,strLen);}}\r
+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;}}}\r
+formattedString+=replacement;}\r
+searchString=searchString.substr(result.index+result[0].length);}\r
+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){}}\r
+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;}\r
+function AjaxAppender(url){var appender=this;var isSupported=true;if(!url){handleError("AjaxAppender: URL must be specified in constructor");isSupported=false;}\r
+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 '"+\r
+configOptionName+"' may not be set after the appender has been initialized");return false;}\r
+return true;}\r
+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));}\r
+sending=false;if(timed){scheduleSending();}}}}\r
+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=[];}}\r
+if(batchedLoggingEvents.length>0){queuedRequests.push(batchedLoggingEvents);}\r
+sendingAnything=(queuedRequests.length>0);waitForResponse=false;timed=false;sendAll();}\r
+return sendingAnything;}\r
+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();}\r
+formattedMessages.push(currentFormattedMessage);}\r
+if(batchedLoggingEvents.length==1){postData=formattedMessages.join("");}else{postData=appender.getLayout().batchHeader+\r
+formattedMessages.join(appender.getLayout().batchSeparator)+\r
+appender.getLayout().batchFooter;}\r
+if(contentType==appender.defaults.contentType){postData=appender.getLayout().returnsPostData?postData:urlEncode(postVarName)+"="+urlEncode(postData);if(postData.length>0){postData+="&";}\r
+postData+="layout="+urlEncode(appender.getLayout().toString());}\r
+return postData;}\r
+function scheduleSending(){window.setTimeout(sendAll,timerInterval);}\r
+function xmlHttpErrorHandler(){var msg="AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}}\r
+function sendRequest(postData,successCallback){try{var xmlHttp=getXmlHttp(xmlHttpErrorHandler);if(isSupported){if(xmlHttp.overrideMimeType){xmlHttp.overrideMimeType(appender.getLayout().getContentType());}\r
+xmlHttp.onreadystatechange=function(){if(xmlHttp.readyState==4){if(isHttpRequestSuccessful(xmlHttp)){if(requestSuccessCallback){requestSuccessCallback(xmlHttp);}\r
+if(successCallback){successCallback(xmlHttp);}}else{var msg="AjaxAppender.append: XMLHttpRequest request to URL "+\r
+url+" returned status code "+xmlHttp.status;handleError(msg);if(failCallback){failCallback(msg);}}\r
+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);}\r
+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);}\r
+return;}\r
+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));}}}\r
+this.append=function(loggingEvent){if(isSupported){if(!initialized){init();}\r
+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);}\r
+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();}\r
+if(sendAllRemaining()){return"Sending log messages";}};}\r
+if(timed){scheduleSending();}}}\r
+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);}\r
+log4javascript.setDocumentReady();};}}\r
+window.log4javascript=log4javascript;return log4javascript;})();\r
--- /dev/null
+/**\r
+ * Copyright 2013 Tim Down.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/**\r
+ * log4javascript\r
+ *\r
+ * log4javascript is a logging framework for JavaScript based on log4j\r
+ * for Java. This file contains all core log4javascript code and is the only\r
+ * file required to use log4javascript, unless you require support for\r
+ * document.domain, in which case you will also need console.html, which must be\r
+ * stored in the same directory as the main log4javascript.js file.\r
+ *\r
+ * Author: Tim Down <tim@log4javascript.org>\r
+ * Version: 1.4.6\r
+ * Edition: log4javascript_production\r
+ * Build date: 19 March 2013\r
+ * Website: http://log4javascript.org\r
+ */\r
+\r
+/* -------------------------------------------------------------------------- */\r
+// Array-related stuff\r
+\r
+// Next three methods are solely for IE5, which is missing them\r
+if (!Array.prototype.push) {\r
+ Array.prototype.push = function() {\r
+ for (var i = 0, len = arguments.length; i < len; i++){\r
+ this[this.length] = arguments[i];\r
+ }\r
+ return this.length;\r
+ };\r
+}\r
+\r
+if (!Array.prototype.shift) {\r
+ Array.prototype.shift = function() {\r
+ if (this.length > 0) {\r
+ var firstItem = this[0];\r
+ for (var i = 0, len = this.length - 1; i < len; i++) {\r
+ this[i] = this[i + 1];\r
+ }\r
+ this.length = this.length - 1;\r
+ return firstItem;\r
+ }\r
+ };\r
+}\r
+\r
+if (!Array.prototype.splice) {\r
+ Array.prototype.splice = function(startIndex, deleteCount) {\r
+ var itemsAfterDeleted = this.slice(startIndex + deleteCount);\r
+ var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);\r
+ this.length = startIndex;\r
+ // Copy the arguments into a proper Array object\r
+ var argumentsArray = [];\r
+ for (var i = 0, len = arguments.length; i < len; i++) {\r
+ argumentsArray[i] = arguments[i];\r
+ }\r
+ var itemsToAppend = (argumentsArray.length > 2) ?\r
+ itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;\r
+ for (i = 0, len = itemsToAppend.length; i < len; i++) {\r
+ this.push(itemsToAppend[i]);\r
+ }\r
+ return itemsDeleted;\r
+ };\r
+}\r
+\r
+/* -------------------------------------------------------------------------- */\r
+\r
+var log4javascript = (function() {\r
+\r
+ function isUndefined(obj) {\r
+ return typeof obj == "undefined";\r
+ }\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Custom event support\r
+\r
+ function EventSupport() {}\r
+\r
+ EventSupport.prototype = {\r
+ eventTypes: [],\r
+ eventListeners: {},\r
+ setEventTypes: function(eventTypesParam) {\r
+ if (eventTypesParam instanceof Array) {\r
+ this.eventTypes = eventTypesParam;\r
+ this.eventListeners = {};\r
+ for (var i = 0, len = this.eventTypes.length; i < len; i++) {\r
+ this.eventListeners[this.eventTypes[i]] = [];\r
+ }\r
+ } else {\r
+ handleError("log4javascript.EventSupport [" + this + "]: setEventTypes: eventTypes parameter must be an Array");\r
+ }\r
+ },\r
+\r
+ addEventListener: function(eventType, listener) {\r
+ if (typeof listener == "function") {\r
+ if (!array_contains(this.eventTypes, eventType)) {\r
+ handleError("log4javascript.EventSupport [" + this + "]: addEventListener: no event called '" + eventType + "'");\r
+ }\r
+ this.eventListeners[eventType].push(listener);\r
+ } else {\r
+ handleError("log4javascript.EventSupport [" + this + "]: addEventListener: listener must be a function");\r
+ }\r
+ },\r
+\r
+ removeEventListener: function(eventType, listener) {\r
+ if (typeof listener == "function") {\r
+ if (!array_contains(this.eventTypes, eventType)) {\r
+ handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: no event called '" + eventType + "'");\r
+ }\r
+ array_remove(this.eventListeners[eventType], listener);\r
+ } else {\r
+ handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: listener must be a function");\r
+ }\r
+ },\r
+\r
+ dispatchEvent: function(eventType, eventArgs) {\r
+ if (array_contains(this.eventTypes, eventType)) {\r
+ var listeners = this.eventListeners[eventType];\r
+ for (var i = 0, len = listeners.length; i < len; i++) {\r
+ listeners[i](this, eventType, eventArgs);\r
+ }\r
+ } else {\r
+ handleError("log4javascript.EventSupport [" + this + "]: dispatchEvent: no event called '" + eventType + "'");\r
+ }\r
+ }\r
+ };\r
+\r
+ /* -------------------------------------------------------------------------- */\r
+\r
+ var applicationStartDate = new Date();\r
+ var uniqueId = "log4javascript_" + applicationStartDate.getTime() + "_" +\r
+ Math.floor(Math.random() * 100000000);\r
+ var emptyFunction = function() {};\r
+ var newLine = "\r\n";\r
+ var pageLoaded = false;\r
+\r
+ // Create main log4javascript object; this will be assigned public properties\r
+ function Log4JavaScript() {}\r
+ Log4JavaScript.prototype = new EventSupport();\r
+\r
+ log4javascript = new Log4JavaScript();\r
+ log4javascript.version = "1.4.6";\r
+ log4javascript.edition = "log4javascript_production";\r
+\r
+ /* -------------------------------------------------------------------------- */\r
+ // Utility functions\r
+\r
+ function toStr(obj) {\r
+ if (obj && obj.toString) {\r
+ return obj.toString();\r
+ } else {\r
+ return String(obj);\r
+ }\r
+ }\r
+\r
+ function getExceptionMessage(ex) {\r
+ if (ex.message) {\r
+ return ex.message;\r
+ } else if (ex.description) {\r
+ return ex.description;\r
+ } else {\r
+ return toStr(ex);\r
+ }\r
+ }\r
+\r
+ // Gets the portion of the URL after the last slash\r
+ function getUrlFileName(url) {\r
+ var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\"));\r
+ return url.substr(lastSlashIndex + 1);\r
+ }\r
+\r
+ // Returns a nicely formatted representation of an error\r
+ function getExceptionStringRep(ex) {\r
+ if (ex) {\r
+ var exStr = "Exception: " + getExceptionMessage(ex);\r
+ try {\r
+ if (ex.lineNumber) {\r
+ exStr += " on line number " + ex.lineNumber;\r
+ }\r
+ if (ex.fileName) {\r
+ exStr += " in file " + getUrlFileName(ex.fileName);\r
+ }\r
+ } catch (localEx) {\r
+ logLog.warn("Unable to obtain file and line information for error");\r
+ }\r
+ if (showStackTraces && ex.stack) {\r
+ exStr += newLine + "Stack trace:" + newLine + ex.stack;\r
+ }\r
+ return exStr;\r
+ }\r
+ return null;\r
+ }\r
+\r
+ function bool(obj) {\r
+ return Boolean(obj);\r
+ }\r
+\r
+ function trim(str) {\r
+ return str.replace(/^\s+/, "").replace(/\s+$/, "");\r
+ }\r
+\r
+ function splitIntoLines(text) {\r
+ // Ensure all line breaks are \n only\r
+ var text2 = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");\r
+ return text2.split("\n");\r
+ }\r
+\r
+ var urlEncode = (typeof window.encodeURIComponent != "undefined") ?\r
+ function(str) {\r
+ return encodeURIComponent(str);\r
+ }: \r
+ function(str) {\r
+ return escape(str).replace(/\+/g, "%2B").replace(/"/g, "%22").replace(/'/g, "%27").replace(/\//g, "%2F").replace(/=/g, "%3D");\r
+ };\r
+\r
+ var urlDecode = (typeof window.decodeURIComponent != "undefined") ?\r
+ function(str) {\r
+ return decodeURIComponent(str);\r
+ }: \r
+ function(str) {\r
+ return unescape(str).replace(/%2B/g, "+").replace(/%22/g, "\"").replace(/%27/g, "'").replace(/%2F/g, "/").replace(/%3D/g, "=");\r
+ };\r
+\r
+ function array_remove(arr, val) {\r
+ var index = -1;\r
+ for (var i = 0, len = arr.length; i < len; i++) {\r
+ if (arr[i] === val) {\r
+ index = i;\r
+ break;\r
+ }\r
+ }\r
+ if (index >= 0) {\r
+ arr.splice(index, 1);\r
+ return true;\r
+ } else {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ function array_contains(arr, val) {\r
+ for(var i = 0, len = arr.length; i < len; i++) {\r
+ if (arr[i] == val) {\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+\r
+ function extractBooleanFromParam(param, defaultValue) {\r
+ if (isUndefined(param)) {\r
+ return defaultValue;\r
+ } else {\r
+ return bool(param);\r
+ }\r
+ }\r
+\r
+ function extractStringFromParam(param, defaultValue) {\r
+ if (isUndefined(param)) {\r
+ return defaultValue;\r
+ } else {\r
+ return String(param);\r
+ }\r
+ }\r
+\r
+ function extractIntFromParam(param, defaultValue) {\r
+ if (isUndefined(param)) {\r
+ return defaultValue;\r
+ } else {\r
+ try {\r
+ var value = parseInt(param, 10);\r
+ return isNaN(value) ? defaultValue : value;\r
+ } catch (ex) {\r
+ logLog.warn("Invalid int param " + param, ex);\r
+ return defaultValue;\r
+ }\r
+ }\r
+ }\r
+\r
+ function extractFunctionFromParam(param, defaultValue) {\r
+ if (typeof param == "function") {\r
+ return param;\r
+ } else {\r
+ return defaultValue;\r
+ }\r
+ }\r
+\r
+ function isError(err) {\r
+ return (err instanceof Error);\r
+ }\r
+\r
+ if (!Function.prototype.apply){\r
+ Function.prototype.apply = function(obj, args) {\r
+ var methodName = "__apply__";\r
+ if (typeof obj[methodName] != "undefined") {\r
+ methodName += String(Math.random()).substr(2);\r
+ }\r
+ obj[methodName] = this;\r
+\r
+ var argsStrings = [];\r
+ for (var i = 0, len = args.length; i < len; i++) {\r
+ argsStrings[i] = "args[" + i + "]";\r
+ }\r
+ var script = "obj." + methodName + "(" + argsStrings.join(",") + ")";\r
+ var returnValue = eval(script);\r
+ delete obj[methodName];\r
+ return returnValue;\r
+ };\r
+ }\r
+\r
+ if (!Function.prototype.call){\r
+ Function.prototype.call = function(obj) {\r
+ var args = [];\r
+ for (var i = 1, len = arguments.length; i < len; i++) {\r
+ args[i - 1] = arguments[i];\r
+ }\r
+ return this.apply(obj, args);\r
+ };\r
+ }\r
+\r
+ function getListenersPropertyName(eventName) {\r
+ return "__log4javascript_listeners__" + eventName;\r
+ }\r
+\r
+ function addEvent(node, eventName, listener, useCapture, win) {\r
+ win = win ? win : window;\r
+ if (node.addEventListener) {\r
+ node.addEventListener(eventName, listener, useCapture);\r
+ } else if (node.attachEvent) {\r
+ node.attachEvent("on" + eventName, listener);\r
+ } else {\r
+ var propertyName = getListenersPropertyName(eventName);\r
+ if (!node[propertyName]) {\r
+ node[propertyName] = [];\r
+ // Set event handler\r
+ node["on" + eventName] = function(evt) {\r
+ evt = getEvent(evt, win);\r
+ var listenersPropertyName = getListenersPropertyName(eventName);\r
+\r
+ // Clone the array of listeners to leave the original untouched\r
+ var listeners = this[listenersPropertyName].concat([]);\r
+ var currentListener;\r
+\r
+ // Call each listener in turn\r
+ while ((currentListener = listeners.shift())) {\r
+ currentListener.call(this, evt);\r
+ }\r
+ };\r
+ }\r
+ node[propertyName].push(listener);\r
+ }\r
+ }\r
+\r
+ function removeEvent(node, eventName, listener, useCapture) {\r
+ if (node.removeEventListener) {\r
+ node.removeEventListener(eventName, listener, useCapture);\r
+ } else if (node.detachEvent) {\r
+ node.detachEvent("on" + eventName, listener);\r
+ } else {\r
+ var propertyName = getListenersPropertyName(eventName);\r
+ if (node[propertyName]) {\r
+ array_remove(node[propertyName], listener);\r
+ }\r
+ }\r
+ }\r
+\r
+ function getEvent(evt, win) {\r
+ win = win ? win : window;\r
+ return evt ? evt : win.event;\r
+ }\r
+\r
+ function stopEventPropagation(evt) {\r
+ if (evt.stopPropagation) {\r
+ evt.stopPropagation();\r
+ } else if (typeof evt.cancelBubble != "undefined") {\r
+ evt.cancelBubble = true;\r
+ }\r
+ evt.returnValue = false;\r
+ }\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Simple logging for log4javascript itself\r
+\r
+ var logLog = {\r
+ quietMode: false,\r
+\r
+ debugMessages: [],\r
+\r
+ setQuietMode: function(quietMode) {\r
+ this.quietMode = bool(quietMode);\r
+ },\r
+\r
+ numberOfErrors: 0,\r
+\r
+ alertAllErrors: false,\r
+\r
+ setAlertAllErrors: function(alertAllErrors) {\r
+ this.alertAllErrors = alertAllErrors;\r
+ },\r
+\r
+ debug: function(message) {\r
+ this.debugMessages.push(message);\r
+ },\r
+\r
+ displayDebug: function() {\r
+ alert(this.debugMessages.join(newLine));\r
+ },\r
+\r
+ warn: function(message, exception) {\r
+ },\r
+\r
+ error: function(message, exception) {\r
+ if (++this.numberOfErrors == 1 || this.alertAllErrors) {\r
+ if (!this.quietMode) {\r
+ var alertMessage = "log4javascript error: " + message;\r
+ if (exception) {\r
+ alertMessage += newLine + newLine + "Original error: " + getExceptionStringRep(exception);\r
+ }\r
+ alert(alertMessage);\r
+ }\r
+ }\r
+ }\r
+ };\r
+ log4javascript.logLog = logLog;\r
+\r
+ log4javascript.setEventTypes(["load", "error"]);\r
+\r
+ function handleError(message, exception) {\r
+ logLog.error(message, exception);\r
+ log4javascript.dispatchEvent("error", { "message": message, "exception": exception });\r
+ }\r
+\r
+ log4javascript.handleError = handleError;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+\r
+ var enabled = !((typeof log4javascript_disabled != "undefined") &&\r
+ log4javascript_disabled);\r
+\r
+ log4javascript.setEnabled = function(enable) {\r
+ enabled = bool(enable);\r
+ };\r
+\r
+ log4javascript.isEnabled = function() {\r
+ return enabled;\r
+ };\r
+\r
+ var useTimeStampsInMilliseconds = true;\r
+\r
+ log4javascript.setTimeStampsInMilliseconds = function(timeStampsInMilliseconds) {\r
+ useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);\r
+ };\r
+\r
+ log4javascript.isTimeStampsInMilliseconds = function() {\r
+ return useTimeStampsInMilliseconds;\r
+ };\r
+ \r
+\r
+ // This evaluates the given expression in the current scope, thus allowing\r
+ // scripts to access private variables. Particularly useful for testing\r
+ log4javascript.evalInScope = function(expr) {\r
+ return eval(expr);\r
+ };\r
+\r
+ var showStackTraces = false;\r
+\r
+ log4javascript.setShowStackTraces = function(show) {\r
+ showStackTraces = bool(show);\r
+ };\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Levels\r
+\r
+ var Level = function(level, name) {\r
+ this.level = level;\r
+ this.name = name;\r
+ };\r
+\r
+ Level.prototype = {\r
+ toString: function() {\r
+ return this.name;\r
+ },\r
+ equals: function(level) {\r
+ return this.level == level.level;\r
+ },\r
+ isGreaterOrEqual: function(level) {\r
+ return this.level >= level.level;\r
+ }\r
+ };\r
+\r
+ Level.ALL = new Level(Number.MIN_VALUE, "ALL");\r
+ Level.TRACE = new Level(10000, "TRACE");\r
+ Level.DEBUG = new Level(20000, "DEBUG");\r
+ Level.INFO = new Level(30000, "INFO");\r
+ Level.WARN = new Level(40000, "WARN");\r
+ Level.ERROR = new Level(50000, "ERROR");\r
+ Level.FATAL = new Level(60000, "FATAL");\r
+ Level.OFF = new Level(Number.MAX_VALUE, "OFF");\r
+\r
+ log4javascript.Level = Level;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Timers\r
+\r
+ function Timer(name, level) {\r
+ this.name = name;\r
+ this.level = isUndefined(level) ? Level.INFO : level;\r
+ this.start = new Date();\r
+ }\r
+\r
+ Timer.prototype.getElapsedTime = function() {\r
+ return new Date().getTime() - this.start.getTime();\r
+ };\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Loggers\r
+\r
+ var anonymousLoggerName = "[anonymous]";\r
+ var defaultLoggerName = "[default]";\r
+ var nullLoggerName = "[null]";\r
+ var rootLoggerName = "root";\r
+\r
+ function Logger(name) {\r
+ this.name = name;\r
+ this.parent = null;\r
+ this.children = [];\r
+\r
+ var appenders = [];\r
+ var loggerLevel = null;\r
+ var isRoot = (this.name === rootLoggerName);\r
+ var isNull = (this.name === nullLoggerName);\r
+\r
+ var appenderCache = null;\r
+ var appenderCacheInvalidated = false;\r
+ \r
+ this.addChild = function(childLogger) {\r
+ this.children.push(childLogger);\r
+ childLogger.parent = this;\r
+ childLogger.invalidateAppenderCache();\r
+ };\r
+\r
+ // Additivity\r
+ var additive = true;\r
+ this.getAdditivity = function() {\r
+ return additive;\r
+ };\r
+\r
+ this.setAdditivity = function(additivity) {\r
+ var valueChanged = (additive != additivity);\r
+ additive = additivity;\r
+ if (valueChanged) {\r
+ this.invalidateAppenderCache();\r
+ }\r
+ };\r
+\r
+ // Create methods that use the appenders variable in this scope\r
+ this.addAppender = function(appender) {\r
+ if (isNull) {\r
+ handleError("Logger.addAppender: you may not add an appender to the null logger");\r
+ } else {\r
+ if (appender instanceof log4javascript.Appender) {\r
+ if (!array_contains(appenders, appender)) {\r
+ appenders.push(appender);\r
+ appender.setAddedToLogger(this);\r
+ this.invalidateAppenderCache();\r
+ }\r
+ } else {\r
+ handleError("Logger.addAppender: appender supplied ('" +\r
+ toStr(appender) + "') is not a subclass of Appender");\r
+ }\r
+ }\r
+ };\r
+\r
+ this.removeAppender = function(appender) {\r
+ array_remove(appenders, appender);\r
+ appender.setRemovedFromLogger(this);\r
+ this.invalidateAppenderCache();\r
+ };\r
+\r
+ this.removeAllAppenders = function() {\r
+ var appenderCount = appenders.length;\r
+ if (appenderCount > 0) {\r
+ for (var i = 0; i < appenderCount; i++) {\r
+ appenders[i].setRemovedFromLogger(this);\r
+ }\r
+ appenders.length = 0;\r
+ this.invalidateAppenderCache();\r
+ }\r
+ };\r
+\r
+ this.getEffectiveAppenders = function() {\r
+ if (appenderCache === null || appenderCacheInvalidated) {\r
+ // Build appender cache\r
+ var parentEffectiveAppenders = (isRoot || !this.getAdditivity()) ?\r
+ [] : this.parent.getEffectiveAppenders();\r
+ appenderCache = parentEffectiveAppenders.concat(appenders);\r
+ appenderCacheInvalidated = false;\r
+ }\r
+ return appenderCache;\r
+ };\r
+ \r
+ this.invalidateAppenderCache = function() {\r
+ appenderCacheInvalidated = true;\r
+ for (var i = 0, len = this.children.length; i < len; i++) {\r
+ this.children[i].invalidateAppenderCache();\r
+ }\r
+ };\r
+\r
+ this.log = function(level, params) {\r
+ if (enabled && level.isGreaterOrEqual(this.getEffectiveLevel())) {\r
+ // Check whether last param is an exception\r
+ var exception;\r
+ var finalParamIndex = params.length - 1;\r
+ var lastParam = params[finalParamIndex];\r
+ if (params.length > 1 && isError(lastParam)) {\r
+ exception = lastParam;\r
+ finalParamIndex--;\r
+ }\r
+\r
+ // Construct genuine array for the params\r
+ var messages = [];\r
+ for (var i = 0; i <= finalParamIndex; i++) {\r
+ messages[i] = params[i];\r
+ }\r
+\r
+ var loggingEvent = new LoggingEvent(\r
+ this, new Date(), level, messages, exception);\r
+\r
+ this.callAppenders(loggingEvent);\r
+ }\r
+ };\r
+\r
+ this.callAppenders = function(loggingEvent) {\r
+ var effectiveAppenders = this.getEffectiveAppenders();\r
+ for (var i = 0, len = effectiveAppenders.length; i < len; i++) {\r
+ effectiveAppenders[i].doAppend(loggingEvent);\r
+ }\r
+ };\r
+\r
+ this.setLevel = function(level) {\r
+ // Having a level of null on the root logger would be very bad.\r
+ if (isRoot && level === null) {\r
+ handleError("Logger.setLevel: you cannot set the level of the root logger to null");\r
+ } else if (level instanceof Level) {\r
+ loggerLevel = level;\r
+ } else {\r
+ handleError("Logger.setLevel: level supplied to logger " +\r
+ this.name + " is not an instance of log4javascript.Level");\r
+ }\r
+ };\r
+\r
+ this.getLevel = function() {\r
+ return loggerLevel;\r
+ };\r
+\r
+ this.getEffectiveLevel = function() {\r
+ for (var logger = this; logger !== null; logger = logger.parent) {\r
+ var level = logger.getLevel();\r
+ if (level !== null) {\r
+ return level;\r
+ }\r
+ }\r
+ };\r
+\r
+ this.group = function(name, initiallyExpanded) {\r
+ if (enabled) {\r
+ var effectiveAppenders = this.getEffectiveAppenders();\r
+ for (var i = 0, len = effectiveAppenders.length; i < len; i++) {\r
+ effectiveAppenders[i].group(name, initiallyExpanded);\r
+ }\r
+ }\r
+ };\r
+\r
+ this.groupEnd = function() {\r
+ if (enabled) {\r
+ var effectiveAppenders = this.getEffectiveAppenders();\r
+ for (var i = 0, len = effectiveAppenders.length; i < len; i++) {\r
+ effectiveAppenders[i].groupEnd();\r
+ }\r
+ }\r
+ };\r
+\r
+ var timers = {};\r
+\r
+ this.time = function(name, level) {\r
+ if (enabled) {\r
+ if (isUndefined(name)) {\r
+ handleError("Logger.time: a name for the timer must be supplied");\r
+ } else if (level && !(level instanceof Level)) {\r
+ handleError("Logger.time: level supplied to timer " +\r
+ name + " is not an instance of log4javascript.Level");\r
+ } else {\r
+ timers[name] = new Timer(name, level);\r
+ }\r
+ }\r
+ };\r
+\r
+ this.timeEnd = function(name) {\r
+ if (enabled) {\r
+ if (isUndefined(name)) {\r
+ handleError("Logger.timeEnd: a name for the timer must be supplied");\r
+ } else if (timers[name]) {\r
+ var timer = timers[name];\r
+ var milliseconds = timer.getElapsedTime();\r
+ this.log(timer.level, ["Timer " + toStr(name) + " completed in " + milliseconds + "ms"]);\r
+ delete timers[name];\r
+ } else {\r
+ logLog.warn("Logger.timeEnd: no timer found with name " + name);\r
+ }\r
+ }\r
+ };\r
+\r
+ this.assert = function(expr) {\r
+ if (enabled && !expr) {\r
+ var args = [];\r
+ for (var i = 1, len = arguments.length; i < len; i++) {\r
+ args.push(arguments[i]);\r
+ }\r
+ args = (args.length > 0) ? args : ["Assertion Failure"];\r
+ args.push(newLine);\r
+ args.push(expr);\r
+ this.log(Level.ERROR, args);\r
+ }\r
+ };\r
+\r
+ this.toString = function() {\r
+ return "Logger[" + this.name + "]";\r
+ };\r
+ }\r
+\r
+ Logger.prototype = {\r
+ trace: function() {\r
+ this.log(Level.TRACE, arguments);\r
+ },\r
+\r
+ debug: function() {\r
+ this.log(Level.DEBUG, arguments);\r
+ },\r
+\r
+ info: function() {\r
+ this.log(Level.INFO, arguments);\r
+ },\r
+\r
+ warn: function() {\r
+ this.log(Level.WARN, arguments);\r
+ },\r
+\r
+ error: function() {\r
+ this.log(Level.ERROR, arguments);\r
+ },\r
+\r
+ fatal: function() {\r
+ this.log(Level.FATAL, arguments);\r
+ },\r
+\r
+ isEnabledFor: function(level) {\r
+ return level.isGreaterOrEqual(this.getEffectiveLevel());\r
+ },\r
+\r
+ isTraceEnabled: function() {\r
+ return this.isEnabledFor(Level.TRACE);\r
+ },\r
+\r
+ isDebugEnabled: function() {\r
+ return this.isEnabledFor(Level.DEBUG);\r
+ },\r
+\r
+ isInfoEnabled: function() {\r
+ return this.isEnabledFor(Level.INFO);\r
+ },\r
+\r
+ isWarnEnabled: function() {\r
+ return this.isEnabledFor(Level.WARN);\r
+ },\r
+\r
+ isErrorEnabled: function() {\r
+ return this.isEnabledFor(Level.ERROR);\r
+ },\r
+\r
+ isFatalEnabled: function() {\r
+ return this.isEnabledFor(Level.FATAL);\r
+ }\r
+ };\r
+\r
+ Logger.prototype.trace.isEntryPoint = true;\r
+ Logger.prototype.debug.isEntryPoint = true;\r
+ Logger.prototype.info.isEntryPoint = true;\r
+ Logger.prototype.warn.isEntryPoint = true;\r
+ Logger.prototype.error.isEntryPoint = true;\r
+ Logger.prototype.fatal.isEntryPoint = true;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Logger access methods\r
+\r
+ // Hashtable of loggers keyed by logger name\r
+ var loggers = {};\r
+ var loggerNames = [];\r
+\r
+ var ROOT_LOGGER_DEFAULT_LEVEL = Level.DEBUG;\r
+ var rootLogger = new Logger(rootLoggerName);\r
+ rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);\r
+\r
+ log4javascript.getRootLogger = function() {\r
+ return rootLogger;\r
+ };\r
+\r
+ log4javascript.getLogger = function(loggerName) {\r
+ // Use default logger if loggerName is not specified or invalid\r
+ if (!(typeof loggerName == "string")) {\r
+ loggerName = anonymousLoggerName;\r
+ logLog.warn("log4javascript.getLogger: non-string logger name " +\r
+ toStr(loggerName) + " supplied, returning anonymous logger");\r
+ }\r
+\r
+ // Do not allow retrieval of the root logger by name\r
+ if (loggerName == rootLoggerName) {\r
+ handleError("log4javascript.getLogger: root logger may not be obtained by name");\r
+ }\r
+\r
+ // Create the logger for this name if it doesn't already exist\r
+ if (!loggers[loggerName]) {\r
+ var logger = new Logger(loggerName);\r
+ loggers[loggerName] = logger;\r
+ loggerNames.push(loggerName);\r
+\r
+ // Set up parent logger, if it doesn't exist\r
+ var lastDotIndex = loggerName.lastIndexOf(".");\r
+ var parentLogger;\r
+ if (lastDotIndex > -1) {\r
+ var parentLoggerName = loggerName.substring(0, lastDotIndex);\r
+ parentLogger = log4javascript.getLogger(parentLoggerName); // Recursively sets up grandparents etc.\r
+ } else {\r
+ parentLogger = rootLogger;\r
+ }\r
+ parentLogger.addChild(logger);\r
+ }\r
+ return loggers[loggerName];\r
+ };\r
+\r
+ var defaultLogger = null;\r
+ log4javascript.getDefaultLogger = function() {\r
+ if (!defaultLogger) {\r
+ defaultLogger = log4javascript.getLogger(defaultLoggerName);\r
+ var a = new log4javascript.PopUpAppender();\r
+ defaultLogger.addAppender(a);\r
+ }\r
+ return defaultLogger;\r
+ };\r
+\r
+ var nullLogger = null;\r
+ log4javascript.getNullLogger = function() {\r
+ if (!nullLogger) {\r
+ nullLogger = new Logger(nullLoggerName);\r
+ nullLogger.setLevel(Level.OFF);\r
+ }\r
+ return nullLogger;\r
+ };\r
+\r
+ // Destroys all loggers\r
+ log4javascript.resetConfiguration = function() {\r
+ rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);\r
+ loggers = {};\r
+ };\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Logging events\r
+\r
+ var LoggingEvent = function(logger, timeStamp, level, messages,\r
+ exception) {\r
+ this.logger = logger;\r
+ this.timeStamp = timeStamp;\r
+ this.timeStampInMilliseconds = timeStamp.getTime();\r
+ this.timeStampInSeconds = Math.floor(this.timeStampInMilliseconds / 1000);\r
+ this.milliseconds = this.timeStamp.getMilliseconds();\r
+ this.level = level;\r
+ this.messages = messages;\r
+ this.exception = exception;\r
+ };\r
+\r
+ LoggingEvent.prototype = {\r
+ getThrowableStrRep: function() {\r
+ return this.exception ?\r
+ getExceptionStringRep(this.exception) : "";\r
+ },\r
+ getCombinedMessages: function() {\r
+ return (this.messages.length == 1) ? this.messages[0] :\r
+ this.messages.join(newLine);\r
+ },\r
+ toString: function() {\r
+ return "LoggingEvent[" + this.level + "]";\r
+ }\r
+ };\r
+\r
+ log4javascript.LoggingEvent = LoggingEvent;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Layout prototype\r
+\r
+ var Layout = function() {\r
+ };\r
+\r
+ Layout.prototype = {\r
+ defaults: {\r
+ loggerKey: "logger",\r
+ timeStampKey: "timestamp",\r
+ millisecondsKey: "milliseconds",\r
+ levelKey: "level",\r
+ messageKey: "message",\r
+ exceptionKey: "exception",\r
+ urlKey: "url"\r
+ },\r
+ loggerKey: "logger",\r
+ timeStampKey: "timestamp",\r
+ millisecondsKey: "milliseconds",\r
+ levelKey: "level",\r
+ messageKey: "message",\r
+ exceptionKey: "exception",\r
+ urlKey: "url",\r
+ batchHeader: "",\r
+ batchFooter: "",\r
+ batchSeparator: "",\r
+ returnsPostData: false,\r
+ overrideTimeStampsSetting: false,\r
+ useTimeStampsInMilliseconds: null,\r
+\r
+ format: function() {\r
+ handleError("Layout.format: layout supplied has no format() method");\r
+ },\r
+\r
+ ignoresThrowable: function() {\r
+ handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");\r
+ },\r
+\r
+ getContentType: function() {\r
+ return "text/plain";\r
+ },\r
+\r
+ allowBatching: function() {\r
+ return true;\r
+ },\r
+\r
+ setTimeStampsInMilliseconds: function(timeStampsInMilliseconds) {\r
+ this.overrideTimeStampsSetting = true;\r
+ this.useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);\r
+ },\r
+\r
+ isTimeStampsInMilliseconds: function() {\r
+ return this.overrideTimeStampsSetting ?\r
+ this.useTimeStampsInMilliseconds : useTimeStampsInMilliseconds;\r
+ },\r
+\r
+ getTimeStampValue: function(loggingEvent) {\r
+ return this.isTimeStampsInMilliseconds() ?\r
+ loggingEvent.timeStampInMilliseconds : loggingEvent.timeStampInSeconds;\r
+ },\r
+\r
+ getDataValues: function(loggingEvent, combineMessages) {\r
+ var dataValues = [\r
+ [this.loggerKey, loggingEvent.logger.name],\r
+ [this.timeStampKey, this.getTimeStampValue(loggingEvent)],\r
+ [this.levelKey, loggingEvent.level.name],\r
+ [this.urlKey, window.location.href],\r
+ [this.messageKey, combineMessages ? loggingEvent.getCombinedMessages() : loggingEvent.messages]\r
+ ];\r
+ if (!this.isTimeStampsInMilliseconds()) {\r
+ dataValues.push([this.millisecondsKey, loggingEvent.milliseconds]);\r
+ }\r
+ if (loggingEvent.exception) {\r
+ dataValues.push([this.exceptionKey, getExceptionStringRep(loggingEvent.exception)]);\r
+ }\r
+ if (this.hasCustomFields()) {\r
+ for (var i = 0, len = this.customFields.length; i < len; i++) {\r
+ var val = this.customFields[i].value;\r
+\r
+ // Check if the value is a function. If so, execute it, passing it the\r
+ // current layout and the logging event\r
+ if (typeof val === "function") {\r
+ val = val(this, loggingEvent);\r
+ }\r
+ dataValues.push([this.customFields[i].name, val]);\r
+ }\r
+ }\r
+ return dataValues;\r
+ },\r
+\r
+ setKeys: function(loggerKey, timeStampKey, levelKey, messageKey,\r
+ exceptionKey, urlKey, millisecondsKey) {\r
+ this.loggerKey = extractStringFromParam(loggerKey, this.defaults.loggerKey);\r
+ this.timeStampKey = extractStringFromParam(timeStampKey, this.defaults.timeStampKey);\r
+ this.levelKey = extractStringFromParam(levelKey, this.defaults.levelKey);\r
+ this.messageKey = extractStringFromParam(messageKey, this.defaults.messageKey);\r
+ this.exceptionKey = extractStringFromParam(exceptionKey, this.defaults.exceptionKey);\r
+ this.urlKey = extractStringFromParam(urlKey, this.defaults.urlKey);\r
+ this.millisecondsKey = extractStringFromParam(millisecondsKey, this.defaults.millisecondsKey);\r
+ },\r
+\r
+ setCustomField: function(name, value) {\r
+ var fieldUpdated = false;\r
+ for (var i = 0, len = this.customFields.length; i < len; i++) {\r
+ if (this.customFields[i].name === name) {\r
+ this.customFields[i].value = value;\r
+ fieldUpdated = true;\r
+ }\r
+ }\r
+ if (!fieldUpdated) {\r
+ this.customFields.push({"name": name, "value": value});\r
+ }\r
+ },\r
+\r
+ hasCustomFields: function() {\r
+ return (this.customFields.length > 0);\r
+ },\r
+\r
+ toString: function() {\r
+ handleError("Layout.toString: all layouts must override this method");\r
+ }\r
+ };\r
+\r
+ log4javascript.Layout = Layout;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Appender prototype\r
+\r
+ var Appender = function() {};\r
+\r
+ Appender.prototype = new EventSupport();\r
+\r
+ Appender.prototype.layout = new PatternLayout();\r
+ Appender.prototype.threshold = Level.ALL;\r
+ Appender.prototype.loggers = [];\r
+\r
+ // Performs threshold checks before delegating actual logging to the\r
+ // subclass's specific append method.\r
+ Appender.prototype.doAppend = function(loggingEvent) {\r
+ if (enabled && loggingEvent.level.level >= this.threshold.level) {\r
+ this.append(loggingEvent);\r
+ }\r
+ };\r
+\r
+ Appender.prototype.append = function(loggingEvent) {};\r
+\r
+ Appender.prototype.setLayout = function(layout) {\r
+ if (layout instanceof Layout) {\r
+ this.layout = layout;\r
+ } else {\r
+ handleError("Appender.setLayout: layout supplied to " +\r
+ this.toString() + " is not a subclass of Layout");\r
+ }\r
+ };\r
+\r
+ Appender.prototype.getLayout = function() {\r
+ return this.layout;\r
+ };\r
+\r
+ Appender.prototype.setThreshold = function(threshold) {\r
+ if (threshold instanceof Level) {\r
+ this.threshold = threshold;\r
+ } else {\r
+ handleError("Appender.setThreshold: threshold supplied to " +\r
+ this.toString() + " is not a subclass of Level");\r
+ }\r
+ };\r
+\r
+ Appender.prototype.getThreshold = function() {\r
+ return this.threshold;\r
+ };\r
+\r
+ Appender.prototype.setAddedToLogger = function(logger) {\r
+ this.loggers.push(logger);\r
+ };\r
+\r
+ Appender.prototype.setRemovedFromLogger = function(logger) {\r
+ array_remove(this.loggers, logger);\r
+ };\r
+\r
+ Appender.prototype.group = emptyFunction;\r
+ Appender.prototype.groupEnd = emptyFunction;\r
+\r
+ Appender.prototype.toString = function() {\r
+ handleError("Appender.toString: all appenders must override this method");\r
+ };\r
+\r
+ log4javascript.Appender = Appender;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // SimpleLayout \r
+\r
+ function SimpleLayout() {\r
+ this.customFields = [];\r
+ }\r
+\r
+ SimpleLayout.prototype = new Layout();\r
+\r
+ SimpleLayout.prototype.format = function(loggingEvent) {\r
+ return loggingEvent.level.name + " - " + loggingEvent.getCombinedMessages();\r
+ };\r
+\r
+ SimpleLayout.prototype.ignoresThrowable = function() {\r
+ return true;\r
+ };\r
+\r
+ SimpleLayout.prototype.toString = function() {\r
+ return "SimpleLayout";\r
+ };\r
+\r
+ log4javascript.SimpleLayout = SimpleLayout;\r
+ /* ----------------------------------------------------------------------- */\r
+ // NullLayout \r
+\r
+ function NullLayout() {\r
+ this.customFields = [];\r
+ }\r
+\r
+ NullLayout.prototype = new Layout();\r
+\r
+ NullLayout.prototype.format = function(loggingEvent) {\r
+ return loggingEvent.messages;\r
+ };\r
+\r
+ NullLayout.prototype.ignoresThrowable = function() {\r
+ return true;\r
+ };\r
+\r
+ NullLayout.prototype.toString = function() {\r
+ return "NullLayout";\r
+ };\r
+\r
+ log4javascript.NullLayout = NullLayout;\r
+/* ---------------------------------------------------------------------- */\r
+ // XmlLayout\r
+\r
+ function XmlLayout(combineMessages) {\r
+ this.combineMessages = extractBooleanFromParam(combineMessages, true);\r
+ this.customFields = [];\r
+ }\r
+\r
+ XmlLayout.prototype = new Layout();\r
+\r
+ XmlLayout.prototype.isCombinedMessages = function() {\r
+ return this.combineMessages;\r
+ };\r
+\r
+ XmlLayout.prototype.getContentType = function() {\r
+ return "text/xml";\r
+ };\r
+\r
+ XmlLayout.prototype.escapeCdata = function(str) {\r
+ return str.replace(/\]\]>/, "]]>]]><![CDATA[");\r
+ };\r
+\r
+ XmlLayout.prototype.format = function(loggingEvent) {\r
+ var layout = this;\r
+ var i, len;\r
+ function formatMessage(message) {\r
+ message = (typeof message === "string") ? message : toStr(message);\r
+ return "<log4javascript:message><![CDATA[" +\r
+ layout.escapeCdata(message) + "]]></log4javascript:message>";\r
+ }\r
+\r
+ var str = "<log4javascript:event logger=\"" + loggingEvent.logger.name +\r
+ "\" timestamp=\"" + this.getTimeStampValue(loggingEvent) + "\"";\r
+ if (!this.isTimeStampsInMilliseconds()) {\r
+ str += " milliseconds=\"" + loggingEvent.milliseconds + "\"";\r
+ }\r
+ str += " level=\"" + loggingEvent.level.name + "\">" + newLine;\r
+ if (this.combineMessages) {\r
+ str += formatMessage(loggingEvent.getCombinedMessages());\r
+ } else {\r
+ str += "<log4javascript:messages>" + newLine;\r
+ for (i = 0, len = loggingEvent.messages.length; i < len; i++) {\r
+ str += formatMessage(loggingEvent.messages[i]) + newLine;\r
+ }\r
+ str += "</log4javascript:messages>" + newLine;\r
+ }\r
+ if (this.hasCustomFields()) {\r
+ for (i = 0, len = this.customFields.length; i < len; i++) {\r
+ str += "<log4javascript:customfield name=\"" +\r
+ this.customFields[i].name + "\"><![CDATA[" +\r
+ this.customFields[i].value.toString() +\r
+ "]]></log4javascript:customfield>" + newLine;\r
+ }\r
+ }\r
+ if (loggingEvent.exception) {\r
+ str += "<log4javascript:exception><![CDATA[" +\r
+ getExceptionStringRep(loggingEvent.exception) +\r
+ "]]></log4javascript:exception>" + newLine;\r
+ }\r
+ str += "</log4javascript:event>" + newLine + newLine;\r
+ return str;\r
+ };\r
+\r
+ XmlLayout.prototype.ignoresThrowable = function() {\r
+ return false;\r
+ };\r
+\r
+ XmlLayout.prototype.toString = function() {\r
+ return "XmlLayout";\r
+ };\r
+\r
+ log4javascript.XmlLayout = XmlLayout;\r
+ /* ---------------------------------------------------------------------- */\r
+ // JsonLayout related\r
+\r
+ function escapeNewLines(str) {\r
+ return str.replace(/\r\n|\r|\n/g, "\\r\\n");\r
+ }\r
+\r
+ function JsonLayout(readable, combineMessages) {\r
+ this.readable = extractBooleanFromParam(readable, false);\r
+ this.combineMessages = extractBooleanFromParam(combineMessages, true);\r
+ this.batchHeader = this.readable ? "[" + newLine : "[";\r
+ this.batchFooter = this.readable ? "]" + newLine : "]";\r
+ this.batchSeparator = this.readable ? "," + newLine : ",";\r
+ this.setKeys();\r
+ this.colon = this.readable ? ": " : ":";\r
+ this.tab = this.readable ? "\t" : "";\r
+ this.lineBreak = this.readable ? newLine : "";\r
+ this.customFields = [];\r
+ }\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // JsonLayout\r
+\r
+ JsonLayout.prototype = new Layout();\r
+\r
+ JsonLayout.prototype.isReadable = function() {\r
+ return this.readable;\r
+ };\r
+\r
+ JsonLayout.prototype.isCombinedMessages = function() {\r
+ return this.combineMessages;\r
+ };\r
+\r
+ JsonLayout.prototype.format = function(loggingEvent) {\r
+ var layout = this;\r
+ var dataValues = this.getDataValues(loggingEvent, this.combineMessages);\r
+ var str = "{" + this.lineBreak;\r
+ var i, len;\r
+\r
+ function formatValue(val, prefix, expand) {\r
+ // Check the type of the data value to decide whether quotation marks\r
+ // or expansion are required\r
+ var formattedValue;\r
+ var valType = typeof val;\r
+ if (val instanceof Date) {\r
+ formattedValue = String(val.getTime());\r
+ } else if (expand && (val instanceof Array)) {\r
+ formattedValue = "[" + layout.lineBreak;\r
+ for (var i = 0, len = val.length; i < len; i++) {\r
+ var childPrefix = prefix + layout.tab;\r
+ formattedValue += childPrefix + formatValue(val[i], childPrefix, false);\r
+ if (i < val.length - 1) {\r
+ formattedValue += ",";\r
+ }\r
+ formattedValue += layout.lineBreak;\r
+ }\r
+ formattedValue += prefix + "]";\r
+ } else if (valType !== "number" && valType !== "boolean") {\r
+ formattedValue = "\"" + escapeNewLines(toStr(val).replace(/\"/g, "\\\"")) + "\"";\r
+ } else {\r
+ formattedValue = val;\r
+ }\r
+ return formattedValue;\r
+ }\r
+\r
+ for (i = 0, len = dataValues.length - 1; i <= len; i++) {\r
+ str += this.tab + "\"" + dataValues[i][0] + "\"" + this.colon + formatValue(dataValues[i][1], this.tab, true);\r
+ if (i < len) {\r
+ str += ",";\r
+ }\r
+ str += this.lineBreak;\r
+ }\r
+\r
+ str += "}" + this.lineBreak;\r
+ return str;\r
+ };\r
+\r
+ JsonLayout.prototype.ignoresThrowable = function() {\r
+ return false;\r
+ };\r
+\r
+ JsonLayout.prototype.toString = function() {\r
+ return "JsonLayout";\r
+ };\r
+\r
+ JsonLayout.prototype.getContentType = function() {\r
+ return "application/json";\r
+ };\r
+\r
+ log4javascript.JsonLayout = JsonLayout;\r
+ /* ---------------------------------------------------------------------- */\r
+ // HttpPostDataLayout\r
+\r
+ function HttpPostDataLayout() {\r
+ this.setKeys();\r
+ this.customFields = [];\r
+ this.returnsPostData = true;\r
+ }\r
+\r
+ HttpPostDataLayout.prototype = new Layout();\r
+\r
+ // Disable batching\r
+ HttpPostDataLayout.prototype.allowBatching = function() {\r
+ return false;\r
+ };\r
+\r
+ HttpPostDataLayout.prototype.format = function(loggingEvent) {\r
+ var dataValues = this.getDataValues(loggingEvent);\r
+ var queryBits = [];\r
+ for (var i = 0, len = dataValues.length; i < len; i++) {\r
+ var val = (dataValues[i][1] instanceof Date) ?\r
+ String(dataValues[i][1].getTime()) : dataValues[i][1];\r
+ queryBits.push(urlEncode(dataValues[i][0]) + "=" + urlEncode(val));\r
+ }\r
+ return queryBits.join("&");\r
+ };\r
+\r
+ HttpPostDataLayout.prototype.ignoresThrowable = function(loggingEvent) {\r
+ return false;\r
+ };\r
+\r
+ HttpPostDataLayout.prototype.toString = function() {\r
+ return "HttpPostDataLayout";\r
+ };\r
+\r
+ log4javascript.HttpPostDataLayout = HttpPostDataLayout;\r
+ /* ---------------------------------------------------------------------- */\r
+ // formatObjectExpansion\r
+\r
+ function formatObjectExpansion(obj, depth, indentation) {\r
+ var objectsExpanded = [];\r
+\r
+ function doFormat(obj, depth, indentation) {\r
+ var i, j, len, childDepth, childIndentation, childLines, expansion,\r
+ childExpansion;\r
+\r
+ if (!indentation) {\r
+ indentation = "";\r
+ }\r
+\r
+ function formatString(text) {\r
+ var lines = splitIntoLines(text);\r
+ for (var j = 1, jLen = lines.length; j < jLen; j++) {\r
+ lines[j] = indentation + lines[j];\r
+ }\r
+ return lines.join(newLine);\r
+ }\r
+\r
+ if (obj === null) {\r
+ return "null";\r
+ } else if (typeof obj == "undefined") {\r
+ return "undefined";\r
+ } else if (typeof obj == "string") {\r
+ return formatString(obj);\r
+ } else if (typeof obj == "object" && array_contains(objectsExpanded, obj)) {\r
+ try {\r
+ expansion = toStr(obj);\r
+ } catch (ex) {\r
+ expansion = "Error formatting property. Details: " + getExceptionStringRep(ex);\r
+ }\r
+ return expansion + " [already expanded]";\r
+ } else if ((obj instanceof Array) && depth > 0) {\r
+ objectsExpanded.push(obj);\r
+ expansion = "[" + newLine;\r
+ childDepth = depth - 1;\r
+ childIndentation = indentation + " ";\r
+ childLines = [];\r
+ for (i = 0, len = obj.length; i < len; i++) {\r
+ try {\r
+ childExpansion = doFormat(obj[i], childDepth, childIndentation);\r
+ childLines.push(childIndentation + childExpansion);\r
+ } catch (ex) {\r
+ childLines.push(childIndentation + "Error formatting array member. Details: " +\r
+ getExceptionStringRep(ex) + "");\r
+ }\r
+ }\r
+ expansion += childLines.join("," + newLine) + newLine + indentation + "]";\r
+ return expansion;\r
+ } else if (Object.prototype.toString.call(obj) == "[object Date]") {\r
+ return obj.toString();\r
+ } else if (typeof obj == "object" && depth > 0) {\r
+ objectsExpanded.push(obj);\r
+ expansion = "{" + newLine;\r
+ childDepth = depth - 1;\r
+ childIndentation = indentation + " ";\r
+ childLines = [];\r
+ for (i in obj) {\r
+ try {\r
+ childExpansion = doFormat(obj[i], childDepth, childIndentation);\r
+ childLines.push(childIndentation + i + ": " + childExpansion);\r
+ } catch (ex) {\r
+ childLines.push(childIndentation + i + ": Error formatting property. Details: " +\r
+ getExceptionStringRep(ex));\r
+ }\r
+ }\r
+ expansion += childLines.join("," + newLine) + newLine + indentation + "}";\r
+ return expansion;\r
+ } else {\r
+ return formatString(toStr(obj));\r
+ }\r
+ }\r
+ return doFormat(obj, depth, indentation);\r
+ }\r
+ /* ---------------------------------------------------------------------- */\r
+ // Date-related stuff\r
+\r
+ var SimpleDateFormat;\r
+\r
+ (function() {\r
+ 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']+)/;\r
+ var monthNames = ["January", "February", "March", "April", "May", "June",\r
+ "July", "August", "September", "October", "November", "December"];\r
+ var dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];\r
+ var TEXT2 = 0, TEXT3 = 1, NUMBER = 2, YEAR = 3, MONTH = 4, TIMEZONE = 5;\r
+ var types = {\r
+ G : TEXT2,\r
+ y : YEAR,\r
+ M : MONTH,\r
+ w : NUMBER,\r
+ W : NUMBER,\r
+ D : NUMBER,\r
+ d : NUMBER,\r
+ F : NUMBER,\r
+ E : TEXT3,\r
+ a : TEXT2,\r
+ H : NUMBER,\r
+ k : NUMBER,\r
+ K : NUMBER,\r
+ h : NUMBER,\r
+ m : NUMBER,\r
+ s : NUMBER,\r
+ S : NUMBER,\r
+ Z : TIMEZONE\r
+ };\r
+ var ONE_DAY = 24 * 60 * 60 * 1000;\r
+ var ONE_WEEK = 7 * ONE_DAY;\r
+ var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK = 1;\r
+\r
+ var newDateAtMidnight = function(year, month, day) {\r
+ var d = new Date(year, month, day, 0, 0, 0);\r
+ d.setMilliseconds(0);\r
+ return d;\r
+ };\r
+\r
+ Date.prototype.getDifference = function(date) {\r
+ return this.getTime() - date.getTime();\r
+ };\r
+\r
+ Date.prototype.isBefore = function(d) {\r
+ return this.getTime() < d.getTime();\r
+ };\r
+\r
+ Date.prototype.getUTCTime = function() {\r
+ return Date.UTC(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours(), this.getMinutes(),\r
+ this.getSeconds(), this.getMilliseconds());\r
+ };\r
+\r
+ Date.prototype.getTimeSince = function(d) {\r
+ return this.getUTCTime() - d.getUTCTime();\r
+ };\r
+\r
+ Date.prototype.getPreviousSunday = function() {\r
+ // Using midday avoids any possibility of DST messing things up\r
+ var midday = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 12, 0, 0);\r
+ var previousSunday = new Date(midday.getTime() - this.getDay() * ONE_DAY);\r
+ return newDateAtMidnight(previousSunday.getFullYear(), previousSunday.getMonth(),\r
+ previousSunday.getDate());\r
+ };\r
+\r
+ Date.prototype.getWeekInYear = function(minimalDaysInFirstWeek) {\r
+ if (isUndefined(this.minimalDaysInFirstWeek)) {\r
+ minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;\r
+ }\r
+ var previousSunday = this.getPreviousSunday();\r
+ var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);\r
+ var numberOfSundays = previousSunday.isBefore(startOfYear) ?\r
+ 0 : 1 + Math.floor(previousSunday.getTimeSince(startOfYear) / ONE_WEEK);\r
+ var numberOfDaysInFirstWeek = 7 - startOfYear.getDay();\r
+ var weekInYear = numberOfSundays;\r
+ if (numberOfDaysInFirstWeek < minimalDaysInFirstWeek) {\r
+ weekInYear--;\r
+ }\r
+ return weekInYear;\r
+ };\r
+\r
+ Date.prototype.getWeekInMonth = function(minimalDaysInFirstWeek) {\r
+ if (isUndefined(this.minimalDaysInFirstWeek)) {\r
+ minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;\r
+ }\r
+ var previousSunday = this.getPreviousSunday();\r
+ var startOfMonth = newDateAtMidnight(this.getFullYear(), this.getMonth(), 1);\r
+ var numberOfSundays = previousSunday.isBefore(startOfMonth) ?\r
+ 0 : 1 + Math.floor(previousSunday.getTimeSince(startOfMonth) / ONE_WEEK);\r
+ var numberOfDaysInFirstWeek = 7 - startOfMonth.getDay();\r
+ var weekInMonth = numberOfSundays;\r
+ if (numberOfDaysInFirstWeek >= minimalDaysInFirstWeek) {\r
+ weekInMonth++;\r
+ }\r
+ return weekInMonth;\r
+ };\r
+\r
+ Date.prototype.getDayInYear = function() {\r
+ var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);\r
+ return 1 + Math.floor(this.getTimeSince(startOfYear) / ONE_DAY);\r
+ };\r
+\r
+ /* ------------------------------------------------------------------ */\r
+\r
+ SimpleDateFormat = function(formatString) {\r
+ this.formatString = formatString;\r
+ };\r
+\r
+ /**\r
+ * Sets the minimum number of days in a week in order for that week to\r
+ * be considered as belonging to a particular month or year\r
+ */\r
+ SimpleDateFormat.prototype.setMinimalDaysInFirstWeek = function(days) {\r
+ this.minimalDaysInFirstWeek = days;\r
+ };\r
+\r
+ SimpleDateFormat.prototype.getMinimalDaysInFirstWeek = function() {\r
+ return isUndefined(this.minimalDaysInFirstWeek) ?\r
+ DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK : this.minimalDaysInFirstWeek;\r
+ };\r
+\r
+ var padWithZeroes = function(str, len) {\r
+ while (str.length < len) {\r
+ str = "0" + str;\r
+ }\r
+ return str;\r
+ };\r
+\r
+ var formatText = function(data, numberOfLetters, minLength) {\r
+ return (numberOfLetters >= 4) ? data : data.substr(0, Math.max(minLength, numberOfLetters));\r
+ };\r
+\r
+ var formatNumber = function(data, numberOfLetters) {\r
+ var dataString = "" + data;\r
+ // Pad with 0s as necessary\r
+ return padWithZeroes(dataString, numberOfLetters);\r
+ };\r
+\r
+ SimpleDateFormat.prototype.format = function(date) {\r
+ var formattedString = "";\r
+ var result;\r
+ var searchString = this.formatString;\r
+ while ((result = regex.exec(searchString))) {\r
+ var quotedString = result[1];\r
+ var patternLetters = result[2];\r
+ var otherLetters = result[3];\r
+ var otherCharacters = result[4];\r
+\r
+ // If the pattern matched is quoted string, output the text between the quotes\r
+ if (quotedString) {\r
+ if (quotedString == "''") {\r
+ formattedString += "'";\r
+ } else {\r
+ formattedString += quotedString.substring(1, quotedString.length - 1);\r
+ }\r
+ } else if (otherLetters) {\r
+ // Swallow non-pattern letters by doing nothing here\r
+ } else if (otherCharacters) {\r
+ // Simply output other characters\r
+ formattedString += otherCharacters;\r
+ } else if (patternLetters) {\r
+ // Replace pattern letters\r
+ var patternLetter = patternLetters.charAt(0);\r
+ var numberOfLetters = patternLetters.length;\r
+ var rawData = "";\r
+ switch(patternLetter) {\r
+ case "G":\r
+ rawData = "AD";\r
+ break;\r
+ case "y":\r
+ rawData = date.getFullYear();\r
+ break;\r
+ case "M":\r
+ rawData = date.getMonth();\r
+ break;\r
+ case "w":\r
+ rawData = date.getWeekInYear(this.getMinimalDaysInFirstWeek());\r
+ break;\r
+ case "W":\r
+ rawData = date.getWeekInMonth(this.getMinimalDaysInFirstWeek());\r
+ break;\r
+ case "D":\r
+ rawData = date.getDayInYear();\r
+ break;\r
+ case "d":\r
+ rawData = date.getDate();\r
+ break;\r
+ case "F":\r
+ rawData = 1 + Math.floor((date.getDate() - 1) / 7);\r
+ break;\r
+ case "E":\r
+ rawData = dayNames[date.getDay()];\r
+ break;\r
+ case "a":\r
+ rawData = (date.getHours() >= 12) ? "PM" : "AM";\r
+ break;\r
+ case "H":\r
+ rawData = date.getHours();\r
+ break;\r
+ case "k":\r
+ rawData = date.getHours() || 24;\r
+ break;\r
+ case "K":\r
+ rawData = date.getHours() % 12;\r
+ break;\r
+ case "h":\r
+ rawData = (date.getHours() % 12) || 12;\r
+ break;\r
+ case "m":\r
+ rawData = date.getMinutes();\r
+ break;\r
+ case "s":\r
+ rawData = date.getSeconds();\r
+ break;\r
+ case "S":\r
+ rawData = date.getMilliseconds();\r
+ break;\r
+ case "Z":\r
+ rawData = date.getTimezoneOffset(); // This returns the number of minutes since GMT was this time.\r
+ break;\r
+ }\r
+ // Format the raw data depending on the type\r
+ switch(types[patternLetter]) {\r
+ case TEXT2:\r
+ formattedString += formatText(rawData, numberOfLetters, 2);\r
+ break;\r
+ case TEXT3:\r
+ formattedString += formatText(rawData, numberOfLetters, 3);\r
+ break;\r
+ case NUMBER:\r
+ formattedString += formatNumber(rawData, numberOfLetters);\r
+ break;\r
+ case YEAR:\r
+ if (numberOfLetters <= 3) {\r
+ // Output a 2-digit year\r
+ var dataString = "" + rawData;\r
+ formattedString += dataString.substr(2, 2);\r
+ } else {\r
+ formattedString += formatNumber(rawData, numberOfLetters);\r
+ }\r
+ break;\r
+ case MONTH:\r
+ if (numberOfLetters >= 3) {\r
+ formattedString += formatText(monthNames[rawData], numberOfLetters, numberOfLetters);\r
+ } else {\r
+ // NB. Months returned by getMonth are zero-based\r
+ formattedString += formatNumber(rawData + 1, numberOfLetters);\r
+ }\r
+ break;\r
+ case TIMEZONE:\r
+ var isPositive = (rawData > 0);\r
+ // The following line looks like a mistake but isn't\r
+ // because of the way getTimezoneOffset measures.\r
+ var prefix = isPositive ? "-" : "+";\r
+ var absData = Math.abs(rawData);\r
+\r
+ // Hours\r
+ var hours = "" + Math.floor(absData / 60);\r
+ hours = padWithZeroes(hours, 2);\r
+ // Minutes\r
+ var minutes = "" + (absData % 60);\r
+ minutes = padWithZeroes(minutes, 2);\r
+\r
+ formattedString += prefix + hours + minutes;\r
+ break;\r
+ }\r
+ }\r
+ searchString = searchString.substr(result.index + result[0].length);\r
+ }\r
+ return formattedString;\r
+ };\r
+ })();\r
+\r
+ log4javascript.SimpleDateFormat = SimpleDateFormat;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // PatternLayout\r
+\r
+ function PatternLayout(pattern) {\r
+ if (pattern) {\r
+ this.pattern = pattern;\r
+ } else {\r
+ this.pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;\r
+ }\r
+ this.customFields = [];\r
+ }\r
+\r
+ PatternLayout.TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n";\r
+ PatternLayout.DEFAULT_CONVERSION_PATTERN = "%m%n";\r
+ PatternLayout.ISO8601_DATEFORMAT = "yyyy-MM-dd HH:mm:ss,SSS";\r
+ PatternLayout.DATETIME_DATEFORMAT = "dd MMM yyyy HH:mm:ss,SSS";\r
+ PatternLayout.ABSOLUTETIME_DATEFORMAT = "HH:mm:ss,SSS";\r
+\r
+ PatternLayout.prototype = new Layout();\r
+\r
+ PatternLayout.prototype.format = function(loggingEvent) {\r
+ var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;\r
+ var formattedString = "";\r
+ var result;\r
+ var searchString = this.pattern;\r
+\r
+ // Cannot use regex global flag since it doesn't work with exec in IE5\r
+ while ((result = regex.exec(searchString))) {\r
+ var matchedString = result[0];\r
+ var padding = result[1];\r
+ var truncation = result[2];\r
+ var conversionCharacter = result[3];\r
+ var specifier = result[5];\r
+ var text = result[6];\r
+\r
+ // Check if the pattern matched was just normal text\r
+ if (text) {\r
+ formattedString += "" + text;\r
+ } else {\r
+ // Create a raw replacement string based on the conversion\r
+ // character and specifier\r
+ var replacement = "";\r
+ switch(conversionCharacter) {\r
+ case "a": // Array of messages\r
+ case "m": // Message\r
+ var depth = 0;\r
+ if (specifier) {\r
+ depth = parseInt(specifier, 10);\r
+ if (isNaN(depth)) {\r
+ handleError("PatternLayout.format: invalid specifier '" +\r
+ specifier + "' for conversion character '" + conversionCharacter +\r
+ "' - should be a number");\r
+ depth = 0;\r
+ }\r
+ }\r
+ var messages = (conversionCharacter === "a") ? loggingEvent.messages[0] : loggingEvent.messages;\r
+ for (var i = 0, len = messages.length; i < len; i++) {\r
+ if (i > 0 && (replacement.charAt(replacement.length - 1) !== " ")) {\r
+ replacement += " ";\r
+ }\r
+ if (depth === 0) {\r
+ replacement += messages[i];\r
+ } else {\r
+ replacement += formatObjectExpansion(messages[i], depth);\r
+ }\r
+ }\r
+ break;\r
+ case "c": // Logger name\r
+ var loggerName = loggingEvent.logger.name;\r
+ if (specifier) {\r
+ var precision = parseInt(specifier, 10);\r
+ var loggerNameBits = loggingEvent.logger.name.split(".");\r
+ if (precision >= loggerNameBits.length) {\r
+ replacement = loggerName;\r
+ } else {\r
+ replacement = loggerNameBits.slice(loggerNameBits.length - precision).join(".");\r
+ }\r
+ } else {\r
+ replacement = loggerName;\r
+ }\r
+ break;\r
+ case "d": // Date\r
+ var dateFormat = PatternLayout.ISO8601_DATEFORMAT;\r
+ if (specifier) {\r
+ dateFormat = specifier;\r
+ // Pick up special cases\r
+ if (dateFormat == "ISO8601") {\r
+ dateFormat = PatternLayout.ISO8601_DATEFORMAT;\r
+ } else if (dateFormat == "ABSOLUTE") {\r
+ dateFormat = PatternLayout.ABSOLUTETIME_DATEFORMAT;\r
+ } else if (dateFormat == "DATE") {\r
+ dateFormat = PatternLayout.DATETIME_DATEFORMAT;\r
+ }\r
+ }\r
+ // Format the date\r
+ replacement = (new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);\r
+ break;\r
+ case "f": // Custom field\r
+ if (this.hasCustomFields()) {\r
+ var fieldIndex = 0;\r
+ if (specifier) {\r
+ fieldIndex = parseInt(specifier, 10);\r
+ if (isNaN(fieldIndex)) {\r
+ handleError("PatternLayout.format: invalid specifier '" +\r
+ specifier + "' for conversion character 'f' - should be a number");\r
+ } else if (fieldIndex === 0) {\r
+ handleError("PatternLayout.format: invalid specifier '" +\r
+ specifier + "' for conversion character 'f' - must be greater than zero");\r
+ } else if (fieldIndex > this.customFields.length) {\r
+ handleError("PatternLayout.format: invalid specifier '" +\r
+ specifier + "' for conversion character 'f' - there aren't that many custom fields");\r
+ } else {\r
+ fieldIndex = fieldIndex - 1;\r
+ }\r
+ }\r
+ var val = this.customFields[fieldIndex].value;\r
+ if (typeof val == "function") {\r
+ val = val(this, loggingEvent);\r
+ }\r
+ replacement = val;\r
+ }\r
+ break;\r
+ case "n": // New line\r
+ replacement = newLine;\r
+ break;\r
+ case "p": // Level\r
+ replacement = loggingEvent.level.name;\r
+ break;\r
+ case "r": // Milliseconds since log4javascript startup\r
+ replacement = "" + loggingEvent.timeStamp.getDifference(applicationStartDate);\r
+ break;\r
+ case "%": // Literal % sign\r
+ replacement = "%";\r
+ break;\r
+ default:\r
+ replacement = matchedString;\r
+ break;\r
+ }\r
+ // Format the replacement according to any padding or\r
+ // truncation specified\r
+ var l;\r
+\r
+ // First, truncation\r
+ if (truncation) {\r
+ l = parseInt(truncation.substr(1), 10);\r
+ var strLen = replacement.length;\r
+ if (l < strLen) {\r
+ replacement = replacement.substring(strLen - l, strLen);\r
+ }\r
+ }\r
+ // Next, padding\r
+ if (padding) {\r
+ if (padding.charAt(0) == "-") {\r
+ l = parseInt(padding.substr(1), 10);\r
+ // Right pad with spaces\r
+ while (replacement.length < l) {\r
+ replacement += " ";\r
+ }\r
+ } else {\r
+ l = parseInt(padding, 10);\r
+ // Left pad with spaces\r
+ while (replacement.length < l) {\r
+ replacement = " " + replacement;\r
+ }\r
+ }\r
+ }\r
+ formattedString += replacement;\r
+ }\r
+ searchString = searchString.substr(result.index + result[0].length);\r
+ }\r
+ return formattedString;\r
+ };\r
+\r
+ PatternLayout.prototype.ignoresThrowable = function() {\r
+ return true;\r
+ };\r
+\r
+ PatternLayout.prototype.toString = function() {\r
+ return "PatternLayout";\r
+ };\r
+\r
+ log4javascript.PatternLayout = PatternLayout;\r
+ /* ---------------------------------------------------------------------- */\r
+ // AjaxAppender related\r
+\r
+ var xmlHttpFactories = [\r
+ function() { return new XMLHttpRequest(); },\r
+ function() { return new ActiveXObject("Msxml2.XMLHTTP"); },\r
+ function() { return new ActiveXObject("Microsoft.XMLHTTP"); }\r
+ ];\r
+\r
+ var getXmlHttp = function(errorHandler) {\r
+ // This is only run the first time; the value of getXmlHttp gets\r
+ // replaced with the factory that succeeds on the first run\r
+ var xmlHttp = null, factory;\r
+ for (var i = 0, len = xmlHttpFactories.length; i < len; i++) {\r
+ factory = xmlHttpFactories[i];\r
+ try {\r
+ xmlHttp = factory();\r
+ getXmlHttp = factory;\r
+ return xmlHttp;\r
+ } catch (e) {\r
+ }\r
+ }\r
+ // If we're here, all factories have failed, so throw an error\r
+ if (errorHandler) {\r
+ errorHandler();\r
+ } else {\r
+ handleError("getXmlHttp: unable to obtain XMLHttpRequest object");\r
+ }\r
+ };\r
+\r
+ function isHttpRequestSuccessful(xmlHttp) {\r
+ return isUndefined(xmlHttp.status) || xmlHttp.status === 0 ||\r
+ (xmlHttp.status >= 200 && xmlHttp.status < 300) ||\r
+ xmlHttp.status == 1223 /* Fix for IE */;\r
+ }\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // AjaxAppender\r
+\r
+ function AjaxAppender(url) {\r
+ var appender = this;\r
+ var isSupported = true;\r
+ if (!url) {\r
+ handleError("AjaxAppender: URL must be specified in constructor");\r
+ isSupported = false;\r
+ }\r
+\r
+ var timed = this.defaults.timed;\r
+ var waitForResponse = this.defaults.waitForResponse;\r
+ var batchSize = this.defaults.batchSize;\r
+ var timerInterval = this.defaults.timerInterval;\r
+ var requestSuccessCallback = this.defaults.requestSuccessCallback;\r
+ var failCallback = this.defaults.failCallback;\r
+ var postVarName = this.defaults.postVarName;\r
+ var sendAllOnUnload = this.defaults.sendAllOnUnload;\r
+ var contentType = this.defaults.contentType;\r
+ var sessionId = null;\r
+\r
+ var queuedLoggingEvents = [];\r
+ var queuedRequests = [];\r
+ var headers = [];\r
+ var sending = false;\r
+ var initialized = false;\r
+\r
+ // Configuration methods. The function scope is used to prevent\r
+ // direct alteration to the appender configuration properties.\r
+ function checkCanConfigure(configOptionName) {\r
+ if (initialized) {\r
+ handleError("AjaxAppender: configuration option '" +\r
+ configOptionName +\r
+ "' may not be set after the appender has been initialized");\r
+ return false;\r
+ }\r
+ return true;\r
+ }\r
+\r
+ this.getSessionId = function() { return sessionId; };\r
+ this.setSessionId = function(sessionIdParam) {\r
+ sessionId = extractStringFromParam(sessionIdParam, null);\r
+ this.layout.setCustomField("sessionid", sessionId);\r
+ };\r
+\r
+ this.setLayout = function(layoutParam) {\r
+ if (checkCanConfigure("layout")) {\r
+ this.layout = layoutParam;\r
+ // Set the session id as a custom field on the layout, if not already present\r
+ if (sessionId !== null) {\r
+ this.setSessionId(sessionId);\r
+ }\r
+ }\r
+ };\r
+\r
+ this.isTimed = function() { return timed; };\r
+ this.setTimed = function(timedParam) {\r
+ if (checkCanConfigure("timed")) {\r
+ timed = bool(timedParam);\r
+ }\r
+ };\r
+\r
+ this.getTimerInterval = function() { return timerInterval; };\r
+ this.setTimerInterval = function(timerIntervalParam) {\r
+ if (checkCanConfigure("timerInterval")) {\r
+ timerInterval = extractIntFromParam(timerIntervalParam, timerInterval);\r
+ }\r
+ };\r
+\r
+ this.isWaitForResponse = function() { return waitForResponse; };\r
+ this.setWaitForResponse = function(waitForResponseParam) {\r
+ if (checkCanConfigure("waitForResponse")) {\r
+ waitForResponse = bool(waitForResponseParam);\r
+ }\r
+ };\r
+\r
+ this.getBatchSize = function() { return batchSize; };\r
+ this.setBatchSize = function(batchSizeParam) {\r
+ if (checkCanConfigure("batchSize")) {\r
+ batchSize = extractIntFromParam(batchSizeParam, batchSize);\r
+ }\r
+ };\r
+\r
+ this.isSendAllOnUnload = function() { return sendAllOnUnload; };\r
+ this.setSendAllOnUnload = function(sendAllOnUnloadParam) {\r
+ if (checkCanConfigure("sendAllOnUnload")) {\r
+ sendAllOnUnload = extractBooleanFromParam(sendAllOnUnloadParam, sendAllOnUnload);\r
+ }\r
+ };\r
+\r
+ this.setRequestSuccessCallback = function(requestSuccessCallbackParam) {\r
+ requestSuccessCallback = extractFunctionFromParam(requestSuccessCallbackParam, requestSuccessCallback);\r
+ };\r
+\r
+ this.setFailCallback = function(failCallbackParam) {\r
+ failCallback = extractFunctionFromParam(failCallbackParam, failCallback);\r
+ };\r
+\r
+ this.getPostVarName = function() { return postVarName; };\r
+ this.setPostVarName = function(postVarNameParam) {\r
+ if (checkCanConfigure("postVarName")) {\r
+ postVarName = extractStringFromParam(postVarNameParam, postVarName);\r
+ }\r
+ };\r
+\r
+ this.getHeaders = function() { return headers; };\r
+ this.addHeader = function(name, value) {\r
+ if (name.toLowerCase() == "content-type") {\r
+ contentType = value;\r
+ } else {\r
+ headers.push( { name: name, value: value } );\r
+ }\r
+ };\r
+\r
+ // Internal functions\r
+ function sendAll() {\r
+ if (isSupported && enabled) {\r
+ sending = true;\r
+ var currentRequestBatch;\r
+ if (waitForResponse) {\r
+ // Send the first request then use this function as the callback once\r
+ // the response comes back\r
+ if (queuedRequests.length > 0) {\r
+ currentRequestBatch = queuedRequests.shift();\r
+ sendRequest(preparePostData(currentRequestBatch), sendAll);\r
+ } else {\r
+ sending = false;\r
+ if (timed) {\r
+ scheduleSending();\r
+ }\r
+ }\r
+ } else {\r
+ // Rattle off all the requests without waiting to see the response\r
+ while ((currentRequestBatch = queuedRequests.shift())) {\r
+ sendRequest(preparePostData(currentRequestBatch));\r
+ }\r
+ sending = false;\r
+ if (timed) {\r
+ scheduleSending();\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ this.sendAll = sendAll;\r
+\r
+ // Called when the window unloads. At this point we're past caring about\r
+ // waiting for responses or timers or incomplete batches - everything\r
+ // must go, now\r
+ function sendAllRemaining() {\r
+ var sendingAnything = false;\r
+ if (isSupported && enabled) {\r
+ // Create requests for everything left over, batched as normal\r
+ var actualBatchSize = appender.getLayout().allowBatching() ? batchSize : 1;\r
+ var currentLoggingEvent;\r
+ var batchedLoggingEvents = [];\r
+ while ((currentLoggingEvent = queuedLoggingEvents.shift())) {\r
+ batchedLoggingEvents.push(currentLoggingEvent);\r
+ if (queuedLoggingEvents.length >= actualBatchSize) {\r
+ // Queue this batch of log entries\r
+ queuedRequests.push(batchedLoggingEvents);\r
+ batchedLoggingEvents = [];\r
+ }\r
+ }\r
+ // If there's a partially completed batch, add it\r
+ if (batchedLoggingEvents.length > 0) {\r
+ queuedRequests.push(batchedLoggingEvents);\r
+ }\r
+ sendingAnything = (queuedRequests.length > 0);\r
+ waitForResponse = false;\r
+ timed = false;\r
+ sendAll();\r
+ }\r
+ return sendingAnything;\r
+ }\r
+\r
+ this.sendAllRemaining = sendAllRemaining;\r
+\r
+ function preparePostData(batchedLoggingEvents) {\r
+ // Format the logging events\r
+ var formattedMessages = [];\r
+ var currentLoggingEvent;\r
+ var postData = "";\r
+ while ((currentLoggingEvent = batchedLoggingEvents.shift())) {\r
+ var currentFormattedMessage = appender.getLayout().format(currentLoggingEvent);\r
+ if (appender.getLayout().ignoresThrowable()) {\r
+ currentFormattedMessage += currentLoggingEvent.getThrowableStrRep();\r
+ }\r
+ formattedMessages.push(currentFormattedMessage);\r
+ }\r
+ // Create the post data string\r
+ if (batchedLoggingEvents.length == 1) {\r
+ postData = formattedMessages.join("");\r
+ } else {\r
+ postData = appender.getLayout().batchHeader +\r
+ formattedMessages.join(appender.getLayout().batchSeparator) +\r
+ appender.getLayout().batchFooter;\r
+ }\r
+ if (contentType == appender.defaults.contentType) {\r
+ postData = appender.getLayout().returnsPostData ? postData :\r
+ urlEncode(postVarName) + "=" + urlEncode(postData);\r
+ // Add the layout name to the post data\r
+ if (postData.length > 0) {\r
+ postData += "&";\r
+ }\r
+ postData += "layout=" + urlEncode(appender.getLayout().toString());\r
+ }\r
+ return postData;\r
+ }\r
+\r
+ function scheduleSending() {\r
+ window.setTimeout(sendAll, timerInterval);\r
+ }\r
+\r
+ function xmlHttpErrorHandler() {\r
+ var msg = "AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";\r
+ handleError(msg);\r
+ isSupported = false;\r
+ if (failCallback) {\r
+ failCallback(msg);\r
+ }\r
+ }\r
+\r
+ function sendRequest(postData, successCallback) {\r
+ try {\r
+ var xmlHttp = getXmlHttp(xmlHttpErrorHandler);\r
+ if (isSupported) {\r
+ if (xmlHttp.overrideMimeType) {\r
+ xmlHttp.overrideMimeType(appender.getLayout().getContentType());\r
+ }\r
+ xmlHttp.onreadystatechange = function() {\r
+ if (xmlHttp.readyState == 4) {\r
+ if (isHttpRequestSuccessful(xmlHttp)) {\r
+ if (requestSuccessCallback) {\r
+ requestSuccessCallback(xmlHttp);\r
+ }\r
+ if (successCallback) {\r
+ successCallback(xmlHttp);\r
+ }\r
+ } else {\r
+ var msg = "AjaxAppender.append: XMLHttpRequest request to URL " +\r
+ url + " returned status code " + xmlHttp.status;\r
+ handleError(msg);\r
+ if (failCallback) {\r
+ failCallback(msg);\r
+ }\r
+ }\r
+ xmlHttp.onreadystatechange = emptyFunction;\r
+ xmlHttp = null;\r
+ }\r
+ };\r
+ xmlHttp.open("POST", url, true);\r
+ try {\r
+ for (var i = 0, header; header = headers[i++]; ) {\r
+ xmlHttp.setRequestHeader(header.name, header.value);\r
+ }\r
+ xmlHttp.setRequestHeader("Content-Type", contentType);\r
+ } catch (headerEx) {\r
+ var msg = "AjaxAppender.append: your browser's XMLHttpRequest implementation" +\r
+ " does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";\r
+ handleError(msg);\r
+ isSupported = false;\r
+ if (failCallback) {\r
+ failCallback(msg);\r
+ }\r
+ return;\r
+ }\r
+ xmlHttp.send(postData);\r
+ }\r
+ } catch (ex) {\r
+ var errMsg = "AjaxAppender.append: error sending log message to " + url;\r
+ handleError(errMsg, ex);\r
+ isSupported = false;\r
+ if (failCallback) {\r
+ failCallback(errMsg + ". Details: " + getExceptionStringRep(ex));\r
+ }\r
+ }\r
+ }\r
+\r
+ this.append = function(loggingEvent) {\r
+ if (isSupported) {\r
+ if (!initialized) {\r
+ init();\r
+ }\r
+ queuedLoggingEvents.push(loggingEvent);\r
+ var actualBatchSize = this.getLayout().allowBatching() ? batchSize : 1;\r
+\r
+ if (queuedLoggingEvents.length >= actualBatchSize) {\r
+ var currentLoggingEvent;\r
+ var batchedLoggingEvents = [];\r
+ while ((currentLoggingEvent = queuedLoggingEvents.shift())) {\r
+ batchedLoggingEvents.push(currentLoggingEvent);\r
+ }\r
+ // Queue this batch of log entries\r
+ queuedRequests.push(batchedLoggingEvents);\r
+\r
+ // If using a timer, the queue of requests will be processed by the\r
+ // timer function, so nothing needs to be done here.\r
+ if (!timed && (!waitForResponse || (waitForResponse && !sending))) {\r
+ sendAll();\r
+ }\r
+ }\r
+ }\r
+ };\r
+\r
+ function init() {\r
+ initialized = true;\r
+ // Add unload event to send outstanding messages\r
+ if (sendAllOnUnload) {\r
+ var oldBeforeUnload = window.onbeforeunload;\r
+ window.onbeforeunload = function() {\r
+ if (oldBeforeUnload) {\r
+ oldBeforeUnload();\r
+ }\r
+ if (sendAllRemaining()) {\r
+ return "Sending log messages";\r
+ }\r
+ };\r
+ }\r
+ // Start timer\r
+ if (timed) {\r
+ scheduleSending();\r
+ }\r
+ }\r
+ }\r
+\r
+ AjaxAppender.prototype = new Appender();\r
+\r
+ AjaxAppender.prototype.defaults = {\r
+ waitForResponse: false,\r
+ timed: false,\r
+ timerInterval: 1000,\r
+ batchSize: 1,\r
+ sendAllOnUnload: false,\r
+ requestSuccessCallback: null,\r
+ failCallback: null,\r
+ postVarName: "data",\r
+ contentType: "application/x-www-form-urlencoded"\r
+ };\r
+\r
+ AjaxAppender.prototype.layout = new HttpPostDataLayout();\r
+\r
+ AjaxAppender.prototype.toString = function() {\r
+ return "AjaxAppender";\r
+ };\r
+\r
+ log4javascript.AjaxAppender = AjaxAppender;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Main load\r
+\r
+ log4javascript.setDocumentReady = function() {\r
+ pageLoaded = true;\r
+ log4javascript.dispatchEvent("load", {});\r
+ };\r
+\r
+ if (window.addEventListener) {\r
+ window.addEventListener("load", log4javascript.setDocumentReady, false);\r
+ } else if (window.attachEvent) {\r
+ window.attachEvent("onload", log4javascript.setDocumentReady);\r
+ } else {\r
+ var oldOnload = window.onload;\r
+ if (typeof window.onload != "function") {\r
+ window.onload = log4javascript.setDocumentReady;\r
+ } else {\r
+ window.onload = function(evt) {\r
+ if (oldOnload) {\r
+ oldOnload(evt);\r
+ }\r
+ log4javascript.setDocumentReady();\r
+ };\r
+ }\r
+ }\r
+\r
+ // Ensure that the log4javascript object is available in the window. This\r
+ // is necessary for log4javascript to be available in IE if loaded using\r
+ // Dojo's module system\r
+ window.log4javascript = log4javascript;\r
+\r
+ return log4javascript;\r
+})();
\ No newline at end of file
--- /dev/null
+/**\r
+ * Copyright 2013 Tim Down.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/**\r
+ * log4javascript\r
+ *\r
+ * log4javascript is a logging framework for JavaScript based on log4j\r
+ * for Java. This file contains all core log4javascript code and is the only\r
+ * file required to use log4javascript, unless you require support for\r
+ * document.domain, in which case you will also need console.html, which must be\r
+ * stored in the same directory as the main log4javascript.js file.\r
+ *\r
+ * Author: Tim Down <tim@log4javascript.org>\r
+ * Version: 1.4.6\r
+ * Edition: log4javascript\r
+ * Build date: 19 March 2013\r
+ * Website: http://log4javascript.org\r
+ */\r
+\r
+/* -------------------------------------------------------------------------- */\r
+// Array-related stuff\r
+\r
+// Next three methods are solely for IE5, which is missing them\r
+if (!Array.prototype.push) {\r
+ Array.prototype.push = function() {\r
+ for (var i = 0, len = arguments.length; i < len; i++){\r
+ this[this.length] = arguments[i];\r
+ }\r
+ return this.length;\r
+ };\r
+}\r
+\r
+if (!Array.prototype.shift) {\r
+ Array.prototype.shift = function() {\r
+ if (this.length > 0) {\r
+ var firstItem = this[0];\r
+ for (var i = 0, len = this.length - 1; i < len; i++) {\r
+ this[i] = this[i + 1];\r
+ }\r
+ this.length = this.length - 1;\r
+ return firstItem;\r
+ }\r
+ };\r
+}\r
+\r
+if (!Array.prototype.splice) {\r
+ Array.prototype.splice = function(startIndex, deleteCount) {\r
+ var itemsAfterDeleted = this.slice(startIndex + deleteCount);\r
+ var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);\r
+ this.length = startIndex;\r
+ // Copy the arguments into a proper Array object\r
+ var argumentsArray = [];\r
+ for (var i = 0, len = arguments.length; i < len; i++) {\r
+ argumentsArray[i] = arguments[i];\r
+ }\r
+ var itemsToAppend = (argumentsArray.length > 2) ?\r
+ itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;\r
+ for (i = 0, len = itemsToAppend.length; i < len; i++) {\r
+ this.push(itemsToAppend[i]);\r
+ }\r
+ return itemsDeleted;\r
+ };\r
+}\r
+\r
+/* -------------------------------------------------------------------------- */\r
+\r
+var log4javascript = (function() {\r
+\r
+ function isUndefined(obj) {\r
+ return typeof obj == "undefined";\r
+ }\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Custom event support\r
+\r
+ function EventSupport() {}\r
+\r
+ EventSupport.prototype = {\r
+ eventTypes: [],\r
+ eventListeners: {},\r
+ setEventTypes: function(eventTypesParam) {\r
+ if (eventTypesParam instanceof Array) {\r
+ this.eventTypes = eventTypesParam;\r
+ this.eventListeners = {};\r
+ for (var i = 0, len = this.eventTypes.length; i < len; i++) {\r
+ this.eventListeners[this.eventTypes[i]] = [];\r
+ }\r
+ } else {\r
+ handleError("log4javascript.EventSupport [" + this + "]: setEventTypes: eventTypes parameter must be an Array");\r
+ }\r
+ },\r
+\r
+ addEventListener: function(eventType, listener) {\r
+ if (typeof listener == "function") {\r
+ if (!array_contains(this.eventTypes, eventType)) {\r
+ handleError("log4javascript.EventSupport [" + this + "]: addEventListener: no event called '" + eventType + "'");\r
+ }\r
+ this.eventListeners[eventType].push(listener);\r
+ } else {\r
+ handleError("log4javascript.EventSupport [" + this + "]: addEventListener: listener must be a function");\r
+ }\r
+ },\r
+\r
+ removeEventListener: function(eventType, listener) {\r
+ if (typeof listener == "function") {\r
+ if (!array_contains(this.eventTypes, eventType)) {\r
+ handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: no event called '" + eventType + "'");\r
+ }\r
+ array_remove(this.eventListeners[eventType], listener);\r
+ } else {\r
+ handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: listener must be a function");\r
+ }\r
+ },\r
+\r
+ dispatchEvent: function(eventType, eventArgs) {\r
+ if (array_contains(this.eventTypes, eventType)) {\r
+ var listeners = this.eventListeners[eventType];\r
+ for (var i = 0, len = listeners.length; i < len; i++) {\r
+ listeners[i](this, eventType, eventArgs);\r
+ }\r
+ } else {\r
+ handleError("log4javascript.EventSupport [" + this + "]: dispatchEvent: no event called '" + eventType + "'");\r
+ }\r
+ }\r
+ };\r
+\r
+ /* -------------------------------------------------------------------------- */\r
+\r
+ var applicationStartDate = new Date();\r
+ var uniqueId = "log4javascript_" + applicationStartDate.getTime() + "_" +\r
+ Math.floor(Math.random() * 100000000);\r
+ var emptyFunction = function() {};\r
+ var newLine = "\r\n";\r
+ var pageLoaded = false;\r
+\r
+ // Create main log4javascript object; this will be assigned public properties\r
+ function Log4JavaScript() {}\r
+ Log4JavaScript.prototype = new EventSupport();\r
+\r
+ log4javascript = new Log4JavaScript();\r
+ log4javascript.version = "1.4.6";\r
+ log4javascript.edition = "log4javascript";\r
+\r
+ /* -------------------------------------------------------------------------- */\r
+ // Utility functions\r
+\r
+ function toStr(obj) {\r
+ if (obj && obj.toString) {\r
+ return obj.toString();\r
+ } else {\r
+ return String(obj);\r
+ }\r
+ }\r
+\r
+ function getExceptionMessage(ex) {\r
+ if (ex.message) {\r
+ return ex.message;\r
+ } else if (ex.description) {\r
+ return ex.description;\r
+ } else {\r
+ return toStr(ex);\r
+ }\r
+ }\r
+\r
+ // Gets the portion of the URL after the last slash\r
+ function getUrlFileName(url) {\r
+ var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\"));\r
+ return url.substr(lastSlashIndex + 1);\r
+ }\r
+\r
+ // Returns a nicely formatted representation of an error\r
+ function getExceptionStringRep(ex) {\r
+ if (ex) {\r
+ var exStr = "Exception: " + getExceptionMessage(ex);\r
+ try {\r
+ if (ex.lineNumber) {\r
+ exStr += " on line number " + ex.lineNumber;\r
+ }\r
+ if (ex.fileName) {\r
+ exStr += " in file " + getUrlFileName(ex.fileName);\r
+ }\r
+ } catch (localEx) {\r
+ logLog.warn("Unable to obtain file and line information for error");\r
+ }\r
+ if (showStackTraces && ex.stack) {\r
+ exStr += newLine + "Stack trace:" + newLine + ex.stack;\r
+ }\r
+ return exStr;\r
+ }\r
+ return null;\r
+ }\r
+\r
+ function bool(obj) {\r
+ return Boolean(obj);\r
+ }\r
+\r
+ function trim(str) {\r
+ return str.replace(/^\s+/, "").replace(/\s+$/, "");\r
+ }\r
+\r
+ function splitIntoLines(text) {\r
+ // Ensure all line breaks are \n only\r
+ var text2 = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");\r
+ return text2.split("\n");\r
+ }\r
+\r
+ var urlEncode = (typeof window.encodeURIComponent != "undefined") ?\r
+ function(str) {\r
+ return encodeURIComponent(str);\r
+ }: \r
+ function(str) {\r
+ return escape(str).replace(/\+/g, "%2B").replace(/"/g, "%22").replace(/'/g, "%27").replace(/\//g, "%2F").replace(/=/g, "%3D");\r
+ };\r
+\r
+ var urlDecode = (typeof window.decodeURIComponent != "undefined") ?\r
+ function(str) {\r
+ return decodeURIComponent(str);\r
+ }: \r
+ function(str) {\r
+ return unescape(str).replace(/%2B/g, "+").replace(/%22/g, "\"").replace(/%27/g, "'").replace(/%2F/g, "/").replace(/%3D/g, "=");\r
+ };\r
+\r
+ function array_remove(arr, val) {\r
+ var index = -1;\r
+ for (var i = 0, len = arr.length; i < len; i++) {\r
+ if (arr[i] === val) {\r
+ index = i;\r
+ break;\r
+ }\r
+ }\r
+ if (index >= 0) {\r
+ arr.splice(index, 1);\r
+ return true;\r
+ } else {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ function array_contains(arr, val) {\r
+ for(var i = 0, len = arr.length; i < len; i++) {\r
+ if (arr[i] == val) {\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+\r
+ function extractBooleanFromParam(param, defaultValue) {\r
+ if (isUndefined(param)) {\r
+ return defaultValue;\r
+ } else {\r
+ return bool(param);\r
+ }\r
+ }\r
+\r
+ function extractStringFromParam(param, defaultValue) {\r
+ if (isUndefined(param)) {\r
+ return defaultValue;\r
+ } else {\r
+ return String(param);\r
+ }\r
+ }\r
+\r
+ function extractIntFromParam(param, defaultValue) {\r
+ if (isUndefined(param)) {\r
+ return defaultValue;\r
+ } else {\r
+ try {\r
+ var value = parseInt(param, 10);\r
+ return isNaN(value) ? defaultValue : value;\r
+ } catch (ex) {\r
+ logLog.warn("Invalid int param " + param, ex);\r
+ return defaultValue;\r
+ }\r
+ }\r
+ }\r
+\r
+ function extractFunctionFromParam(param, defaultValue) {\r
+ if (typeof param == "function") {\r
+ return param;\r
+ } else {\r
+ return defaultValue;\r
+ }\r
+ }\r
+\r
+ function isError(err) {\r
+ return (err instanceof Error);\r
+ }\r
+\r
+ if (!Function.prototype.apply){\r
+ Function.prototype.apply = function(obj, args) {\r
+ var methodName = "__apply__";\r
+ if (typeof obj[methodName] != "undefined") {\r
+ methodName += String(Math.random()).substr(2);\r
+ }\r
+ obj[methodName] = this;\r
+\r
+ var argsStrings = [];\r
+ for (var i = 0, len = args.length; i < len; i++) {\r
+ argsStrings[i] = "args[" + i + "]";\r
+ }\r
+ var script = "obj." + methodName + "(" + argsStrings.join(",") + ")";\r
+ var returnValue = eval(script);\r
+ delete obj[methodName];\r
+ return returnValue;\r
+ };\r
+ }\r
+\r
+ if (!Function.prototype.call){\r
+ Function.prototype.call = function(obj) {\r
+ var args = [];\r
+ for (var i = 1, len = arguments.length; i < len; i++) {\r
+ args[i - 1] = arguments[i];\r
+ }\r
+ return this.apply(obj, args);\r
+ };\r
+ }\r
+\r
+ function getListenersPropertyName(eventName) {\r
+ return "__log4javascript_listeners__" + eventName;\r
+ }\r
+\r
+ function addEvent(node, eventName, listener, useCapture, win) {\r
+ win = win ? win : window;\r
+ if (node.addEventListener) {\r
+ node.addEventListener(eventName, listener, useCapture);\r
+ } else if (node.attachEvent) {\r
+ node.attachEvent("on" + eventName, listener);\r
+ } else {\r
+ var propertyName = getListenersPropertyName(eventName);\r
+ if (!node[propertyName]) {\r
+ node[propertyName] = [];\r
+ // Set event handler\r
+ node["on" + eventName] = function(evt) {\r
+ evt = getEvent(evt, win);\r
+ var listenersPropertyName = getListenersPropertyName(eventName);\r
+\r
+ // Clone the array of listeners to leave the original untouched\r
+ var listeners = this[listenersPropertyName].concat([]);\r
+ var currentListener;\r
+\r
+ // Call each listener in turn\r
+ while ((currentListener = listeners.shift())) {\r
+ currentListener.call(this, evt);\r
+ }\r
+ };\r
+ }\r
+ node[propertyName].push(listener);\r
+ }\r
+ }\r
+\r
+ function removeEvent(node, eventName, listener, useCapture) {\r
+ if (node.removeEventListener) {\r
+ node.removeEventListener(eventName, listener, useCapture);\r
+ } else if (node.detachEvent) {\r
+ node.detachEvent("on" + eventName, listener);\r
+ } else {\r
+ var propertyName = getListenersPropertyName(eventName);\r
+ if (node[propertyName]) {\r
+ array_remove(node[propertyName], listener);\r
+ }\r
+ }\r
+ }\r
+\r
+ function getEvent(evt, win) {\r
+ win = win ? win : window;\r
+ return evt ? evt : win.event;\r
+ }\r
+\r
+ function stopEventPropagation(evt) {\r
+ if (evt.stopPropagation) {\r
+ evt.stopPropagation();\r
+ } else if (typeof evt.cancelBubble != "undefined") {\r
+ evt.cancelBubble = true;\r
+ }\r
+ evt.returnValue = false;\r
+ }\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Simple logging for log4javascript itself\r
+\r
+ var logLog = {\r
+ quietMode: false,\r
+\r
+ debugMessages: [],\r
+\r
+ setQuietMode: function(quietMode) {\r
+ this.quietMode = bool(quietMode);\r
+ },\r
+\r
+ numberOfErrors: 0,\r
+\r
+ alertAllErrors: false,\r
+\r
+ setAlertAllErrors: function(alertAllErrors) {\r
+ this.alertAllErrors = alertAllErrors;\r
+ },\r
+\r
+ debug: function(message) {\r
+ this.debugMessages.push(message);\r
+ },\r
+\r
+ displayDebug: function() {\r
+ alert(this.debugMessages.join(newLine));\r
+ },\r
+\r
+ warn: function(message, exception) {\r
+ },\r
+\r
+ error: function(message, exception) {\r
+ if (++this.numberOfErrors == 1 || this.alertAllErrors) {\r
+ if (!this.quietMode) {\r
+ var alertMessage = "log4javascript error: " + message;\r
+ if (exception) {\r
+ alertMessage += newLine + newLine + "Original error: " + getExceptionStringRep(exception);\r
+ }\r
+ alert(alertMessage);\r
+ }\r
+ }\r
+ }\r
+ };\r
+ log4javascript.logLog = logLog;\r
+\r
+ log4javascript.setEventTypes(["load", "error"]);\r
+\r
+ function handleError(message, exception) {\r
+ logLog.error(message, exception);\r
+ log4javascript.dispatchEvent("error", { "message": message, "exception": exception });\r
+ }\r
+\r
+ log4javascript.handleError = handleError;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+\r
+ var enabled = !((typeof log4javascript_disabled != "undefined") &&\r
+ log4javascript_disabled);\r
+\r
+ log4javascript.setEnabled = function(enable) {\r
+ enabled = bool(enable);\r
+ };\r
+\r
+ log4javascript.isEnabled = function() {\r
+ return enabled;\r
+ };\r
+\r
+ var useTimeStampsInMilliseconds = true;\r
+\r
+ log4javascript.setTimeStampsInMilliseconds = function(timeStampsInMilliseconds) {\r
+ useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);\r
+ };\r
+\r
+ log4javascript.isTimeStampsInMilliseconds = function() {\r
+ return useTimeStampsInMilliseconds;\r
+ };\r
+ \r
+\r
+ // This evaluates the given expression in the current scope, thus allowing\r
+ // scripts to access private variables. Particularly useful for testing\r
+ log4javascript.evalInScope = function(expr) {\r
+ return eval(expr);\r
+ };\r
+\r
+ var showStackTraces = false;\r
+\r
+ log4javascript.setShowStackTraces = function(show) {\r
+ showStackTraces = bool(show);\r
+ };\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Levels\r
+\r
+ var Level = function(level, name) {\r
+ this.level = level;\r
+ this.name = name;\r
+ };\r
+\r
+ Level.prototype = {\r
+ toString: function() {\r
+ return this.name;\r
+ },\r
+ equals: function(level) {\r
+ return this.level == level.level;\r
+ },\r
+ isGreaterOrEqual: function(level) {\r
+ return this.level >= level.level;\r
+ }\r
+ };\r
+\r
+ Level.ALL = new Level(Number.MIN_VALUE, "ALL");\r
+ Level.TRACE = new Level(10000, "TRACE");\r
+ Level.DEBUG = new Level(20000, "DEBUG");\r
+ Level.INFO = new Level(30000, "INFO");\r
+ Level.WARN = new Level(40000, "WARN");\r
+ Level.ERROR = new Level(50000, "ERROR");\r
+ Level.FATAL = new Level(60000, "FATAL");\r
+ Level.OFF = new Level(Number.MAX_VALUE, "OFF");\r
+\r
+ log4javascript.Level = Level;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Timers\r
+\r
+ function Timer(name, level) {\r
+ this.name = name;\r
+ this.level = isUndefined(level) ? Level.INFO : level;\r
+ this.start = new Date();\r
+ }\r
+\r
+ Timer.prototype.getElapsedTime = function() {\r
+ return new Date().getTime() - this.start.getTime();\r
+ };\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Loggers\r
+\r
+ var anonymousLoggerName = "[anonymous]";\r
+ var defaultLoggerName = "[default]";\r
+ var nullLoggerName = "[null]";\r
+ var rootLoggerName = "root";\r
+\r
+ function Logger(name) {\r
+ this.name = name;\r
+ this.parent = null;\r
+ this.children = [];\r
+\r
+ var appenders = [];\r
+ var loggerLevel = null;\r
+ var isRoot = (this.name === rootLoggerName);\r
+ var isNull = (this.name === nullLoggerName);\r
+\r
+ var appenderCache = null;\r
+ var appenderCacheInvalidated = false;\r
+ \r
+ this.addChild = function(childLogger) {\r
+ this.children.push(childLogger);\r
+ childLogger.parent = this;\r
+ childLogger.invalidateAppenderCache();\r
+ };\r
+\r
+ // Additivity\r
+ var additive = true;\r
+ this.getAdditivity = function() {\r
+ return additive;\r
+ };\r
+\r
+ this.setAdditivity = function(additivity) {\r
+ var valueChanged = (additive != additivity);\r
+ additive = additivity;\r
+ if (valueChanged) {\r
+ this.invalidateAppenderCache();\r
+ }\r
+ };\r
+\r
+ // Create methods that use the appenders variable in this scope\r
+ this.addAppender = function(appender) {\r
+ if (isNull) {\r
+ handleError("Logger.addAppender: you may not add an appender to the null logger");\r
+ } else {\r
+ if (appender instanceof log4javascript.Appender) {\r
+ if (!array_contains(appenders, appender)) {\r
+ appenders.push(appender);\r
+ appender.setAddedToLogger(this);\r
+ this.invalidateAppenderCache();\r
+ }\r
+ } else {\r
+ handleError("Logger.addAppender: appender supplied ('" +\r
+ toStr(appender) + "') is not a subclass of Appender");\r
+ }\r
+ }\r
+ };\r
+\r
+ this.removeAppender = function(appender) {\r
+ array_remove(appenders, appender);\r
+ appender.setRemovedFromLogger(this);\r
+ this.invalidateAppenderCache();\r
+ };\r
+\r
+ this.removeAllAppenders = function() {\r
+ var appenderCount = appenders.length;\r
+ if (appenderCount > 0) {\r
+ for (var i = 0; i < appenderCount; i++) {\r
+ appenders[i].setRemovedFromLogger(this);\r
+ }\r
+ appenders.length = 0;\r
+ this.invalidateAppenderCache();\r
+ }\r
+ };\r
+\r
+ this.getEffectiveAppenders = function() {\r
+ if (appenderCache === null || appenderCacheInvalidated) {\r
+ // Build appender cache\r
+ var parentEffectiveAppenders = (isRoot || !this.getAdditivity()) ?\r
+ [] : this.parent.getEffectiveAppenders();\r
+ appenderCache = parentEffectiveAppenders.concat(appenders);\r
+ appenderCacheInvalidated = false;\r
+ }\r
+ return appenderCache;\r
+ };\r
+ \r
+ this.invalidateAppenderCache = function() {\r
+ appenderCacheInvalidated = true;\r
+ for (var i = 0, len = this.children.length; i < len; i++) {\r
+ this.children[i].invalidateAppenderCache();\r
+ }\r
+ };\r
+\r
+ this.log = function(level, params) {\r
+ if (enabled && level.isGreaterOrEqual(this.getEffectiveLevel())) {\r
+ // Check whether last param is an exception\r
+ var exception;\r
+ var finalParamIndex = params.length - 1;\r
+ var lastParam = params[finalParamIndex];\r
+ if (params.length > 1 && isError(lastParam)) {\r
+ exception = lastParam;\r
+ finalParamIndex--;\r
+ }\r
+\r
+ // Construct genuine array for the params\r
+ var messages = [];\r
+ for (var i = 0; i <= finalParamIndex; i++) {\r
+ messages[i] = params[i];\r
+ }\r
+\r
+ var loggingEvent = new LoggingEvent(\r
+ this, new Date(), level, messages, exception);\r
+\r
+ this.callAppenders(loggingEvent);\r
+ }\r
+ };\r
+\r
+ this.callAppenders = function(loggingEvent) {\r
+ var effectiveAppenders = this.getEffectiveAppenders();\r
+ for (var i = 0, len = effectiveAppenders.length; i < len; i++) {\r
+ effectiveAppenders[i].doAppend(loggingEvent);\r
+ }\r
+ };\r
+\r
+ this.setLevel = function(level) {\r
+ // Having a level of null on the root logger would be very bad.\r
+ if (isRoot && level === null) {\r
+ handleError("Logger.setLevel: you cannot set the level of the root logger to null");\r
+ } else if (level instanceof Level) {\r
+ loggerLevel = level;\r
+ } else {\r
+ handleError("Logger.setLevel: level supplied to logger " +\r
+ this.name + " is not an instance of log4javascript.Level");\r
+ }\r
+ };\r
+\r
+ this.getLevel = function() {\r
+ return loggerLevel;\r
+ };\r
+\r
+ this.getEffectiveLevel = function() {\r
+ for (var logger = this; logger !== null; logger = logger.parent) {\r
+ var level = logger.getLevel();\r
+ if (level !== null) {\r
+ return level;\r
+ }\r
+ }\r
+ };\r
+\r
+ this.group = function(name, initiallyExpanded) {\r
+ if (enabled) {\r
+ var effectiveAppenders = this.getEffectiveAppenders();\r
+ for (var i = 0, len = effectiveAppenders.length; i < len; i++) {\r
+ effectiveAppenders[i].group(name, initiallyExpanded);\r
+ }\r
+ }\r
+ };\r
+\r
+ this.groupEnd = function() {\r
+ if (enabled) {\r
+ var effectiveAppenders = this.getEffectiveAppenders();\r
+ for (var i = 0, len = effectiveAppenders.length; i < len; i++) {\r
+ effectiveAppenders[i].groupEnd();\r
+ }\r
+ }\r
+ };\r
+\r
+ var timers = {};\r
+\r
+ this.time = function(name, level) {\r
+ if (enabled) {\r
+ if (isUndefined(name)) {\r
+ handleError("Logger.time: a name for the timer must be supplied");\r
+ } else if (level && !(level instanceof Level)) {\r
+ handleError("Logger.time: level supplied to timer " +\r
+ name + " is not an instance of log4javascript.Level");\r
+ } else {\r
+ timers[name] = new Timer(name, level);\r
+ }\r
+ }\r
+ };\r
+\r
+ this.timeEnd = function(name) {\r
+ if (enabled) {\r
+ if (isUndefined(name)) {\r
+ handleError("Logger.timeEnd: a name for the timer must be supplied");\r
+ } else if (timers[name]) {\r
+ var timer = timers[name];\r
+ var milliseconds = timer.getElapsedTime();\r
+ this.log(timer.level, ["Timer " + toStr(name) + " completed in " + milliseconds + "ms"]);\r
+ delete timers[name];\r
+ } else {\r
+ logLog.warn("Logger.timeEnd: no timer found with name " + name);\r
+ }\r
+ }\r
+ };\r
+\r
+ this.assert = function(expr) {\r
+ if (enabled && !expr) {\r
+ var args = [];\r
+ for (var i = 1, len = arguments.length; i < len; i++) {\r
+ args.push(arguments[i]);\r
+ }\r
+ args = (args.length > 0) ? args : ["Assertion Failure"];\r
+ args.push(newLine);\r
+ args.push(expr);\r
+ this.log(Level.ERROR, args);\r
+ }\r
+ };\r
+\r
+ this.toString = function() {\r
+ return "Logger[" + this.name + "]";\r
+ };\r
+ }\r
+\r
+ Logger.prototype = {\r
+ trace: function() {\r
+ this.log(Level.TRACE, arguments);\r
+ },\r
+\r
+ debug: function() {\r
+ this.log(Level.DEBUG, arguments);\r
+ },\r
+\r
+ info: function() {\r
+ this.log(Level.INFO, arguments);\r
+ },\r
+\r
+ warn: function() {\r
+ this.log(Level.WARN, arguments);\r
+ },\r
+\r
+ error: function() {\r
+ this.log(Level.ERROR, arguments);\r
+ },\r
+\r
+ fatal: function() {\r
+ this.log(Level.FATAL, arguments);\r
+ },\r
+\r
+ isEnabledFor: function(level) {\r
+ return level.isGreaterOrEqual(this.getEffectiveLevel());\r
+ },\r
+\r
+ isTraceEnabled: function() {\r
+ return this.isEnabledFor(Level.TRACE);\r
+ },\r
+\r
+ isDebugEnabled: function() {\r
+ return this.isEnabledFor(Level.DEBUG);\r
+ },\r
+\r
+ isInfoEnabled: function() {\r
+ return this.isEnabledFor(Level.INFO);\r
+ },\r
+\r
+ isWarnEnabled: function() {\r
+ return this.isEnabledFor(Level.WARN);\r
+ },\r
+\r
+ isErrorEnabled: function() {\r
+ return this.isEnabledFor(Level.ERROR);\r
+ },\r
+\r
+ isFatalEnabled: function() {\r
+ return this.isEnabledFor(Level.FATAL);\r
+ }\r
+ };\r
+\r
+ Logger.prototype.trace.isEntryPoint = true;\r
+ Logger.prototype.debug.isEntryPoint = true;\r
+ Logger.prototype.info.isEntryPoint = true;\r
+ Logger.prototype.warn.isEntryPoint = true;\r
+ Logger.prototype.error.isEntryPoint = true;\r
+ Logger.prototype.fatal.isEntryPoint = true;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Logger access methods\r
+\r
+ // Hashtable of loggers keyed by logger name\r
+ var loggers = {};\r
+ var loggerNames = [];\r
+\r
+ var ROOT_LOGGER_DEFAULT_LEVEL = Level.DEBUG;\r
+ var rootLogger = new Logger(rootLoggerName);\r
+ rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);\r
+\r
+ log4javascript.getRootLogger = function() {\r
+ return rootLogger;\r
+ };\r
+\r
+ log4javascript.getLogger = function(loggerName) {\r
+ // Use default logger if loggerName is not specified or invalid\r
+ if (!(typeof loggerName == "string")) {\r
+ loggerName = anonymousLoggerName;\r
+ logLog.warn("log4javascript.getLogger: non-string logger name " +\r
+ toStr(loggerName) + " supplied, returning anonymous logger");\r
+ }\r
+\r
+ // Do not allow retrieval of the root logger by name\r
+ if (loggerName == rootLoggerName) {\r
+ handleError("log4javascript.getLogger: root logger may not be obtained by name");\r
+ }\r
+\r
+ // Create the logger for this name if it doesn't already exist\r
+ if (!loggers[loggerName]) {\r
+ var logger = new Logger(loggerName);\r
+ loggers[loggerName] = logger;\r
+ loggerNames.push(loggerName);\r
+\r
+ // Set up parent logger, if it doesn't exist\r
+ var lastDotIndex = loggerName.lastIndexOf(".");\r
+ var parentLogger;\r
+ if (lastDotIndex > -1) {\r
+ var parentLoggerName = loggerName.substring(0, lastDotIndex);\r
+ parentLogger = log4javascript.getLogger(parentLoggerName); // Recursively sets up grandparents etc.\r
+ } else {\r
+ parentLogger = rootLogger;\r
+ }\r
+ parentLogger.addChild(logger);\r
+ }\r
+ return loggers[loggerName];\r
+ };\r
+\r
+ var defaultLogger = null;\r
+ log4javascript.getDefaultLogger = function() {\r
+ if (!defaultLogger) {\r
+ defaultLogger = log4javascript.getLogger(defaultLoggerName);\r
+ var a = new log4javascript.PopUpAppender();\r
+ defaultLogger.addAppender(a);\r
+ }\r
+ return defaultLogger;\r
+ };\r
+\r
+ var nullLogger = null;\r
+ log4javascript.getNullLogger = function() {\r
+ if (!nullLogger) {\r
+ nullLogger = new Logger(nullLoggerName);\r
+ nullLogger.setLevel(Level.OFF);\r
+ }\r
+ return nullLogger;\r
+ };\r
+\r
+ // Destroys all loggers\r
+ log4javascript.resetConfiguration = function() {\r
+ rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);\r
+ loggers = {};\r
+ };\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Logging events\r
+\r
+ var LoggingEvent = function(logger, timeStamp, level, messages,\r
+ exception) {\r
+ this.logger = logger;\r
+ this.timeStamp = timeStamp;\r
+ this.timeStampInMilliseconds = timeStamp.getTime();\r
+ this.timeStampInSeconds = Math.floor(this.timeStampInMilliseconds / 1000);\r
+ this.milliseconds = this.timeStamp.getMilliseconds();\r
+ this.level = level;\r
+ this.messages = messages;\r
+ this.exception = exception;\r
+ };\r
+\r
+ LoggingEvent.prototype = {\r
+ getThrowableStrRep: function() {\r
+ return this.exception ?\r
+ getExceptionStringRep(this.exception) : "";\r
+ },\r
+ getCombinedMessages: function() {\r
+ return (this.messages.length == 1) ? this.messages[0] :\r
+ this.messages.join(newLine);\r
+ },\r
+ toString: function() {\r
+ return "LoggingEvent[" + this.level + "]";\r
+ }\r
+ };\r
+\r
+ log4javascript.LoggingEvent = LoggingEvent;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Layout prototype\r
+\r
+ var Layout = function() {\r
+ };\r
+\r
+ Layout.prototype = {\r
+ defaults: {\r
+ loggerKey: "logger",\r
+ timeStampKey: "timestamp",\r
+ millisecondsKey: "milliseconds",\r
+ levelKey: "level",\r
+ messageKey: "message",\r
+ exceptionKey: "exception",\r
+ urlKey: "url"\r
+ },\r
+ loggerKey: "logger",\r
+ timeStampKey: "timestamp",\r
+ millisecondsKey: "milliseconds",\r
+ levelKey: "level",\r
+ messageKey: "message",\r
+ exceptionKey: "exception",\r
+ urlKey: "url",\r
+ batchHeader: "",\r
+ batchFooter: "",\r
+ batchSeparator: "",\r
+ returnsPostData: false,\r
+ overrideTimeStampsSetting: false,\r
+ useTimeStampsInMilliseconds: null,\r
+\r
+ format: function() {\r
+ handleError("Layout.format: layout supplied has no format() method");\r
+ },\r
+\r
+ ignoresThrowable: function() {\r
+ handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");\r
+ },\r
+\r
+ getContentType: function() {\r
+ return "text/plain";\r
+ },\r
+\r
+ allowBatching: function() {\r
+ return true;\r
+ },\r
+\r
+ setTimeStampsInMilliseconds: function(timeStampsInMilliseconds) {\r
+ this.overrideTimeStampsSetting = true;\r
+ this.useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);\r
+ },\r
+\r
+ isTimeStampsInMilliseconds: function() {\r
+ return this.overrideTimeStampsSetting ?\r
+ this.useTimeStampsInMilliseconds : useTimeStampsInMilliseconds;\r
+ },\r
+\r
+ getTimeStampValue: function(loggingEvent) {\r
+ return this.isTimeStampsInMilliseconds() ?\r
+ loggingEvent.timeStampInMilliseconds : loggingEvent.timeStampInSeconds;\r
+ },\r
+\r
+ getDataValues: function(loggingEvent, combineMessages) {\r
+ var dataValues = [\r
+ [this.loggerKey, loggingEvent.logger.name],\r
+ [this.timeStampKey, this.getTimeStampValue(loggingEvent)],\r
+ [this.levelKey, loggingEvent.level.name],\r
+ [this.urlKey, window.location.href],\r
+ [this.messageKey, combineMessages ? loggingEvent.getCombinedMessages() : loggingEvent.messages]\r
+ ];\r
+ if (!this.isTimeStampsInMilliseconds()) {\r
+ dataValues.push([this.millisecondsKey, loggingEvent.milliseconds]);\r
+ }\r
+ if (loggingEvent.exception) {\r
+ dataValues.push([this.exceptionKey, getExceptionStringRep(loggingEvent.exception)]);\r
+ }\r
+ if (this.hasCustomFields()) {\r
+ for (var i = 0, len = this.customFields.length; i < len; i++) {\r
+ var val = this.customFields[i].value;\r
+\r
+ // Check if the value is a function. If so, execute it, passing it the\r
+ // current layout and the logging event\r
+ if (typeof val === "function") {\r
+ val = val(this, loggingEvent);\r
+ }\r
+ dataValues.push([this.customFields[i].name, val]);\r
+ }\r
+ }\r
+ return dataValues;\r
+ },\r
+\r
+ setKeys: function(loggerKey, timeStampKey, levelKey, messageKey,\r
+ exceptionKey, urlKey, millisecondsKey) {\r
+ this.loggerKey = extractStringFromParam(loggerKey, this.defaults.loggerKey);\r
+ this.timeStampKey = extractStringFromParam(timeStampKey, this.defaults.timeStampKey);\r
+ this.levelKey = extractStringFromParam(levelKey, this.defaults.levelKey);\r
+ this.messageKey = extractStringFromParam(messageKey, this.defaults.messageKey);\r
+ this.exceptionKey = extractStringFromParam(exceptionKey, this.defaults.exceptionKey);\r
+ this.urlKey = extractStringFromParam(urlKey, this.defaults.urlKey);\r
+ this.millisecondsKey = extractStringFromParam(millisecondsKey, this.defaults.millisecondsKey);\r
+ },\r
+\r
+ setCustomField: function(name, value) {\r
+ var fieldUpdated = false;\r
+ for (var i = 0, len = this.customFields.length; i < len; i++) {\r
+ if (this.customFields[i].name === name) {\r
+ this.customFields[i].value = value;\r
+ fieldUpdated = true;\r
+ }\r
+ }\r
+ if (!fieldUpdated) {\r
+ this.customFields.push({"name": name, "value": value});\r
+ }\r
+ },\r
+\r
+ hasCustomFields: function() {\r
+ return (this.customFields.length > 0);\r
+ },\r
+\r
+ toString: function() {\r
+ handleError("Layout.toString: all layouts must override this method");\r
+ }\r
+ };\r
+\r
+ log4javascript.Layout = Layout;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Appender prototype\r
+\r
+ var Appender = function() {};\r
+\r
+ Appender.prototype = new EventSupport();\r
+\r
+ Appender.prototype.layout = new PatternLayout();\r
+ Appender.prototype.threshold = Level.ALL;\r
+ Appender.prototype.loggers = [];\r
+\r
+ // Performs threshold checks before delegating actual logging to the\r
+ // subclass's specific append method.\r
+ Appender.prototype.doAppend = function(loggingEvent) {\r
+ if (enabled && loggingEvent.level.level >= this.threshold.level) {\r
+ this.append(loggingEvent);\r
+ }\r
+ };\r
+\r
+ Appender.prototype.append = function(loggingEvent) {};\r
+\r
+ Appender.prototype.setLayout = function(layout) {\r
+ if (layout instanceof Layout) {\r
+ this.layout = layout;\r
+ } else {\r
+ handleError("Appender.setLayout: layout supplied to " +\r
+ this.toString() + " is not a subclass of Layout");\r
+ }\r
+ };\r
+\r
+ Appender.prototype.getLayout = function() {\r
+ return this.layout;\r
+ };\r
+\r
+ Appender.prototype.setThreshold = function(threshold) {\r
+ if (threshold instanceof Level) {\r
+ this.threshold = threshold;\r
+ } else {\r
+ handleError("Appender.setThreshold: threshold supplied to " +\r
+ this.toString() + " is not a subclass of Level");\r
+ }\r
+ };\r
+\r
+ Appender.prototype.getThreshold = function() {\r
+ return this.threshold;\r
+ };\r
+\r
+ Appender.prototype.setAddedToLogger = function(logger) {\r
+ this.loggers.push(logger);\r
+ };\r
+\r
+ Appender.prototype.setRemovedFromLogger = function(logger) {\r
+ array_remove(this.loggers, logger);\r
+ };\r
+\r
+ Appender.prototype.group = emptyFunction;\r
+ Appender.prototype.groupEnd = emptyFunction;\r
+\r
+ Appender.prototype.toString = function() {\r
+ handleError("Appender.toString: all appenders must override this method");\r
+ };\r
+\r
+ log4javascript.Appender = Appender;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // SimpleLayout \r
+\r
+ function SimpleLayout() {\r
+ this.customFields = [];\r
+ }\r
+\r
+ SimpleLayout.prototype = new Layout();\r
+\r
+ SimpleLayout.prototype.format = function(loggingEvent) {\r
+ return loggingEvent.level.name + " - " + loggingEvent.getCombinedMessages();\r
+ };\r
+\r
+ SimpleLayout.prototype.ignoresThrowable = function() {\r
+ return true;\r
+ };\r
+\r
+ SimpleLayout.prototype.toString = function() {\r
+ return "SimpleLayout";\r
+ };\r
+\r
+ log4javascript.SimpleLayout = SimpleLayout;\r
+ /* ----------------------------------------------------------------------- */\r
+ // NullLayout \r
+\r
+ function NullLayout() {\r
+ this.customFields = [];\r
+ }\r
+\r
+ NullLayout.prototype = new Layout();\r
+\r
+ NullLayout.prototype.format = function(loggingEvent) {\r
+ return loggingEvent.messages;\r
+ };\r
+\r
+ NullLayout.prototype.ignoresThrowable = function() {\r
+ return true;\r
+ };\r
+\r
+ NullLayout.prototype.toString = function() {\r
+ return "NullLayout";\r
+ };\r
+\r
+ log4javascript.NullLayout = NullLayout;\r
+/* ---------------------------------------------------------------------- */\r
+ // XmlLayout\r
+\r
+ function XmlLayout(combineMessages) {\r
+ this.combineMessages = extractBooleanFromParam(combineMessages, true);\r
+ this.customFields = [];\r
+ }\r
+\r
+ XmlLayout.prototype = new Layout();\r
+\r
+ XmlLayout.prototype.isCombinedMessages = function() {\r
+ return this.combineMessages;\r
+ };\r
+\r
+ XmlLayout.prototype.getContentType = function() {\r
+ return "text/xml";\r
+ };\r
+\r
+ XmlLayout.prototype.escapeCdata = function(str) {\r
+ return str.replace(/\]\]>/, "]]>]]><![CDATA[");\r
+ };\r
+\r
+ XmlLayout.prototype.format = function(loggingEvent) {\r
+ var layout = this;\r
+ var i, len;\r
+ function formatMessage(message) {\r
+ message = (typeof message === "string") ? message : toStr(message);\r
+ return "<log4javascript:message><![CDATA[" +\r
+ layout.escapeCdata(message) + "]]></log4javascript:message>";\r
+ }\r
+\r
+ var str = "<log4javascript:event logger=\"" + loggingEvent.logger.name +\r
+ "\" timestamp=\"" + this.getTimeStampValue(loggingEvent) + "\"";\r
+ if (!this.isTimeStampsInMilliseconds()) {\r
+ str += " milliseconds=\"" + loggingEvent.milliseconds + "\"";\r
+ }\r
+ str += " level=\"" + loggingEvent.level.name + "\">" + newLine;\r
+ if (this.combineMessages) {\r
+ str += formatMessage(loggingEvent.getCombinedMessages());\r
+ } else {\r
+ str += "<log4javascript:messages>" + newLine;\r
+ for (i = 0, len = loggingEvent.messages.length; i < len; i++) {\r
+ str += formatMessage(loggingEvent.messages[i]) + newLine;\r
+ }\r
+ str += "</log4javascript:messages>" + newLine;\r
+ }\r
+ if (this.hasCustomFields()) {\r
+ for (i = 0, len = this.customFields.length; i < len; i++) {\r
+ str += "<log4javascript:customfield name=\"" +\r
+ this.customFields[i].name + "\"><![CDATA[" +\r
+ this.customFields[i].value.toString() +\r
+ "]]></log4javascript:customfield>" + newLine;\r
+ }\r
+ }\r
+ if (loggingEvent.exception) {\r
+ str += "<log4javascript:exception><![CDATA[" +\r
+ getExceptionStringRep(loggingEvent.exception) +\r
+ "]]></log4javascript:exception>" + newLine;\r
+ }\r
+ str += "</log4javascript:event>" + newLine + newLine;\r
+ return str;\r
+ };\r
+\r
+ XmlLayout.prototype.ignoresThrowable = function() {\r
+ return false;\r
+ };\r
+\r
+ XmlLayout.prototype.toString = function() {\r
+ return "XmlLayout";\r
+ };\r
+\r
+ log4javascript.XmlLayout = XmlLayout;\r
+ /* ---------------------------------------------------------------------- */\r
+ // JsonLayout related\r
+\r
+ function escapeNewLines(str) {\r
+ return str.replace(/\r\n|\r|\n/g, "\\r\\n");\r
+ }\r
+\r
+ function JsonLayout(readable, combineMessages) {\r
+ this.readable = extractBooleanFromParam(readable, false);\r
+ this.combineMessages = extractBooleanFromParam(combineMessages, true);\r
+ this.batchHeader = this.readable ? "[" + newLine : "[";\r
+ this.batchFooter = this.readable ? "]" + newLine : "]";\r
+ this.batchSeparator = this.readable ? "," + newLine : ",";\r
+ this.setKeys();\r
+ this.colon = this.readable ? ": " : ":";\r
+ this.tab = this.readable ? "\t" : "";\r
+ this.lineBreak = this.readable ? newLine : "";\r
+ this.customFields = [];\r
+ }\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // JsonLayout\r
+\r
+ JsonLayout.prototype = new Layout();\r
+\r
+ JsonLayout.prototype.isReadable = function() {\r
+ return this.readable;\r
+ };\r
+\r
+ JsonLayout.prototype.isCombinedMessages = function() {\r
+ return this.combineMessages;\r
+ };\r
+\r
+ JsonLayout.prototype.format = function(loggingEvent) {\r
+ var layout = this;\r
+ var dataValues = this.getDataValues(loggingEvent, this.combineMessages);\r
+ var str = "{" + this.lineBreak;\r
+ var i, len;\r
+\r
+ function formatValue(val, prefix, expand) {\r
+ // Check the type of the data value to decide whether quotation marks\r
+ // or expansion are required\r
+ var formattedValue;\r
+ var valType = typeof val;\r
+ if (val instanceof Date) {\r
+ formattedValue = String(val.getTime());\r
+ } else if (expand && (val instanceof Array)) {\r
+ formattedValue = "[" + layout.lineBreak;\r
+ for (var i = 0, len = val.length; i < len; i++) {\r
+ var childPrefix = prefix + layout.tab;\r
+ formattedValue += childPrefix + formatValue(val[i], childPrefix, false);\r
+ if (i < val.length - 1) {\r
+ formattedValue += ",";\r
+ }\r
+ formattedValue += layout.lineBreak;\r
+ }\r
+ formattedValue += prefix + "]";\r
+ } else if (valType !== "number" && valType !== "boolean") {\r
+ formattedValue = "\"" + escapeNewLines(toStr(val).replace(/\"/g, "\\\"")) + "\"";\r
+ } else {\r
+ formattedValue = val;\r
+ }\r
+ return formattedValue;\r
+ }\r
+\r
+ for (i = 0, len = dataValues.length - 1; i <= len; i++) {\r
+ str += this.tab + "\"" + dataValues[i][0] + "\"" + this.colon + formatValue(dataValues[i][1], this.tab, true);\r
+ if (i < len) {\r
+ str += ",";\r
+ }\r
+ str += this.lineBreak;\r
+ }\r
+\r
+ str += "}" + this.lineBreak;\r
+ return str;\r
+ };\r
+\r
+ JsonLayout.prototype.ignoresThrowable = function() {\r
+ return false;\r
+ };\r
+\r
+ JsonLayout.prototype.toString = function() {\r
+ return "JsonLayout";\r
+ };\r
+\r
+ JsonLayout.prototype.getContentType = function() {\r
+ return "application/json";\r
+ };\r
+\r
+ log4javascript.JsonLayout = JsonLayout;\r
+ /* ---------------------------------------------------------------------- */\r
+ // HttpPostDataLayout\r
+\r
+ function HttpPostDataLayout() {\r
+ this.setKeys();\r
+ this.customFields = [];\r
+ this.returnsPostData = true;\r
+ }\r
+\r
+ HttpPostDataLayout.prototype = new Layout();\r
+\r
+ // Disable batching\r
+ HttpPostDataLayout.prototype.allowBatching = function() {\r
+ return false;\r
+ };\r
+\r
+ HttpPostDataLayout.prototype.format = function(loggingEvent) {\r
+ var dataValues = this.getDataValues(loggingEvent);\r
+ var queryBits = [];\r
+ for (var i = 0, len = dataValues.length; i < len; i++) {\r
+ var val = (dataValues[i][1] instanceof Date) ?\r
+ String(dataValues[i][1].getTime()) : dataValues[i][1];\r
+ queryBits.push(urlEncode(dataValues[i][0]) + "=" + urlEncode(val));\r
+ }\r
+ return queryBits.join("&");\r
+ };\r
+\r
+ HttpPostDataLayout.prototype.ignoresThrowable = function(loggingEvent) {\r
+ return false;\r
+ };\r
+\r
+ HttpPostDataLayout.prototype.toString = function() {\r
+ return "HttpPostDataLayout";\r
+ };\r
+\r
+ log4javascript.HttpPostDataLayout = HttpPostDataLayout;\r
+ /* ---------------------------------------------------------------------- */\r
+ // formatObjectExpansion\r
+\r
+ function formatObjectExpansion(obj, depth, indentation) {\r
+ var objectsExpanded = [];\r
+\r
+ function doFormat(obj, depth, indentation) {\r
+ var i, j, len, childDepth, childIndentation, childLines, expansion,\r
+ childExpansion;\r
+\r
+ if (!indentation) {\r
+ indentation = "";\r
+ }\r
+\r
+ function formatString(text) {\r
+ var lines = splitIntoLines(text);\r
+ for (var j = 1, jLen = lines.length; j < jLen; j++) {\r
+ lines[j] = indentation + lines[j];\r
+ }\r
+ return lines.join(newLine);\r
+ }\r
+\r
+ if (obj === null) {\r
+ return "null";\r
+ } else if (typeof obj == "undefined") {\r
+ return "undefined";\r
+ } else if (typeof obj == "string") {\r
+ return formatString(obj);\r
+ } else if (typeof obj == "object" && array_contains(objectsExpanded, obj)) {\r
+ try {\r
+ expansion = toStr(obj);\r
+ } catch (ex) {\r
+ expansion = "Error formatting property. Details: " + getExceptionStringRep(ex);\r
+ }\r
+ return expansion + " [already expanded]";\r
+ } else if ((obj instanceof Array) && depth > 0) {\r
+ objectsExpanded.push(obj);\r
+ expansion = "[" + newLine;\r
+ childDepth = depth - 1;\r
+ childIndentation = indentation + " ";\r
+ childLines = [];\r
+ for (i = 0, len = obj.length; i < len; i++) {\r
+ try {\r
+ childExpansion = doFormat(obj[i], childDepth, childIndentation);\r
+ childLines.push(childIndentation + childExpansion);\r
+ } catch (ex) {\r
+ childLines.push(childIndentation + "Error formatting array member. Details: " +\r
+ getExceptionStringRep(ex) + "");\r
+ }\r
+ }\r
+ expansion += childLines.join("," + newLine) + newLine + indentation + "]";\r
+ return expansion;\r
+ } else if (Object.prototype.toString.call(obj) == "[object Date]") {\r
+ return obj.toString();\r
+ } else if (typeof obj == "object" && depth > 0) {\r
+ objectsExpanded.push(obj);\r
+ expansion = "{" + newLine;\r
+ childDepth = depth - 1;\r
+ childIndentation = indentation + " ";\r
+ childLines = [];\r
+ for (i in obj) {\r
+ try {\r
+ childExpansion = doFormat(obj[i], childDepth, childIndentation);\r
+ childLines.push(childIndentation + i + ": " + childExpansion);\r
+ } catch (ex) {\r
+ childLines.push(childIndentation + i + ": Error formatting property. Details: " +\r
+ getExceptionStringRep(ex));\r
+ }\r
+ }\r
+ expansion += childLines.join("," + newLine) + newLine + indentation + "}";\r
+ return expansion;\r
+ } else {\r
+ return formatString(toStr(obj));\r
+ }\r
+ }\r
+ return doFormat(obj, depth, indentation);\r
+ }\r
+ /* ---------------------------------------------------------------------- */\r
+ // Date-related stuff\r
+\r
+ var SimpleDateFormat;\r
+\r
+ (function() {\r
+ 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']+)/;\r
+ var monthNames = ["January", "February", "March", "April", "May", "June",\r
+ "July", "August", "September", "October", "November", "December"];\r
+ var dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];\r
+ var TEXT2 = 0, TEXT3 = 1, NUMBER = 2, YEAR = 3, MONTH = 4, TIMEZONE = 5;\r
+ var types = {\r
+ G : TEXT2,\r
+ y : YEAR,\r
+ M : MONTH,\r
+ w : NUMBER,\r
+ W : NUMBER,\r
+ D : NUMBER,\r
+ d : NUMBER,\r
+ F : NUMBER,\r
+ E : TEXT3,\r
+ a : TEXT2,\r
+ H : NUMBER,\r
+ k : NUMBER,\r
+ K : NUMBER,\r
+ h : NUMBER,\r
+ m : NUMBER,\r
+ s : NUMBER,\r
+ S : NUMBER,\r
+ Z : TIMEZONE\r
+ };\r
+ var ONE_DAY = 24 * 60 * 60 * 1000;\r
+ var ONE_WEEK = 7 * ONE_DAY;\r
+ var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK = 1;\r
+\r
+ var newDateAtMidnight = function(year, month, day) {\r
+ var d = new Date(year, month, day, 0, 0, 0);\r
+ d.setMilliseconds(0);\r
+ return d;\r
+ };\r
+\r
+ Date.prototype.getDifference = function(date) {\r
+ return this.getTime() - date.getTime();\r
+ };\r
+\r
+ Date.prototype.isBefore = function(d) {\r
+ return this.getTime() < d.getTime();\r
+ };\r
+\r
+ Date.prototype.getUTCTime = function() {\r
+ return Date.UTC(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours(), this.getMinutes(),\r
+ this.getSeconds(), this.getMilliseconds());\r
+ };\r
+\r
+ Date.prototype.getTimeSince = function(d) {\r
+ return this.getUTCTime() - d.getUTCTime();\r
+ };\r
+\r
+ Date.prototype.getPreviousSunday = function() {\r
+ // Using midday avoids any possibility of DST messing things up\r
+ var midday = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 12, 0, 0);\r
+ var previousSunday = new Date(midday.getTime() - this.getDay() * ONE_DAY);\r
+ return newDateAtMidnight(previousSunday.getFullYear(), previousSunday.getMonth(),\r
+ previousSunday.getDate());\r
+ };\r
+\r
+ Date.prototype.getWeekInYear = function(minimalDaysInFirstWeek) {\r
+ if (isUndefined(this.minimalDaysInFirstWeek)) {\r
+ minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;\r
+ }\r
+ var previousSunday = this.getPreviousSunday();\r
+ var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);\r
+ var numberOfSundays = previousSunday.isBefore(startOfYear) ?\r
+ 0 : 1 + Math.floor(previousSunday.getTimeSince(startOfYear) / ONE_WEEK);\r
+ var numberOfDaysInFirstWeek = 7 - startOfYear.getDay();\r
+ var weekInYear = numberOfSundays;\r
+ if (numberOfDaysInFirstWeek < minimalDaysInFirstWeek) {\r
+ weekInYear--;\r
+ }\r
+ return weekInYear;\r
+ };\r
+\r
+ Date.prototype.getWeekInMonth = function(minimalDaysInFirstWeek) {\r
+ if (isUndefined(this.minimalDaysInFirstWeek)) {\r
+ minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;\r
+ }\r
+ var previousSunday = this.getPreviousSunday();\r
+ var startOfMonth = newDateAtMidnight(this.getFullYear(), this.getMonth(), 1);\r
+ var numberOfSundays = previousSunday.isBefore(startOfMonth) ?\r
+ 0 : 1 + Math.floor(previousSunday.getTimeSince(startOfMonth) / ONE_WEEK);\r
+ var numberOfDaysInFirstWeek = 7 - startOfMonth.getDay();\r
+ var weekInMonth = numberOfSundays;\r
+ if (numberOfDaysInFirstWeek >= minimalDaysInFirstWeek) {\r
+ weekInMonth++;\r
+ }\r
+ return weekInMonth;\r
+ };\r
+\r
+ Date.prototype.getDayInYear = function() {\r
+ var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);\r
+ return 1 + Math.floor(this.getTimeSince(startOfYear) / ONE_DAY);\r
+ };\r
+\r
+ /* ------------------------------------------------------------------ */\r
+\r
+ SimpleDateFormat = function(formatString) {\r
+ this.formatString = formatString;\r
+ };\r
+\r
+ /**\r
+ * Sets the minimum number of days in a week in order for that week to\r
+ * be considered as belonging to a particular month or year\r
+ */\r
+ SimpleDateFormat.prototype.setMinimalDaysInFirstWeek = function(days) {\r
+ this.minimalDaysInFirstWeek = days;\r
+ };\r
+\r
+ SimpleDateFormat.prototype.getMinimalDaysInFirstWeek = function() {\r
+ return isUndefined(this.minimalDaysInFirstWeek) ?\r
+ DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK : this.minimalDaysInFirstWeek;\r
+ };\r
+\r
+ var padWithZeroes = function(str, len) {\r
+ while (str.length < len) {\r
+ str = "0" + str;\r
+ }\r
+ return str;\r
+ };\r
+\r
+ var formatText = function(data, numberOfLetters, minLength) {\r
+ return (numberOfLetters >= 4) ? data : data.substr(0, Math.max(minLength, numberOfLetters));\r
+ };\r
+\r
+ var formatNumber = function(data, numberOfLetters) {\r
+ var dataString = "" + data;\r
+ // Pad with 0s as necessary\r
+ return padWithZeroes(dataString, numberOfLetters);\r
+ };\r
+\r
+ SimpleDateFormat.prototype.format = function(date) {\r
+ var formattedString = "";\r
+ var result;\r
+ var searchString = this.formatString;\r
+ while ((result = regex.exec(searchString))) {\r
+ var quotedString = result[1];\r
+ var patternLetters = result[2];\r
+ var otherLetters = result[3];\r
+ var otherCharacters = result[4];\r
+\r
+ // If the pattern matched is quoted string, output the text between the quotes\r
+ if (quotedString) {\r
+ if (quotedString == "''") {\r
+ formattedString += "'";\r
+ } else {\r
+ formattedString += quotedString.substring(1, quotedString.length - 1);\r
+ }\r
+ } else if (otherLetters) {\r
+ // Swallow non-pattern letters by doing nothing here\r
+ } else if (otherCharacters) {\r
+ // Simply output other characters\r
+ formattedString += otherCharacters;\r
+ } else if (patternLetters) {\r
+ // Replace pattern letters\r
+ var patternLetter = patternLetters.charAt(0);\r
+ var numberOfLetters = patternLetters.length;\r
+ var rawData = "";\r
+ switch(patternLetter) {\r
+ case "G":\r
+ rawData = "AD";\r
+ break;\r
+ case "y":\r
+ rawData = date.getFullYear();\r
+ break;\r
+ case "M":\r
+ rawData = date.getMonth();\r
+ break;\r
+ case "w":\r
+ rawData = date.getWeekInYear(this.getMinimalDaysInFirstWeek());\r
+ break;\r
+ case "W":\r
+ rawData = date.getWeekInMonth(this.getMinimalDaysInFirstWeek());\r
+ break;\r
+ case "D":\r
+ rawData = date.getDayInYear();\r
+ break;\r
+ case "d":\r
+ rawData = date.getDate();\r
+ break;\r
+ case "F":\r
+ rawData = 1 + Math.floor((date.getDate() - 1) / 7);\r
+ break;\r
+ case "E":\r
+ rawData = dayNames[date.getDay()];\r
+ break;\r
+ case "a":\r
+ rawData = (date.getHours() >= 12) ? "PM" : "AM";\r
+ break;\r
+ case "H":\r
+ rawData = date.getHours();\r
+ break;\r
+ case "k":\r
+ rawData = date.getHours() || 24;\r
+ break;\r
+ case "K":\r
+ rawData = date.getHours() % 12;\r
+ break;\r
+ case "h":\r
+ rawData = (date.getHours() % 12) || 12;\r
+ break;\r
+ case "m":\r
+ rawData = date.getMinutes();\r
+ break;\r
+ case "s":\r
+ rawData = date.getSeconds();\r
+ break;\r
+ case "S":\r
+ rawData = date.getMilliseconds();\r
+ break;\r
+ case "Z":\r
+ rawData = date.getTimezoneOffset(); // This returns the number of minutes since GMT was this time.\r
+ break;\r
+ }\r
+ // Format the raw data depending on the type\r
+ switch(types[patternLetter]) {\r
+ case TEXT2:\r
+ formattedString += formatText(rawData, numberOfLetters, 2);\r
+ break;\r
+ case TEXT3:\r
+ formattedString += formatText(rawData, numberOfLetters, 3);\r
+ break;\r
+ case NUMBER:\r
+ formattedString += formatNumber(rawData, numberOfLetters);\r
+ break;\r
+ case YEAR:\r
+ if (numberOfLetters <= 3) {\r
+ // Output a 2-digit year\r
+ var dataString = "" + rawData;\r
+ formattedString += dataString.substr(2, 2);\r
+ } else {\r
+ formattedString += formatNumber(rawData, numberOfLetters);\r
+ }\r
+ break;\r
+ case MONTH:\r
+ if (numberOfLetters >= 3) {\r
+ formattedString += formatText(monthNames[rawData], numberOfLetters, numberOfLetters);\r
+ } else {\r
+ // NB. Months returned by getMonth are zero-based\r
+ formattedString += formatNumber(rawData + 1, numberOfLetters);\r
+ }\r
+ break;\r
+ case TIMEZONE:\r
+ var isPositive = (rawData > 0);\r
+ // The following line looks like a mistake but isn't\r
+ // because of the way getTimezoneOffset measures.\r
+ var prefix = isPositive ? "-" : "+";\r
+ var absData = Math.abs(rawData);\r
+\r
+ // Hours\r
+ var hours = "" + Math.floor(absData / 60);\r
+ hours = padWithZeroes(hours, 2);\r
+ // Minutes\r
+ var minutes = "" + (absData % 60);\r
+ minutes = padWithZeroes(minutes, 2);\r
+\r
+ formattedString += prefix + hours + minutes;\r
+ break;\r
+ }\r
+ }\r
+ searchString = searchString.substr(result.index + result[0].length);\r
+ }\r
+ return formattedString;\r
+ };\r
+ })();\r
+\r
+ log4javascript.SimpleDateFormat = SimpleDateFormat;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // PatternLayout\r
+\r
+ function PatternLayout(pattern) {\r
+ if (pattern) {\r
+ this.pattern = pattern;\r
+ } else {\r
+ this.pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;\r
+ }\r
+ this.customFields = [];\r
+ }\r
+\r
+ PatternLayout.TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n";\r
+ PatternLayout.DEFAULT_CONVERSION_PATTERN = "%m%n";\r
+ PatternLayout.ISO8601_DATEFORMAT = "yyyy-MM-dd HH:mm:ss,SSS";\r
+ PatternLayout.DATETIME_DATEFORMAT = "dd MMM yyyy HH:mm:ss,SSS";\r
+ PatternLayout.ABSOLUTETIME_DATEFORMAT = "HH:mm:ss,SSS";\r
+\r
+ PatternLayout.prototype = new Layout();\r
+\r
+ PatternLayout.prototype.format = function(loggingEvent) {\r
+ var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;\r
+ var formattedString = "";\r
+ var result;\r
+ var searchString = this.pattern;\r
+\r
+ // Cannot use regex global flag since it doesn't work with exec in IE5\r
+ while ((result = regex.exec(searchString))) {\r
+ var matchedString = result[0];\r
+ var padding = result[1];\r
+ var truncation = result[2];\r
+ var conversionCharacter = result[3];\r
+ var specifier = result[5];\r
+ var text = result[6];\r
+\r
+ // Check if the pattern matched was just normal text\r
+ if (text) {\r
+ formattedString += "" + text;\r
+ } else {\r
+ // Create a raw replacement string based on the conversion\r
+ // character and specifier\r
+ var replacement = "";\r
+ switch(conversionCharacter) {\r
+ case "a": // Array of messages\r
+ case "m": // Message\r
+ var depth = 0;\r
+ if (specifier) {\r
+ depth = parseInt(specifier, 10);\r
+ if (isNaN(depth)) {\r
+ handleError("PatternLayout.format: invalid specifier '" +\r
+ specifier + "' for conversion character '" + conversionCharacter +\r
+ "' - should be a number");\r
+ depth = 0;\r
+ }\r
+ }\r
+ var messages = (conversionCharacter === "a") ? loggingEvent.messages[0] : loggingEvent.messages;\r
+ for (var i = 0, len = messages.length; i < len; i++) {\r
+ if (i > 0 && (replacement.charAt(replacement.length - 1) !== " ")) {\r
+ replacement += " ";\r
+ }\r
+ if (depth === 0) {\r
+ replacement += messages[i];\r
+ } else {\r
+ replacement += formatObjectExpansion(messages[i], depth);\r
+ }\r
+ }\r
+ break;\r
+ case "c": // Logger name\r
+ var loggerName = loggingEvent.logger.name;\r
+ if (specifier) {\r
+ var precision = parseInt(specifier, 10);\r
+ var loggerNameBits = loggingEvent.logger.name.split(".");\r
+ if (precision >= loggerNameBits.length) {\r
+ replacement = loggerName;\r
+ } else {\r
+ replacement = loggerNameBits.slice(loggerNameBits.length - precision).join(".");\r
+ }\r
+ } else {\r
+ replacement = loggerName;\r
+ }\r
+ break;\r
+ case "d": // Date\r
+ var dateFormat = PatternLayout.ISO8601_DATEFORMAT;\r
+ if (specifier) {\r
+ dateFormat = specifier;\r
+ // Pick up special cases\r
+ if (dateFormat == "ISO8601") {\r
+ dateFormat = PatternLayout.ISO8601_DATEFORMAT;\r
+ } else if (dateFormat == "ABSOLUTE") {\r
+ dateFormat = PatternLayout.ABSOLUTETIME_DATEFORMAT;\r
+ } else if (dateFormat == "DATE") {\r
+ dateFormat = PatternLayout.DATETIME_DATEFORMAT;\r
+ }\r
+ }\r
+ // Format the date\r
+ replacement = (new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);\r
+ break;\r
+ case "f": // Custom field\r
+ if (this.hasCustomFields()) {\r
+ var fieldIndex = 0;\r
+ if (specifier) {\r
+ fieldIndex = parseInt(specifier, 10);\r
+ if (isNaN(fieldIndex)) {\r
+ handleError("PatternLayout.format: invalid specifier '" +\r
+ specifier + "' for conversion character 'f' - should be a number");\r
+ } else if (fieldIndex === 0) {\r
+ handleError("PatternLayout.format: invalid specifier '" +\r
+ specifier + "' for conversion character 'f' - must be greater than zero");\r
+ } else if (fieldIndex > this.customFields.length) {\r
+ handleError("PatternLayout.format: invalid specifier '" +\r
+ specifier + "' for conversion character 'f' - there aren't that many custom fields");\r
+ } else {\r
+ fieldIndex = fieldIndex - 1;\r
+ }\r
+ }\r
+ var val = this.customFields[fieldIndex].value;\r
+ if (typeof val == "function") {\r
+ val = val(this, loggingEvent);\r
+ }\r
+ replacement = val;\r
+ }\r
+ break;\r
+ case "n": // New line\r
+ replacement = newLine;\r
+ break;\r
+ case "p": // Level\r
+ replacement = loggingEvent.level.name;\r
+ break;\r
+ case "r": // Milliseconds since log4javascript startup\r
+ replacement = "" + loggingEvent.timeStamp.getDifference(applicationStartDate);\r
+ break;\r
+ case "%": // Literal % sign\r
+ replacement = "%";\r
+ break;\r
+ default:\r
+ replacement = matchedString;\r
+ break;\r
+ }\r
+ // Format the replacement according to any padding or\r
+ // truncation specified\r
+ var l;\r
+\r
+ // First, truncation\r
+ if (truncation) {\r
+ l = parseInt(truncation.substr(1), 10);\r
+ var strLen = replacement.length;\r
+ if (l < strLen) {\r
+ replacement = replacement.substring(strLen - l, strLen);\r
+ }\r
+ }\r
+ // Next, padding\r
+ if (padding) {\r
+ if (padding.charAt(0) == "-") {\r
+ l = parseInt(padding.substr(1), 10);\r
+ // Right pad with spaces\r
+ while (replacement.length < l) {\r
+ replacement += " ";\r
+ }\r
+ } else {\r
+ l = parseInt(padding, 10);\r
+ // Left pad with spaces\r
+ while (replacement.length < l) {\r
+ replacement = " " + replacement;\r
+ }\r
+ }\r
+ }\r
+ formattedString += replacement;\r
+ }\r
+ searchString = searchString.substr(result.index + result[0].length);\r
+ }\r
+ return formattedString;\r
+ };\r
+\r
+ PatternLayout.prototype.ignoresThrowable = function() {\r
+ return true;\r
+ };\r
+\r
+ PatternLayout.prototype.toString = function() {\r
+ return "PatternLayout";\r
+ };\r
+\r
+ log4javascript.PatternLayout = PatternLayout;\r
+ /* ---------------------------------------------------------------------- */\r
+ // AlertAppender\r
+\r
+ function AlertAppender() {}\r
+\r
+ AlertAppender.prototype = new Appender();\r
+\r
+ AlertAppender.prototype.layout = new SimpleLayout();\r
+\r
+ AlertAppender.prototype.append = function(loggingEvent) {\r
+ var formattedMessage = this.getLayout().format(loggingEvent);\r
+ if (this.getLayout().ignoresThrowable()) {\r
+ formattedMessage += loggingEvent.getThrowableStrRep();\r
+ }\r
+ alert(formattedMessage);\r
+ };\r
+\r
+ AlertAppender.prototype.toString = function() {\r
+ return "AlertAppender";\r
+ };\r
+\r
+ log4javascript.AlertAppender = AlertAppender;\r
+ /* ---------------------------------------------------------------------- */\r
+ // BrowserConsoleAppender (only works in Opera and Safari and Firefox with\r
+ // Firebug extension)\r
+\r
+ function BrowserConsoleAppender() {}\r
+\r
+ BrowserConsoleAppender.prototype = new log4javascript.Appender();\r
+ BrowserConsoleAppender.prototype.layout = new NullLayout();\r
+ BrowserConsoleAppender.prototype.threshold = Level.DEBUG;\r
+\r
+ BrowserConsoleAppender.prototype.append = function(loggingEvent) {\r
+ var appender = this;\r
+\r
+ var getFormattedMessage = function() {\r
+ var layout = appender.getLayout();\r
+ var formattedMessage = layout.format(loggingEvent);\r
+ if (layout.ignoresThrowable() && loggingEvent.exception) {\r
+ formattedMessage += loggingEvent.getThrowableStrRep();\r
+ }\r
+ return formattedMessage;\r
+ };\r
+\r
+ if ((typeof opera != "undefined") && opera.postError) { // Opera\r
+ opera.postError(getFormattedMessage());\r
+ } else if (window.console && window.console.log) { // Safari and Firebug\r
+ var formattedMesage = getFormattedMessage();\r
+ // Log to Firebug using its logging methods or revert to the console.log\r
+ // method in Safari\r
+ if (window.console.debug && Level.DEBUG.isGreaterOrEqual(loggingEvent.level)) {\r
+ window.console.debug(formattedMesage);\r
+ } else if (window.console.info && Level.INFO.equals(loggingEvent.level)) {\r
+ window.console.info(formattedMesage);\r
+ } else if (window.console.warn && Level.WARN.equals(loggingEvent.level)) {\r
+ window.console.warn(formattedMesage);\r
+ } else if (window.console.error && loggingEvent.level.isGreaterOrEqual(Level.ERROR)) {\r
+ window.console.error(formattedMesage);\r
+ } else {\r
+ window.console.log(formattedMesage);\r
+ }\r
+ }\r
+ };\r
+\r
+ BrowserConsoleAppender.prototype.group = function(name) {\r
+ if (window.console && window.console.group) {\r
+ window.console.group(name);\r
+ }\r
+ };\r
+\r
+ BrowserConsoleAppender.prototype.groupEnd = function() {\r
+ if (window.console && window.console.groupEnd) {\r
+ window.console.groupEnd();\r
+ }\r
+ };\r
+\r
+ BrowserConsoleAppender.prototype.toString = function() {\r
+ return "BrowserConsoleAppender";\r
+ };\r
+\r
+ log4javascript.BrowserConsoleAppender = BrowserConsoleAppender;\r
+ /* ---------------------------------------------------------------------- */\r
+ // AjaxAppender related\r
+\r
+ var xmlHttpFactories = [\r
+ function() { return new XMLHttpRequest(); },\r
+ function() { return new ActiveXObject("Msxml2.XMLHTTP"); },\r
+ function() { return new ActiveXObject("Microsoft.XMLHTTP"); }\r
+ ];\r
+\r
+ var getXmlHttp = function(errorHandler) {\r
+ // This is only run the first time; the value of getXmlHttp gets\r
+ // replaced with the factory that succeeds on the first run\r
+ var xmlHttp = null, factory;\r
+ for (var i = 0, len = xmlHttpFactories.length; i < len; i++) {\r
+ factory = xmlHttpFactories[i];\r
+ try {\r
+ xmlHttp = factory();\r
+ getXmlHttp = factory;\r
+ return xmlHttp;\r
+ } catch (e) {\r
+ }\r
+ }\r
+ // If we're here, all factories have failed, so throw an error\r
+ if (errorHandler) {\r
+ errorHandler();\r
+ } else {\r
+ handleError("getXmlHttp: unable to obtain XMLHttpRequest object");\r
+ }\r
+ };\r
+\r
+ function isHttpRequestSuccessful(xmlHttp) {\r
+ return isUndefined(xmlHttp.status) || xmlHttp.status === 0 ||\r
+ (xmlHttp.status >= 200 && xmlHttp.status < 300) ||\r
+ xmlHttp.status == 1223 /* Fix for IE */;\r
+ }\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // AjaxAppender\r
+\r
+ function AjaxAppender(url) {\r
+ var appender = this;\r
+ var isSupported = true;\r
+ if (!url) {\r
+ handleError("AjaxAppender: URL must be specified in constructor");\r
+ isSupported = false;\r
+ }\r
+\r
+ var timed = this.defaults.timed;\r
+ var waitForResponse = this.defaults.waitForResponse;\r
+ var batchSize = this.defaults.batchSize;\r
+ var timerInterval = this.defaults.timerInterval;\r
+ var requestSuccessCallback = this.defaults.requestSuccessCallback;\r
+ var failCallback = this.defaults.failCallback;\r
+ var postVarName = this.defaults.postVarName;\r
+ var sendAllOnUnload = this.defaults.sendAllOnUnload;\r
+ var contentType = this.defaults.contentType;\r
+ var sessionId = null;\r
+\r
+ var queuedLoggingEvents = [];\r
+ var queuedRequests = [];\r
+ var headers = [];\r
+ var sending = false;\r
+ var initialized = false;\r
+\r
+ // Configuration methods. The function scope is used to prevent\r
+ // direct alteration to the appender configuration properties.\r
+ function checkCanConfigure(configOptionName) {\r
+ if (initialized) {\r
+ handleError("AjaxAppender: configuration option '" +\r
+ configOptionName +\r
+ "' may not be set after the appender has been initialized");\r
+ return false;\r
+ }\r
+ return true;\r
+ }\r
+\r
+ this.getSessionId = function() { return sessionId; };\r
+ this.setSessionId = function(sessionIdParam) {\r
+ sessionId = extractStringFromParam(sessionIdParam, null);\r
+ this.layout.setCustomField("sessionid", sessionId);\r
+ };\r
+\r
+ this.setLayout = function(layoutParam) {\r
+ if (checkCanConfigure("layout")) {\r
+ this.layout = layoutParam;\r
+ // Set the session id as a custom field on the layout, if not already present\r
+ if (sessionId !== null) {\r
+ this.setSessionId(sessionId);\r
+ }\r
+ }\r
+ };\r
+\r
+ this.isTimed = function() { return timed; };\r
+ this.setTimed = function(timedParam) {\r
+ if (checkCanConfigure("timed")) {\r
+ timed = bool(timedParam);\r
+ }\r
+ };\r
+\r
+ this.getTimerInterval = function() { return timerInterval; };\r
+ this.setTimerInterval = function(timerIntervalParam) {\r
+ if (checkCanConfigure("timerInterval")) {\r
+ timerInterval = extractIntFromParam(timerIntervalParam, timerInterval);\r
+ }\r
+ };\r
+\r
+ this.isWaitForResponse = function() { return waitForResponse; };\r
+ this.setWaitForResponse = function(waitForResponseParam) {\r
+ if (checkCanConfigure("waitForResponse")) {\r
+ waitForResponse = bool(waitForResponseParam);\r
+ }\r
+ };\r
+\r
+ this.getBatchSize = function() { return batchSize; };\r
+ this.setBatchSize = function(batchSizeParam) {\r
+ if (checkCanConfigure("batchSize")) {\r
+ batchSize = extractIntFromParam(batchSizeParam, batchSize);\r
+ }\r
+ };\r
+\r
+ this.isSendAllOnUnload = function() { return sendAllOnUnload; };\r
+ this.setSendAllOnUnload = function(sendAllOnUnloadParam) {\r
+ if (checkCanConfigure("sendAllOnUnload")) {\r
+ sendAllOnUnload = extractBooleanFromParam(sendAllOnUnloadParam, sendAllOnUnload);\r
+ }\r
+ };\r
+\r
+ this.setRequestSuccessCallback = function(requestSuccessCallbackParam) {\r
+ requestSuccessCallback = extractFunctionFromParam(requestSuccessCallbackParam, requestSuccessCallback);\r
+ };\r
+\r
+ this.setFailCallback = function(failCallbackParam) {\r
+ failCallback = extractFunctionFromParam(failCallbackParam, failCallback);\r
+ };\r
+\r
+ this.getPostVarName = function() { return postVarName; };\r
+ this.setPostVarName = function(postVarNameParam) {\r
+ if (checkCanConfigure("postVarName")) {\r
+ postVarName = extractStringFromParam(postVarNameParam, postVarName);\r
+ }\r
+ };\r
+\r
+ this.getHeaders = function() { return headers; };\r
+ this.addHeader = function(name, value) {\r
+ if (name.toLowerCase() == "content-type") {\r
+ contentType = value;\r
+ } else {\r
+ headers.push( { name: name, value: value } );\r
+ }\r
+ };\r
+\r
+ // Internal functions\r
+ function sendAll() {\r
+ if (isSupported && enabled) {\r
+ sending = true;\r
+ var currentRequestBatch;\r
+ if (waitForResponse) {\r
+ // Send the first request then use this function as the callback once\r
+ // the response comes back\r
+ if (queuedRequests.length > 0) {\r
+ currentRequestBatch = queuedRequests.shift();\r
+ sendRequest(preparePostData(currentRequestBatch), sendAll);\r
+ } else {\r
+ sending = false;\r
+ if (timed) {\r
+ scheduleSending();\r
+ }\r
+ }\r
+ } else {\r
+ // Rattle off all the requests without waiting to see the response\r
+ while ((currentRequestBatch = queuedRequests.shift())) {\r
+ sendRequest(preparePostData(currentRequestBatch));\r
+ }\r
+ sending = false;\r
+ if (timed) {\r
+ scheduleSending();\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ this.sendAll = sendAll;\r
+\r
+ // Called when the window unloads. At this point we're past caring about\r
+ // waiting for responses or timers or incomplete batches - everything\r
+ // must go, now\r
+ function sendAllRemaining() {\r
+ var sendingAnything = false;\r
+ if (isSupported && enabled) {\r
+ // Create requests for everything left over, batched as normal\r
+ var actualBatchSize = appender.getLayout().allowBatching() ? batchSize : 1;\r
+ var currentLoggingEvent;\r
+ var batchedLoggingEvents = [];\r
+ while ((currentLoggingEvent = queuedLoggingEvents.shift())) {\r
+ batchedLoggingEvents.push(currentLoggingEvent);\r
+ if (queuedLoggingEvents.length >= actualBatchSize) {\r
+ // Queue this batch of log entries\r
+ queuedRequests.push(batchedLoggingEvents);\r
+ batchedLoggingEvents = [];\r
+ }\r
+ }\r
+ // If there's a partially completed batch, add it\r
+ if (batchedLoggingEvents.length > 0) {\r
+ queuedRequests.push(batchedLoggingEvents);\r
+ }\r
+ sendingAnything = (queuedRequests.length > 0);\r
+ waitForResponse = false;\r
+ timed = false;\r
+ sendAll();\r
+ }\r
+ return sendingAnything;\r
+ }\r
+\r
+ this.sendAllRemaining = sendAllRemaining;\r
+\r
+ function preparePostData(batchedLoggingEvents) {\r
+ // Format the logging events\r
+ var formattedMessages = [];\r
+ var currentLoggingEvent;\r
+ var postData = "";\r
+ while ((currentLoggingEvent = batchedLoggingEvents.shift())) {\r
+ var currentFormattedMessage = appender.getLayout().format(currentLoggingEvent);\r
+ if (appender.getLayout().ignoresThrowable()) {\r
+ currentFormattedMessage += currentLoggingEvent.getThrowableStrRep();\r
+ }\r
+ formattedMessages.push(currentFormattedMessage);\r
+ }\r
+ // Create the post data string\r
+ if (batchedLoggingEvents.length == 1) {\r
+ postData = formattedMessages.join("");\r
+ } else {\r
+ postData = appender.getLayout().batchHeader +\r
+ formattedMessages.join(appender.getLayout().batchSeparator) +\r
+ appender.getLayout().batchFooter;\r
+ }\r
+ if (contentType == appender.defaults.contentType) {\r
+ postData = appender.getLayout().returnsPostData ? postData :\r
+ urlEncode(postVarName) + "=" + urlEncode(postData);\r
+ // Add the layout name to the post data\r
+ if (postData.length > 0) {\r
+ postData += "&";\r
+ }\r
+ postData += "layout=" + urlEncode(appender.getLayout().toString());\r
+ }\r
+ return postData;\r
+ }\r
+\r
+ function scheduleSending() {\r
+ window.setTimeout(sendAll, timerInterval);\r
+ }\r
+\r
+ function xmlHttpErrorHandler() {\r
+ var msg = "AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";\r
+ handleError(msg);\r
+ isSupported = false;\r
+ if (failCallback) {\r
+ failCallback(msg);\r
+ }\r
+ }\r
+\r
+ function sendRequest(postData, successCallback) {\r
+ try {\r
+ var xmlHttp = getXmlHttp(xmlHttpErrorHandler);\r
+ if (isSupported) {\r
+ if (xmlHttp.overrideMimeType) {\r
+ xmlHttp.overrideMimeType(appender.getLayout().getContentType());\r
+ }\r
+ xmlHttp.onreadystatechange = function() {\r
+ if (xmlHttp.readyState == 4) {\r
+ if (isHttpRequestSuccessful(xmlHttp)) {\r
+ if (requestSuccessCallback) {\r
+ requestSuccessCallback(xmlHttp);\r
+ }\r
+ if (successCallback) {\r
+ successCallback(xmlHttp);\r
+ }\r
+ } else {\r
+ var msg = "AjaxAppender.append: XMLHttpRequest request to URL " +\r
+ url + " returned status code " + xmlHttp.status;\r
+ handleError(msg);\r
+ if (failCallback) {\r
+ failCallback(msg);\r
+ }\r
+ }\r
+ xmlHttp.onreadystatechange = emptyFunction;\r
+ xmlHttp = null;\r
+ }\r
+ };\r
+ xmlHttp.open("POST", url, true);\r
+ try {\r
+ for (var i = 0, header; header = headers[i++]; ) {\r
+ xmlHttp.setRequestHeader(header.name, header.value);\r
+ }\r
+ xmlHttp.setRequestHeader("Content-Type", contentType);\r
+ } catch (headerEx) {\r
+ var msg = "AjaxAppender.append: your browser's XMLHttpRequest implementation" +\r
+ " does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";\r
+ handleError(msg);\r
+ isSupported = false;\r
+ if (failCallback) {\r
+ failCallback(msg);\r
+ }\r
+ return;\r
+ }\r
+ xmlHttp.send(postData);\r
+ }\r
+ } catch (ex) {\r
+ var errMsg = "AjaxAppender.append: error sending log message to " + url;\r
+ handleError(errMsg, ex);\r
+ isSupported = false;\r
+ if (failCallback) {\r
+ failCallback(errMsg + ". Details: " + getExceptionStringRep(ex));\r
+ }\r
+ }\r
+ }\r
+\r
+ this.append = function(loggingEvent) {\r
+ if (isSupported) {\r
+ if (!initialized) {\r
+ init();\r
+ }\r
+ queuedLoggingEvents.push(loggingEvent);\r
+ var actualBatchSize = this.getLayout().allowBatching() ? batchSize : 1;\r
+\r
+ if (queuedLoggingEvents.length >= actualBatchSize) {\r
+ var currentLoggingEvent;\r
+ var batchedLoggingEvents = [];\r
+ while ((currentLoggingEvent = queuedLoggingEvents.shift())) {\r
+ batchedLoggingEvents.push(currentLoggingEvent);\r
+ }\r
+ // Queue this batch of log entries\r
+ queuedRequests.push(batchedLoggingEvents);\r
+\r
+ // If using a timer, the queue of requests will be processed by the\r
+ // timer function, so nothing needs to be done here.\r
+ if (!timed && (!waitForResponse || (waitForResponse && !sending))) {\r
+ sendAll();\r
+ }\r
+ }\r
+ }\r
+ };\r
+\r
+ function init() {\r
+ initialized = true;\r
+ // Add unload event to send outstanding messages\r
+ if (sendAllOnUnload) {\r
+ var oldBeforeUnload = window.onbeforeunload;\r
+ window.onbeforeunload = function() {\r
+ if (oldBeforeUnload) {\r
+ oldBeforeUnload();\r
+ }\r
+ if (sendAllRemaining()) {\r
+ return "Sending log messages";\r
+ }\r
+ };\r
+ }\r
+ // Start timer\r
+ if (timed) {\r
+ scheduleSending();\r
+ }\r
+ }\r
+ }\r
+\r
+ AjaxAppender.prototype = new Appender();\r
+\r
+ AjaxAppender.prototype.defaults = {\r
+ waitForResponse: false,\r
+ timed: false,\r
+ timerInterval: 1000,\r
+ batchSize: 1,\r
+ sendAllOnUnload: false,\r
+ requestSuccessCallback: null,\r
+ failCallback: null,\r
+ postVarName: "data",\r
+ contentType: "application/x-www-form-urlencoded"\r
+ };\r
+\r
+ AjaxAppender.prototype.layout = new HttpPostDataLayout();\r
+\r
+ AjaxAppender.prototype.toString = function() {\r
+ return "AjaxAppender";\r
+ };\r
+\r
+ log4javascript.AjaxAppender = AjaxAppender;\r
+ /* ---------------------------------------------------------------------- */\r
+ // PopUpAppender and InPageAppender related\r
+\r
+ function setCookie(name, value, days, path) {\r
+ var expires;\r
+ path = path ? "; path=" + path : "";\r
+ if (days) {\r
+ var date = new Date();\r
+ date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));\r
+ expires = "; expires=" + date.toGMTString();\r
+ } else {\r
+ expires = "";\r
+ }\r
+ document.cookie = escape(name) + "=" + escape(value) + expires + path;\r
+ }\r
+\r
+ function getCookie(name) {\r
+ var nameEquals = escape(name) + "=";\r
+ var ca = document.cookie.split(";");\r
+ for (var i = 0, len = ca.length; i < len; i++) {\r
+ var c = ca[i];\r
+ while (c.charAt(0) === " ") {\r
+ c = c.substring(1, c.length);\r
+ }\r
+ if (c.indexOf(nameEquals) === 0) {\r
+ return unescape(c.substring(nameEquals.length, c.length));\r
+ }\r
+ }\r
+ return null;\r
+ }\r
+\r
+ // Gets the base URL of the location of the log4javascript script.\r
+ // This is far from infallible.\r
+ function getBaseUrl() {\r
+ var scripts = document.getElementsByTagName("script");\r
+ for (var i = 0, len = scripts.length; i < len; ++i) {\r
+ if (scripts[i].src.indexOf("log4javascript") != -1) {\r
+ var lastSlash = scripts[i].src.lastIndexOf("/");\r
+ return (lastSlash == -1) ? "" : scripts[i].src.substr(0, lastSlash + 1);\r
+ }\r
+ }\r
+ return null;\r
+ }\r
+\r
+ function isLoaded(win) {\r
+ try {\r
+ return bool(win.loaded);\r
+ } catch (ex) {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // ConsoleAppender (prototype for PopUpAppender and InPageAppender)\r
+\r
+ var ConsoleAppender;\r
+\r
+ // Create an anonymous function to protect base console methods\r
+ (function() {\r
+ var getConsoleHtmlLines = function() {\r
+ return [\r
+'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',\r
+'<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">',\r
+' <head>',\r
+' <title>log4javascript</title>',\r
+' <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',\r
+' <!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->',\r
+' <meta http-equiv="X-UA-Compatible" content="IE=7" />',\r
+' <script type="text/javascript">var isIe = false, isIePre7 = false;</script>',\r
+' <!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->',\r
+' <!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->',\r
+' <script type="text/javascript">',\r
+' //<![CDATA[',\r
+' var loggingEnabled = true;',\r
+' var logQueuedEventsTimer = null;',\r
+' var logEntries = [];',\r
+' var logEntriesAndSeparators = [];',\r
+' var logItems = [];',\r
+' var renderDelay = 100;',\r
+' var unrenderedLogItemsExist = false;',\r
+' var rootGroup, currentGroup = null;',\r
+' var loaded = false;',\r
+' var currentLogItem = null;',\r
+' var logMainContainer;',\r
+'',\r
+' function copyProperties(obj, props) {',\r
+' for (var i in props) {',\r
+' obj[i] = props[i];',\r
+' }',\r
+' }',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function LogItem() {',\r
+' }',\r
+'',\r
+' LogItem.prototype = {',\r
+' mainContainer: null,',\r
+' wrappedContainer: null,',\r
+' unwrappedContainer: null,',\r
+' group: null,',\r
+'',\r
+' appendToLog: function() {',\r
+' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',\r
+' this.elementContainers[i].appendToLog();',\r
+' }',\r
+' this.group.update();',\r
+' },',\r
+'',\r
+' doRemove: function(doUpdate, removeFromGroup) {',\r
+' if (this.rendered) {',\r
+' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',\r
+' this.elementContainers[i].remove();',\r
+' }',\r
+' this.unwrappedElementContainer = null;',\r
+' this.wrappedElementContainer = null;',\r
+' this.mainElementContainer = null;',\r
+' }',\r
+' if (this.group && removeFromGroup) {',\r
+' this.group.removeChild(this, doUpdate);',\r
+' }',\r
+' if (this === currentLogItem) {',\r
+' currentLogItem = null;',\r
+' }',\r
+' },',\r
+'',\r
+' remove: function(doUpdate, removeFromGroup) {',\r
+' this.doRemove(doUpdate, removeFromGroup);',\r
+' },',\r
+'',\r
+' render: function() {},',\r
+'',\r
+' accept: function(visitor) {',\r
+' visitor.visit(this);',\r
+' },',\r
+'',\r
+' getUnwrappedDomContainer: function() {',\r
+' return this.group.unwrappedElementContainer.contentDiv;',\r
+' },',\r
+'',\r
+' getWrappedDomContainer: function() {',\r
+' return this.group.wrappedElementContainer.contentDiv;',\r
+' },',\r
+'',\r
+' getMainDomContainer: function() {',\r
+' return this.group.mainElementContainer.contentDiv;',\r
+' }',\r
+' };',\r
+'',\r
+' LogItem.serializedItemKeys = {LOG_ENTRY: 0, GROUP_START: 1, GROUP_END: 2};',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function LogItemContainerElement() {',\r
+' }',\r
+'',\r
+' LogItemContainerElement.prototype = {',\r
+' appendToLog: function() {',\r
+' var insertBeforeFirst = (newestAtTop && this.containerDomNode.hasChildNodes());',\r
+' if (insertBeforeFirst) {',\r
+' this.containerDomNode.insertBefore(this.mainDiv, this.containerDomNode.firstChild);',\r
+' } else {',\r
+' this.containerDomNode.appendChild(this.mainDiv);',\r
+' }',\r
+' }',\r
+' };',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function SeparatorElementContainer(containerDomNode) {',\r
+' this.containerDomNode = containerDomNode;',\r
+' this.mainDiv = document.createElement("div");',\r
+' this.mainDiv.className = "separator";',\r
+' this.mainDiv.innerHTML = " ";',\r
+' }',\r
+'',\r
+' SeparatorElementContainer.prototype = new LogItemContainerElement();',\r
+'',\r
+' SeparatorElementContainer.prototype.remove = function() {',\r
+' this.mainDiv.parentNode.removeChild(this.mainDiv);',\r
+' this.mainDiv = null;',\r
+' };',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function Separator() {',\r
+' this.rendered = false;',\r
+' }',\r
+'',\r
+' Separator.prototype = new LogItem();',\r
+'',\r
+' copyProperties(Separator.prototype, {',\r
+' render: function() {',\r
+' var containerDomNode = this.group.contentDiv;',\r
+' if (isIe) {',\r
+' this.unwrappedElementContainer = new SeparatorElementContainer(this.getUnwrappedDomContainer());',\r
+' this.wrappedElementContainer = new SeparatorElementContainer(this.getWrappedDomContainer());',\r
+' this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',\r
+' } else {',\r
+' this.mainElementContainer = new SeparatorElementContainer(this.getMainDomContainer());',\r
+' this.elementContainers = [this.mainElementContainer];',\r
+' }',\r
+' this.content = this.formattedMessage;',\r
+' this.rendered = true;',\r
+' }',\r
+' });',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function GroupElementContainer(group, containerDomNode, isRoot, isWrapped) {',\r
+' this.group = group;',\r
+' this.containerDomNode = containerDomNode;',\r
+' this.isRoot = isRoot;',\r
+' this.isWrapped = isWrapped;',\r
+' this.expandable = false;',\r
+'',\r
+' if (this.isRoot) {',\r
+' if (isIe) {',\r
+' this.contentDiv = logMainContainer.appendChild(document.createElement("div"));',\r
+' this.contentDiv.id = this.isWrapped ? "log_wrapped" : "log_unwrapped";',\r
+' } else {',\r
+' this.contentDiv = logMainContainer;',\r
+' }',\r
+' } else {',\r
+' var groupElementContainer = this;',\r
+' ',\r
+' this.mainDiv = document.createElement("div");',\r
+' this.mainDiv.className = "group";',\r
+'',\r
+' this.headingDiv = this.mainDiv.appendChild(document.createElement("div"));',\r
+' this.headingDiv.className = "groupheading";',\r
+'',\r
+' this.expander = this.headingDiv.appendChild(document.createElement("span"));',\r
+' this.expander.className = "expander unselectable greyedout";',\r
+' this.expander.unselectable = true;',\r
+' var expanderText = this.group.expanded ? "-" : "+";',\r
+' this.expanderTextNode = this.expander.appendChild(document.createTextNode(expanderText));',\r
+' ',\r
+' this.headingDiv.appendChild(document.createTextNode(" " + this.group.name));',\r
+'',\r
+' this.contentDiv = this.mainDiv.appendChild(document.createElement("div"));',\r
+' var contentCssClass = this.group.expanded ? "expanded" : "collapsed";',\r
+' this.contentDiv.className = "groupcontent " + contentCssClass;',\r
+'',\r
+' this.expander.onclick = function() {',\r
+' if (groupElementContainer.group.expandable) {',\r
+' groupElementContainer.group.toggleExpanded();',\r
+' }',\r
+' };',\r
+' }',\r
+' }',\r
+'',\r
+' GroupElementContainer.prototype = new LogItemContainerElement();',\r
+'',\r
+' copyProperties(GroupElementContainer.prototype, {',\r
+' toggleExpanded: function() {',\r
+' if (!this.isRoot) {',\r
+' var oldCssClass, newCssClass, expanderText;',\r
+' if (this.group.expanded) {',\r
+' newCssClass = "expanded";',\r
+' oldCssClass = "collapsed";',\r
+' expanderText = "-";',\r
+' } else {',\r
+' newCssClass = "collapsed";',\r
+' oldCssClass = "expanded";',\r
+' expanderText = "+";',\r
+' }',\r
+' replaceClass(this.contentDiv, newCssClass, oldCssClass);',\r
+' this.expanderTextNode.nodeValue = expanderText;',\r
+' }',\r
+' },',\r
+'',\r
+' remove: function() {',\r
+' if (!this.isRoot) {',\r
+' this.headingDiv = null;',\r
+' this.expander.onclick = null;',\r
+' this.expander = null;',\r
+' this.expanderTextNode = null;',\r
+' this.contentDiv = null;',\r
+' this.containerDomNode = null;',\r
+' this.mainDiv.parentNode.removeChild(this.mainDiv);',\r
+' this.mainDiv = null;',\r
+' }',\r
+' },',\r
+'',\r
+' reverseChildren: function() {',\r
+' // Invert the order of the log entries',\r
+' var node = null;',\r
+'',\r
+' // Remove all the log container nodes',\r
+' var childDomNodes = [];',\r
+' while ((node = this.contentDiv.firstChild)) {',\r
+' this.contentDiv.removeChild(node);',\r
+' childDomNodes.push(node);',\r
+' }',\r
+'',\r
+' // Put them all back in reverse order',\r
+' while ((node = childDomNodes.pop())) {',\r
+' this.contentDiv.appendChild(node);',\r
+' }',\r
+' },',\r
+'',\r
+' update: function() {',\r
+' if (!this.isRoot) {',\r
+' if (this.group.expandable) {',\r
+' removeClass(this.expander, "greyedout");',\r
+' } else {',\r
+' addClass(this.expander, "greyedout");',\r
+' }',\r
+' }',\r
+' },',\r
+'',\r
+' clear: function() {',\r
+' if (this.isRoot) {',\r
+' this.contentDiv.innerHTML = "";',\r
+' }',\r
+' }',\r
+' });',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function Group(name, isRoot, initiallyExpanded) {',\r
+' this.name = name;',\r
+' this.group = null;',\r
+' this.isRoot = isRoot;',\r
+' this.initiallyExpanded = initiallyExpanded;',\r
+' this.elementContainers = [];',\r
+' this.children = [];',\r
+' this.expanded = initiallyExpanded;',\r
+' this.rendered = false;',\r
+' this.expandable = false;',\r
+' }',\r
+'',\r
+' Group.prototype = new LogItem();',\r
+'',\r
+' copyProperties(Group.prototype, {',\r
+' addChild: function(logItem) {',\r
+' this.children.push(logItem);',\r
+' logItem.group = this;',\r
+' },',\r
+'',\r
+' render: function() {',\r
+' if (isIe) {',\r
+' var unwrappedDomContainer, wrappedDomContainer;',\r
+' if (this.isRoot) {',\r
+' unwrappedDomContainer = logMainContainer;',\r
+' wrappedDomContainer = logMainContainer;',\r
+' } else {',\r
+' unwrappedDomContainer = this.getUnwrappedDomContainer();',\r
+' wrappedDomContainer = this.getWrappedDomContainer();',\r
+' }',\r
+' this.unwrappedElementContainer = new GroupElementContainer(this, unwrappedDomContainer, this.isRoot, false);',\r
+' this.wrappedElementContainer = new GroupElementContainer(this, wrappedDomContainer, this.isRoot, true);',\r
+' this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',\r
+' } else {',\r
+' var mainDomContainer = this.isRoot ? logMainContainer : this.getMainDomContainer();',\r
+' this.mainElementContainer = new GroupElementContainer(this, mainDomContainer, this.isRoot, false);',\r
+' this.elementContainers = [this.mainElementContainer];',\r
+' }',\r
+' this.rendered = true;',\r
+' },',\r
+'',\r
+' toggleExpanded: function() {',\r
+' this.expanded = !this.expanded;',\r
+' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',\r
+' this.elementContainers[i].toggleExpanded();',\r
+' }',\r
+' },',\r
+'',\r
+' expand: function() {',\r
+' if (!this.expanded) {',\r
+' this.toggleExpanded();',\r
+' }',\r
+' },',\r
+'',\r
+' accept: function(visitor) {',\r
+' visitor.visitGroup(this);',\r
+' },',\r
+'',\r
+' reverseChildren: function() {',\r
+' if (this.rendered) {',\r
+' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',\r
+' this.elementContainers[i].reverseChildren();',\r
+' }',\r
+' }',\r
+' },',\r
+'',\r
+' update: function() {',\r
+' var previouslyExpandable = this.expandable;',\r
+' this.expandable = (this.children.length !== 0);',\r
+' if (this.expandable !== previouslyExpandable) {',\r
+' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',\r
+' this.elementContainers[i].update();',\r
+' }',\r
+' }',\r
+' },',\r
+'',\r
+' flatten: function() {',\r
+' var visitor = new GroupFlattener();',\r
+' this.accept(visitor);',\r
+' return visitor.logEntriesAndSeparators;',\r
+' },',\r
+'',\r
+' removeChild: function(child, doUpdate) {',\r
+' array_remove(this.children, child);',\r
+' child.group = null;',\r
+' if (doUpdate) {',\r
+' this.update();',\r
+' }',\r
+' },',\r
+'',\r
+' remove: function(doUpdate, removeFromGroup) {',\r
+' for (var i = 0, len = this.children.length; i < len; i++) {',\r
+' this.children[i].remove(false, false);',\r
+' }',\r
+' this.children = [];',\r
+' this.update();',\r
+' if (this === currentGroup) {',\r
+' currentGroup = this.group;',\r
+' }',\r
+' this.doRemove(doUpdate, removeFromGroup);',\r
+' },',\r
+'',\r
+' serialize: function(items) {',\r
+' items.push([LogItem.serializedItemKeys.GROUP_START, this.name]);',\r
+' for (var i = 0, len = this.children.length; i < len; i++) {',\r
+' this.children[i].serialize(items);',\r
+' }',\r
+' if (this !== currentGroup) {',\r
+' items.push([LogItem.serializedItemKeys.GROUP_END]);',\r
+' }',\r
+' },',\r
+'',\r
+' clear: function() {',\r
+' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',\r
+' this.elementContainers[i].clear();',\r
+' }',\r
+' }',\r
+' });',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function LogEntryElementContainer() {',\r
+' }',\r
+'',\r
+' LogEntryElementContainer.prototype = new LogItemContainerElement();',\r
+'',\r
+' copyProperties(LogEntryElementContainer.prototype, {',\r
+' remove: function() {',\r
+' this.doRemove();',\r
+' },',\r
+'',\r
+' doRemove: function() {',\r
+' this.mainDiv.parentNode.removeChild(this.mainDiv);',\r
+' this.mainDiv = null;',\r
+' this.contentElement = null;',\r
+' this.containerDomNode = null;',\r
+' },',\r
+'',\r
+' setContent: function(content, wrappedContent) {',\r
+' if (content === this.formattedMessage) {',\r
+' this.contentElement.innerHTML = "";',\r
+' this.contentElement.appendChild(document.createTextNode(this.formattedMessage));',\r
+' } else {',\r
+' this.contentElement.innerHTML = content;',\r
+' }',\r
+' },',\r
+'',\r
+' setSearchMatch: function(isMatch) {',\r
+' var oldCssClass = isMatch ? "searchnonmatch" : "searchmatch";',\r
+' var newCssClass = isMatch ? "searchmatch" : "searchnonmatch";',\r
+' replaceClass(this.mainDiv, newCssClass, oldCssClass);',\r
+' },',\r
+'',\r
+' clearSearch: function() {',\r
+' removeClass(this.mainDiv, "searchmatch");',\r
+' removeClass(this.mainDiv, "searchnonmatch");',\r
+' }',\r
+' });',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function LogEntryWrappedElementContainer(logEntry, containerDomNode) {',\r
+' this.logEntry = logEntry;',\r
+' this.containerDomNode = containerDomNode;',\r
+' this.mainDiv = document.createElement("div");',\r
+' this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));',\r
+' this.mainDiv.className = "logentry wrapped " + this.logEntry.level;',\r
+' this.contentElement = this.mainDiv;',\r
+' }',\r
+'',\r
+' LogEntryWrappedElementContainer.prototype = new LogEntryElementContainer();',\r
+'',\r
+' LogEntryWrappedElementContainer.prototype.setContent = function(content, wrappedContent) {',\r
+' if (content === this.formattedMessage) {',\r
+' this.contentElement.innerHTML = "";',\r
+' this.contentElement.appendChild(document.createTextNode(this.formattedMessage));',\r
+' } else {',\r
+' this.contentElement.innerHTML = wrappedContent;',\r
+' }',\r
+' };',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function LogEntryUnwrappedElementContainer(logEntry, containerDomNode) {',\r
+' this.logEntry = logEntry;',\r
+' this.containerDomNode = containerDomNode;',\r
+' this.mainDiv = document.createElement("div");',\r
+' this.mainDiv.className = "logentry unwrapped " + this.logEntry.level;',\r
+' this.pre = this.mainDiv.appendChild(document.createElement("pre"));',\r
+' this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));',\r
+' this.pre.className = "unwrapped";',\r
+' this.contentElement = this.pre;',\r
+' }',\r
+'',\r
+' LogEntryUnwrappedElementContainer.prototype = new LogEntryElementContainer();',\r
+'',\r
+' LogEntryUnwrappedElementContainer.prototype.remove = function() {',\r
+' this.doRemove();',\r
+' this.pre = null;',\r
+' };',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function LogEntryMainElementContainer(logEntry, containerDomNode) {',\r
+' this.logEntry = logEntry;',\r
+' this.containerDomNode = containerDomNode;',\r
+' this.mainDiv = document.createElement("div");',\r
+' this.mainDiv.className = "logentry nonielogentry " + this.logEntry.level;',\r
+' this.contentElement = this.mainDiv.appendChild(document.createElement("span"));',\r
+' this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));',\r
+' }',\r
+'',\r
+' LogEntryMainElementContainer.prototype = new LogEntryElementContainer();',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function LogEntry(level, formattedMessage) {',\r
+' this.level = level;',\r
+' this.formattedMessage = formattedMessage;',\r
+' this.rendered = false;',\r
+' }',\r
+'',\r
+' LogEntry.prototype = new LogItem();',\r
+'',\r
+' copyProperties(LogEntry.prototype, {',\r
+' render: function() {',\r
+' var logEntry = this;',\r
+' var containerDomNode = this.group.contentDiv;',\r
+'',\r
+' // Support for the CSS attribute white-space in IE for Windows is',\r
+' // non-existent pre version 6 and slightly odd in 6, so instead',\r
+' // use two different HTML elements',\r
+' if (isIe) {',\r
+' this.formattedMessage = this.formattedMessage.replace(/\\r\\n/g, "\\r"); // Workaround for IE\'s treatment of white space',\r
+' this.unwrappedElementContainer = new LogEntryUnwrappedElementContainer(this, this.getUnwrappedDomContainer());',\r
+' this.wrappedElementContainer = new LogEntryWrappedElementContainer(this, this.getWrappedDomContainer());',\r
+' this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',\r
+' } else {',\r
+' this.mainElementContainer = new LogEntryMainElementContainer(this, this.getMainDomContainer());',\r
+' this.elementContainers = [this.mainElementContainer];',\r
+' }',\r
+' this.content = this.formattedMessage;',\r
+' this.rendered = true;',\r
+' },',\r
+'',\r
+' setContent: function(content, wrappedContent) {',\r
+' if (content != this.content) {',\r
+' if (isIe && (content !== this.formattedMessage)) {',\r
+' content = content.replace(/\\r\\n/g, "\\r"); // Workaround for IE\'s treatment of white space',\r
+' }',\r
+' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',\r
+' this.elementContainers[i].setContent(content, wrappedContent);',\r
+' }',\r
+' this.content = content;',\r
+' }',\r
+' },',\r
+'',\r
+' getSearchMatches: function() {',\r
+' var matches = [];',\r
+' var i, len;',\r
+' if (isIe) {',\r
+' var unwrappedEls = getElementsByClass(this.unwrappedElementContainer.mainDiv, "searchterm", "span");',\r
+' var wrappedEls = getElementsByClass(this.wrappedElementContainer.mainDiv, "searchterm", "span");',\r
+' for (i = 0, len = unwrappedEls.length; i < len; i++) {',\r
+' matches[i] = new Match(this.level, null, unwrappedEls[i], wrappedEls[i]);',\r
+' }',\r
+' } else {',\r
+' var els = getElementsByClass(this.mainElementContainer.mainDiv, "searchterm", "span");',\r
+' for (i = 0, len = els.length; i < len; i++) {',\r
+' matches[i] = new Match(this.level, els[i]);',\r
+' }',\r
+' }',\r
+' return matches;',\r
+' },',\r
+'',\r
+' setSearchMatch: function(isMatch) {',\r
+' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',\r
+' this.elementContainers[i].setSearchMatch(isMatch);',\r
+' }',\r
+' },',\r
+'',\r
+' clearSearch: function() {',\r
+' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',\r
+' this.elementContainers[i].clearSearch();',\r
+' }',\r
+' },',\r
+'',\r
+' accept: function(visitor) {',\r
+' visitor.visitLogEntry(this);',\r
+' },',\r
+'',\r
+' serialize: function(items) {',\r
+' items.push([LogItem.serializedItemKeys.LOG_ENTRY, this.level, this.formattedMessage]);',\r
+' }',\r
+' });',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function LogItemVisitor() {',\r
+' }',\r
+'',\r
+' LogItemVisitor.prototype = {',\r
+' visit: function(logItem) {',\r
+' },',\r
+'',\r
+' visitParent: function(logItem) {',\r
+' if (logItem.group) {',\r
+' logItem.group.accept(this);',\r
+' }',\r
+' },',\r
+'',\r
+' visitChildren: function(logItem) {',\r
+' for (var i = 0, len = logItem.children.length; i < len; i++) {',\r
+' logItem.children[i].accept(this);',\r
+' }',\r
+' },',\r
+'',\r
+' visitLogEntry: function(logEntry) {',\r
+' this.visit(logEntry);',\r
+' },',\r
+'',\r
+' visitSeparator: function(separator) {',\r
+' this.visit(separator);',\r
+' },',\r
+'',\r
+' visitGroup: function(group) {',\r
+' this.visit(group);',\r
+' }',\r
+' };',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function GroupFlattener() {',\r
+' this.logEntriesAndSeparators = [];',\r
+' }',\r
+'',\r
+' GroupFlattener.prototype = new LogItemVisitor();',\r
+'',\r
+' GroupFlattener.prototype.visitGroup = function(group) {',\r
+' this.visitChildren(group);',\r
+' };',\r
+'',\r
+' GroupFlattener.prototype.visitLogEntry = function(logEntry) {',\r
+' this.logEntriesAndSeparators.push(logEntry);',\r
+' };',\r
+'',\r
+' GroupFlattener.prototype.visitSeparator = function(separator) {',\r
+' this.logEntriesAndSeparators.push(separator);',\r
+' };',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' window.onload = function() {',\r
+' // Sort out document.domain',\r
+' if (location.search) {',\r
+' var queryBits = unescape(location.search).substr(1).split("&"), nameValueBits;',\r
+' for (var i = 0, len = queryBits.length; i < len; i++) {',\r
+' nameValueBits = queryBits[i].split("=");',\r
+' if (nameValueBits[0] == "log4javascript_domain") {',\r
+' document.domain = nameValueBits[1];',\r
+' break;',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' // Create DOM objects',\r
+' logMainContainer = $("log");',\r
+' if (isIePre7) {',\r
+' addClass(logMainContainer, "oldIe");',\r
+' }',\r
+'',\r
+' rootGroup = new Group("root", true);',\r
+' rootGroup.render();',\r
+' currentGroup = rootGroup;',\r
+' ',\r
+' setCommandInputWidth();',\r
+' setLogContainerHeight();',\r
+' toggleLoggingEnabled();',\r
+' toggleSearchEnabled();',\r
+' toggleSearchFilter();',\r
+' toggleSearchHighlight();',\r
+' applyFilters();',\r
+' checkAllLevels();',\r
+' toggleWrap();',\r
+' toggleNewestAtTop();',\r
+' toggleScrollToLatest();',\r
+' renderQueuedLogItems();',\r
+' loaded = true;',\r
+' $("command").value = "";',\r
+' $("command").autocomplete = "off";',\r
+' $("command").onkeydown = function(evt) {',\r
+' evt = getEvent(evt);',\r
+' if (evt.keyCode == 10 || evt.keyCode == 13) { // Return/Enter',\r
+' evalCommandLine();',\r
+' stopPropagation(evt);',\r
+' } else if (evt.keyCode == 27) { // Escape',\r
+' this.value = "";',\r
+' this.focus();',\r
+' } else if (evt.keyCode == 38 && commandHistory.length > 0) { // Up',\r
+' currentCommandIndex = Math.max(0, currentCommandIndex - 1);',\r
+' this.value = commandHistory[currentCommandIndex];',\r
+' moveCaretToEnd(this);',\r
+' } else if (evt.keyCode == 40 && commandHistory.length > 0) { // Down',\r
+' currentCommandIndex = Math.min(commandHistory.length - 1, currentCommandIndex + 1);',\r
+' this.value = commandHistory[currentCommandIndex];',\r
+' moveCaretToEnd(this);',\r
+' }',\r
+' };',\r
+'',\r
+' // Prevent the keypress moving the caret in Firefox',\r
+' $("command").onkeypress = function(evt) {',\r
+' evt = getEvent(evt);',\r
+' if (evt.keyCode == 38 && commandHistory.length > 0 && evt.preventDefault) { // Up',\r
+' evt.preventDefault();',\r
+' }',\r
+' };',\r
+'',\r
+' // Prevent the keyup event blurring the input in Opera',\r
+' $("command").onkeyup = function(evt) {',\r
+' evt = getEvent(evt);',\r
+' if (evt.keyCode == 27 && evt.preventDefault) { // Up',\r
+' evt.preventDefault();',\r
+' this.focus();',\r
+' }',\r
+' };',\r
+'',\r
+' // Add document keyboard shortcuts',\r
+' document.onkeydown = function keyEventHandler(evt) {',\r
+' evt = getEvent(evt);',\r
+' switch (evt.keyCode) {',\r
+' case 69: // Ctrl + shift + E: re-execute last command',\r
+' if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',\r
+' evalLastCommand();',\r
+' cancelKeyEvent(evt);',\r
+' return false;',\r
+' }',\r
+' break;',\r
+' case 75: // Ctrl + shift + K: focus search',\r
+' if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',\r
+' focusSearch();',\r
+' cancelKeyEvent(evt);',\r
+' return false;',\r
+' }',\r
+' break;',\r
+' case 40: // Ctrl + shift + down arrow: focus command line',\r
+' case 76: // Ctrl + shift + L: focus command line',\r
+' if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',\r
+' focusCommandLine();',\r
+' cancelKeyEvent(evt);',\r
+' return false;',\r
+' }',\r
+' break;',\r
+' }',\r
+' };',\r
+'',\r
+' // Workaround to make sure log div starts at the correct size',\r
+' setTimeout(setLogContainerHeight, 20);',\r
+'',\r
+' setShowCommandLine(showCommandLine);',\r
+' doSearch();',\r
+' };',\r
+'',\r
+' window.onunload = function() {',\r
+' if (mainWindowExists()) {',\r
+' appender.unload();',\r
+' }',\r
+' appender = null;',\r
+' };',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function toggleLoggingEnabled() {',\r
+' setLoggingEnabled($("enableLogging").checked);',\r
+' }',\r
+'',\r
+' function setLoggingEnabled(enable) {',\r
+' loggingEnabled = enable;',\r
+' }',\r
+'',\r
+' var appender = null;',\r
+'',\r
+' function setAppender(appenderParam) {',\r
+' appender = appenderParam;',\r
+' }',\r
+'',\r
+' function setShowCloseButton(showCloseButton) {',\r
+' $("closeButton").style.display = showCloseButton ? "inline" : "none";',\r
+' }',\r
+'',\r
+' function setShowHideButton(showHideButton) {',\r
+' $("hideButton").style.display = showHideButton ? "inline" : "none";',\r
+' }',\r
+'',\r
+' var newestAtTop = false;',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function LogItemContentReverser() {',\r
+' }',\r
+' ',\r
+' LogItemContentReverser.prototype = new LogItemVisitor();',\r
+' ',\r
+' LogItemContentReverser.prototype.visitGroup = function(group) {',\r
+' group.reverseChildren();',\r
+' this.visitChildren(group);',\r
+' };',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function setNewestAtTop(isNewestAtTop) {',\r
+' var oldNewestAtTop = newestAtTop;',\r
+' var i, iLen, j, jLen;',\r
+' newestAtTop = Boolean(isNewestAtTop);',\r
+' if (oldNewestAtTop != newestAtTop) {',\r
+' var visitor = new LogItemContentReverser();',\r
+' rootGroup.accept(visitor);',\r
+'',\r
+' // Reassemble the matches array',\r
+' if (currentSearch) {',\r
+' var currentMatch = currentSearch.matches[currentMatchIndex];',\r
+' var matchIndex = 0;',\r
+' var matches = [];',\r
+' var actOnLogEntry = function(logEntry) {',\r
+' var logEntryMatches = logEntry.getSearchMatches();',\r
+' for (j = 0, jLen = logEntryMatches.length; j < jLen; j++) {',\r
+' matches[matchIndex] = logEntryMatches[j];',\r
+' if (currentMatch && logEntryMatches[j].equals(currentMatch)) {',\r
+' currentMatchIndex = matchIndex;',\r
+' }',\r
+' matchIndex++;',\r
+' }',\r
+' };',\r
+' if (newestAtTop) {',\r
+' for (i = logEntries.length - 1; i >= 0; i--) {',\r
+' actOnLogEntry(logEntries[i]);',\r
+' }',\r
+' } else {',\r
+' for (i = 0, iLen = logEntries.length; i < iLen; i++) {',\r
+' actOnLogEntry(logEntries[i]);',\r
+' }',\r
+' }',\r
+' currentSearch.matches = matches;',\r
+' if (currentMatch) {',\r
+' currentMatch.setCurrent();',\r
+' }',\r
+' } else if (scrollToLatest) {',\r
+' doScrollToLatest();',\r
+' }',\r
+' }',\r
+' $("newestAtTop").checked = isNewestAtTop;',\r
+' }',\r
+'',\r
+' function toggleNewestAtTop() {',\r
+' var isNewestAtTop = $("newestAtTop").checked;',\r
+' setNewestAtTop(isNewestAtTop);',\r
+' }',\r
+'',\r
+' var scrollToLatest = true;',\r
+'',\r
+' function setScrollToLatest(isScrollToLatest) {',\r
+' scrollToLatest = isScrollToLatest;',\r
+' if (scrollToLatest) {',\r
+' doScrollToLatest();',\r
+' }',\r
+' $("scrollToLatest").checked = isScrollToLatest;',\r
+' }',\r
+'',\r
+' function toggleScrollToLatest() {',\r
+' var isScrollToLatest = $("scrollToLatest").checked;',\r
+' setScrollToLatest(isScrollToLatest);',\r
+' }',\r
+'',\r
+' function doScrollToLatest() {',\r
+' var l = logMainContainer;',\r
+' if (typeof l.scrollTop != "undefined") {',\r
+' if (newestAtTop) {',\r
+' l.scrollTop = 0;',\r
+' } else {',\r
+' var latestLogEntry = l.lastChild;',\r
+' if (latestLogEntry) {',\r
+' l.scrollTop = l.scrollHeight;',\r
+' }',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' var closeIfOpenerCloses = true;',\r
+'',\r
+' function setCloseIfOpenerCloses(isCloseIfOpenerCloses) {',\r
+' closeIfOpenerCloses = isCloseIfOpenerCloses;',\r
+' }',\r
+'',\r
+' var maxMessages = null;',\r
+'',\r
+' function setMaxMessages(max) {',\r
+' maxMessages = max;',\r
+' pruneLogEntries();',\r
+' }',\r
+'',\r
+' var showCommandLine = false;',\r
+'',\r
+' function setShowCommandLine(isShowCommandLine) {',\r
+' showCommandLine = isShowCommandLine;',\r
+' if (loaded) {',\r
+' $("commandLine").style.display = showCommandLine ? "block" : "none";',\r
+' setCommandInputWidth();',\r
+' setLogContainerHeight();',\r
+' }',\r
+' }',\r
+'',\r
+' function focusCommandLine() {',\r
+' if (loaded) {',\r
+' $("command").focus();',\r
+' }',\r
+' }',\r
+'',\r
+' function focusSearch() {',\r
+' if (loaded) {',\r
+' $("searchBox").focus();',\r
+' }',\r
+' }',\r
+'',\r
+' function getLogItems() {',\r
+' var items = [];',\r
+' for (var i = 0, len = logItems.length; i < len; i++) {',\r
+' logItems[i].serialize(items);',\r
+' }',\r
+' return items;',\r
+' }',\r
+'',\r
+' function setLogItems(items) {',\r
+' var loggingReallyEnabled = loggingEnabled;',\r
+' // Temporarily turn logging on',\r
+' loggingEnabled = true;',\r
+' for (var i = 0, len = items.length; i < len; i++) {',\r
+' switch (items[i][0]) {',\r
+' case LogItem.serializedItemKeys.LOG_ENTRY:',\r
+' log(items[i][1], items[i][2]);',\r
+' break;',\r
+' case LogItem.serializedItemKeys.GROUP_START:',\r
+' group(items[i][1]);',\r
+' break;',\r
+' case LogItem.serializedItemKeys.GROUP_END:',\r
+' groupEnd();',\r
+' break;',\r
+' }',\r
+' }',\r
+' loggingEnabled = loggingReallyEnabled;',\r
+' }',\r
+'',\r
+' function log(logLevel, formattedMessage) {',\r
+' if (loggingEnabled) {',\r
+' var logEntry = new LogEntry(logLevel, formattedMessage);',\r
+' logEntries.push(logEntry);',\r
+' logEntriesAndSeparators.push(logEntry);',\r
+' logItems.push(logEntry);',\r
+' currentGroup.addChild(logEntry);',\r
+' if (loaded) {',\r
+' if (logQueuedEventsTimer !== null) {',\r
+' clearTimeout(logQueuedEventsTimer);',\r
+' }',\r
+' logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);',\r
+' unrenderedLogItemsExist = true;',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function renderQueuedLogItems() {',\r
+' logQueuedEventsTimer = null;',\r
+' var pruned = pruneLogEntries();',\r
+'',\r
+' // Render any unrendered log entries and apply the current search to them',\r
+' var initiallyHasMatches = currentSearch ? currentSearch.hasMatches() : false;',\r
+' for (var i = 0, len = logItems.length; i < len; i++) {',\r
+' if (!logItems[i].rendered) {',\r
+' logItems[i].render();',\r
+' logItems[i].appendToLog();',\r
+' if (currentSearch && (logItems[i] instanceof LogEntry)) {',\r
+' currentSearch.applyTo(logItems[i]);',\r
+' }',\r
+' }',\r
+' }',\r
+' if (currentSearch) {',\r
+' if (pruned) {',\r
+' if (currentSearch.hasVisibleMatches()) {',\r
+' if (currentMatchIndex === null) {',\r
+' setCurrentMatchIndex(0);',\r
+' }',\r
+' displayMatches();',\r
+' } else {',\r
+' displayNoMatches();',\r
+' }',\r
+' } else if (!initiallyHasMatches && currentSearch.hasVisibleMatches()) {',\r
+' setCurrentMatchIndex(0);',\r
+' displayMatches();',\r
+' }',\r
+' }',\r
+' if (scrollToLatest) {',\r
+' doScrollToLatest();',\r
+' }',\r
+' unrenderedLogItemsExist = false;',\r
+' }',\r
+'',\r
+' function pruneLogEntries() {',\r
+' if ((maxMessages !== null) && (logEntriesAndSeparators.length > maxMessages)) {',\r
+' var numberToDelete = logEntriesAndSeparators.length - maxMessages;',\r
+' var prunedLogEntries = logEntriesAndSeparators.slice(0, numberToDelete);',\r
+' if (currentSearch) {',\r
+' currentSearch.removeMatches(prunedLogEntries);',\r
+' }',\r
+' var group;',\r
+' for (var i = 0; i < numberToDelete; i++) {',\r
+' group = logEntriesAndSeparators[i].group;',\r
+' array_remove(logItems, logEntriesAndSeparators[i]);',\r
+' array_remove(logEntries, logEntriesAndSeparators[i]);',\r
+' logEntriesAndSeparators[i].remove(true, true);',\r
+' if (group.children.length === 0 && group !== currentGroup && group !== rootGroup) {',\r
+' array_remove(logItems, group);',\r
+' group.remove(true, true);',\r
+' }',\r
+' }',\r
+' logEntriesAndSeparators = array_removeFromStart(logEntriesAndSeparators, numberToDelete);',\r
+' return true;',\r
+' }',\r
+' return false;',\r
+' }',\r
+'',\r
+' function group(name, startExpanded) {',\r
+' if (loggingEnabled) {',\r
+' initiallyExpanded = (typeof startExpanded === "undefined") ? true : Boolean(startExpanded);',\r
+' var newGroup = new Group(name, false, initiallyExpanded);',\r
+' currentGroup.addChild(newGroup);',\r
+' currentGroup = newGroup;',\r
+' logItems.push(newGroup);',\r
+' if (loaded) {',\r
+' if (logQueuedEventsTimer !== null) {',\r
+' clearTimeout(logQueuedEventsTimer);',\r
+' }',\r
+' logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);',\r
+' unrenderedLogItemsExist = true;',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function groupEnd() {',\r
+' currentGroup = (currentGroup === rootGroup) ? rootGroup : currentGroup.group;',\r
+' }',\r
+'',\r
+' function mainPageReloaded() {',\r
+' currentGroup = rootGroup;',\r
+' var separator = new Separator();',\r
+' logEntriesAndSeparators.push(separator);',\r
+' logItems.push(separator);',\r
+' currentGroup.addChild(separator);',\r
+' }',\r
+'',\r
+' function closeWindow() {',\r
+' if (appender && mainWindowExists()) {',\r
+' appender.close(true);',\r
+' } else {',\r
+' window.close();',\r
+' }',\r
+' }',\r
+'',\r
+' function hide() {',\r
+' if (appender && mainWindowExists()) {',\r
+' appender.hide();',\r
+' }',\r
+' }',\r
+'',\r
+' var mainWindow = window;',\r
+' var windowId = "log4javascriptConsoleWindow_" + new Date().getTime() + "_" + ("" + Math.random()).substr(2);',\r
+'',\r
+' function setMainWindow(win) {',\r
+' mainWindow = win;',\r
+' mainWindow[windowId] = window;',\r
+' // If this is a pop-up, poll the opener to see if it\'s closed',\r
+' if (opener && closeIfOpenerCloses) {',\r
+' pollOpener();',\r
+' }',\r
+' }',\r
+'',\r
+' function pollOpener() {',\r
+' if (closeIfOpenerCloses) {',\r
+' if (mainWindowExists()) {',\r
+' setTimeout(pollOpener, 500);',\r
+' } else {',\r
+' closeWindow();',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function mainWindowExists() {',\r
+' try {',\r
+' return (mainWindow && !mainWindow.closed &&',\r
+' mainWindow[windowId] == window);',\r
+' } catch (ex) {}',\r
+' return false;',\r
+' }',\r
+'',\r
+' var logLevels = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"];',\r
+'',\r
+' function getCheckBox(logLevel) {',\r
+' return $("switch_" + logLevel);',\r
+' }',\r
+'',\r
+' function getIeWrappedLogContainer() {',\r
+' return $("log_wrapped");',\r
+' }',\r
+'',\r
+' function getIeUnwrappedLogContainer() {',\r
+' return $("log_unwrapped");',\r
+' }',\r
+'',\r
+' function applyFilters() {',\r
+' for (var i = 0; i < logLevels.length; i++) {',\r
+' if (getCheckBox(logLevels[i]).checked) {',\r
+' addClass(logMainContainer, logLevels[i]);',\r
+' } else {',\r
+' removeClass(logMainContainer, logLevels[i]);',\r
+' }',\r
+' }',\r
+' updateSearchFromFilters();',\r
+' }',\r
+'',\r
+' function toggleAllLevels() {',\r
+' var turnOn = $("switch_ALL").checked;',\r
+' for (var i = 0; i < logLevels.length; i++) {',\r
+' getCheckBox(logLevels[i]).checked = turnOn;',\r
+' if (turnOn) {',\r
+' addClass(logMainContainer, logLevels[i]);',\r
+' } else {',\r
+' removeClass(logMainContainer, logLevels[i]);',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function checkAllLevels() {',\r
+' for (var i = 0; i < logLevels.length; i++) {',\r
+' if (!getCheckBox(logLevels[i]).checked) {',\r
+' getCheckBox("ALL").checked = false;',\r
+' return;',\r
+' }',\r
+' }',\r
+' getCheckBox("ALL").checked = true;',\r
+' }',\r
+'',\r
+' function clearLog() {',\r
+' rootGroup.clear();',\r
+' currentGroup = rootGroup;',\r
+' logEntries = [];',\r
+' logItems = [];',\r
+' logEntriesAndSeparators = [];',\r
+' doSearch();',\r
+' }',\r
+'',\r
+' function toggleWrap() {',\r
+' var enable = $("wrap").checked;',\r
+' if (enable) {',\r
+' addClass(logMainContainer, "wrap");',\r
+' } else {',\r
+' removeClass(logMainContainer, "wrap");',\r
+' }',\r
+' refreshCurrentMatch();',\r
+' }',\r
+'',\r
+' /* ------------------------------------------------------------------- */',\r
+'',\r
+' // Search',\r
+'',\r
+' var searchTimer = null;',\r
+'',\r
+' function scheduleSearch() {',\r
+' try {',\r
+' clearTimeout(searchTimer);',\r
+' } catch (ex) {',\r
+' // Do nothing',\r
+' }',\r
+' searchTimer = setTimeout(doSearch, 500);',\r
+' }',\r
+'',\r
+' function Search(searchTerm, isRegex, searchRegex, isCaseSensitive) {',\r
+' this.searchTerm = searchTerm;',\r
+' this.isRegex = isRegex;',\r
+' this.searchRegex = searchRegex;',\r
+' this.isCaseSensitive = isCaseSensitive;',\r
+' this.matches = [];',\r
+' }',\r
+'',\r
+' Search.prototype = {',\r
+' hasMatches: function() {',\r
+' return this.matches.length > 0;',\r
+' },',\r
+'',\r
+' hasVisibleMatches: function() {',\r
+' if (this.hasMatches()) {',\r
+' for (var i = 0; i < this.matches.length; i++) {',\r
+' if (this.matches[i].isVisible()) {',\r
+' return true;',\r
+' }',\r
+' }',\r
+' }',\r
+' return false;',\r
+' },',\r
+'',\r
+' match: function(logEntry) {',\r
+' var entryText = String(logEntry.formattedMessage);',\r
+' var matchesSearch = false;',\r
+' if (this.isRegex) {',\r
+' matchesSearch = this.searchRegex.test(entryText);',\r
+' } else if (this.isCaseSensitive) {',\r
+' matchesSearch = (entryText.indexOf(this.searchTerm) > -1);',\r
+' } else {',\r
+' matchesSearch = (entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1);',\r
+' }',\r
+' return matchesSearch;',\r
+' },',\r
+'',\r
+' getNextVisibleMatchIndex: function() {',\r
+' for (var i = currentMatchIndex + 1; i < this.matches.length; i++) {',\r
+' if (this.matches[i].isVisible()) {',\r
+' return i;',\r
+' }',\r
+' }',\r
+' // Start again from the first match',\r
+' for (i = 0; i <= currentMatchIndex; i++) {',\r
+' if (this.matches[i].isVisible()) {',\r
+' return i;',\r
+' }',\r
+' }',\r
+' return -1;',\r
+' },',\r
+'',\r
+' getPreviousVisibleMatchIndex: function() {',\r
+' for (var i = currentMatchIndex - 1; i >= 0; i--) {',\r
+' if (this.matches[i].isVisible()) {',\r
+' return i;',\r
+' }',\r
+' }',\r
+' // Start again from the last match',\r
+' for (var i = this.matches.length - 1; i >= currentMatchIndex; i--) {',\r
+' if (this.matches[i].isVisible()) {',\r
+' return i;',\r
+' }',\r
+' }',\r
+' return -1;',\r
+' },',\r
+'',\r
+' applyTo: function(logEntry) {',\r
+' var doesMatch = this.match(logEntry);',\r
+' if (doesMatch) {',\r
+' logEntry.group.expand();',\r
+' logEntry.setSearchMatch(true);',\r
+' var logEntryContent;',\r
+' var wrappedLogEntryContent;',\r
+' var searchTermReplacementStartTag = "<span class=\\\"searchterm\\\">";',\r
+' var searchTermReplacementEndTag = "<" + "/span>";',\r
+' var preTagName = isIe ? "pre" : "span";',\r
+' var preStartTag = "<" + preTagName + " class=\\\"pre\\\">";',\r
+' var preEndTag = "<" + "/" + preTagName + ">";',\r
+' var startIndex = 0;',\r
+' var searchIndex, matchedText, textBeforeMatch;',\r
+' if (this.isRegex) {',\r
+' var flags = this.isCaseSensitive ? "g" : "gi";',\r
+' var capturingRegex = new RegExp("(" + this.searchRegex.source + ")", flags);',\r
+'',\r
+' // Replace the search term with temporary tokens for the start and end tags',\r
+' var rnd = ("" + Math.random()).substr(2);',\r
+' var startToken = "%%s" + rnd + "%%";',\r
+' var endToken = "%%e" + rnd + "%%";',\r
+' logEntryContent = logEntry.formattedMessage.replace(capturingRegex, startToken + "$1" + endToken);',\r
+'',\r
+' // Escape the HTML to get rid of angle brackets',\r
+' logEntryContent = escapeHtml(logEntryContent);',\r
+'',\r
+' // Substitute the proper HTML back in for the search match',\r
+' var result;',\r
+' var searchString = logEntryContent;',\r
+' logEntryContent = "";',\r
+' wrappedLogEntryContent = "";',\r
+' while ((searchIndex = searchString.indexOf(startToken, startIndex)) > -1) {',\r
+' var endTokenIndex = searchString.indexOf(endToken, searchIndex);',\r
+' matchedText = searchString.substring(searchIndex + startToken.length, endTokenIndex);',\r
+' textBeforeMatch = searchString.substring(startIndex, searchIndex);',\r
+' logEntryContent += preStartTag + textBeforeMatch + preEndTag;',\r
+' logEntryContent += searchTermReplacementStartTag + preStartTag + matchedText +',\r
+' preEndTag + searchTermReplacementEndTag;',\r
+' if (isIe) {',\r
+' wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +',\r
+' matchedText + searchTermReplacementEndTag;',\r
+' }',\r
+' startIndex = endTokenIndex + endToken.length;',\r
+' }',\r
+' logEntryContent += preStartTag + searchString.substr(startIndex) + preEndTag;',\r
+' if (isIe) {',\r
+' wrappedLogEntryContent += searchString.substr(startIndex);',\r
+' }',\r
+' } else {',\r
+' logEntryContent = "";',\r
+' wrappedLogEntryContent = "";',\r
+' var searchTermReplacementLength = searchTermReplacementStartTag.length +',\r
+' this.searchTerm.length + searchTermReplacementEndTag.length;',\r
+' var searchTermLength = this.searchTerm.length;',\r
+' var searchTermLowerCase = this.searchTerm.toLowerCase();',\r
+' var logTextLowerCase = logEntry.formattedMessage.toLowerCase();',\r
+' while ((searchIndex = logTextLowerCase.indexOf(searchTermLowerCase, startIndex)) > -1) {',\r
+' matchedText = escapeHtml(logEntry.formattedMessage.substr(searchIndex, this.searchTerm.length));',\r
+' textBeforeMatch = escapeHtml(logEntry.formattedMessage.substring(startIndex, searchIndex));',\r
+' var searchTermReplacement = searchTermReplacementStartTag +',\r
+' preStartTag + matchedText + preEndTag + searchTermReplacementEndTag;',\r
+' logEntryContent += preStartTag + textBeforeMatch + preEndTag + searchTermReplacement;',\r
+' if (isIe) {',\r
+' wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +',\r
+' matchedText + searchTermReplacementEndTag;',\r
+' }',\r
+' startIndex = searchIndex + searchTermLength;',\r
+' }',\r
+' var textAfterLastMatch = escapeHtml(logEntry.formattedMessage.substr(startIndex));',\r
+' logEntryContent += preStartTag + textAfterLastMatch + preEndTag;',\r
+' if (isIe) {',\r
+' wrappedLogEntryContent += textAfterLastMatch;',\r
+' }',\r
+' }',\r
+' logEntry.setContent(logEntryContent, wrappedLogEntryContent);',\r
+' var logEntryMatches = logEntry.getSearchMatches();',\r
+' this.matches = this.matches.concat(logEntryMatches);',\r
+' } else {',\r
+' logEntry.setSearchMatch(false);',\r
+' logEntry.setContent(logEntry.formattedMessage, logEntry.formattedMessage);',\r
+' }',\r
+' return doesMatch;',\r
+' },',\r
+'',\r
+' removeMatches: function(logEntries) {',\r
+' var matchesToRemoveCount = 0;',\r
+' var currentMatchRemoved = false;',\r
+' var matchesToRemove = [];',\r
+' var i, iLen, j, jLen;',\r
+'',\r
+' // Establish the list of matches to be removed',\r
+' for (i = 0, iLen = this.matches.length; i < iLen; i++) {',\r
+' for (j = 0, jLen = logEntries.length; j < jLen; j++) {',\r
+' if (this.matches[i].belongsTo(logEntries[j])) {',\r
+' matchesToRemove.push(this.matches[i]);',\r
+' if (i === currentMatchIndex) {',\r
+' currentMatchRemoved = true;',\r
+' }',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' // Set the new current match index if the current match has been deleted',\r
+' // This will be the first match that appears after the first log entry being',\r
+' // deleted, if one exists; otherwise, it\'s the first match overall',\r
+' var newMatch = currentMatchRemoved ? null : this.matches[currentMatchIndex];',\r
+' if (currentMatchRemoved) {',\r
+' for (i = currentMatchIndex, iLen = this.matches.length; i < iLen; i++) {',\r
+' if (this.matches[i].isVisible() && !array_contains(matchesToRemove, this.matches[i])) {',\r
+' newMatch = this.matches[i];',\r
+' break;',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' // Remove the matches',\r
+' for (i = 0, iLen = matchesToRemove.length; i < iLen; i++) {',\r
+' array_remove(this.matches, matchesToRemove[i]);',\r
+' matchesToRemove[i].remove();',\r
+' }',\r
+'',\r
+' // Set the new match, if one exists',\r
+' if (this.hasVisibleMatches()) {',\r
+' if (newMatch === null) {',\r
+' setCurrentMatchIndex(0);',\r
+' } else {',\r
+' // Get the index of the new match',\r
+' var newMatchIndex = 0;',\r
+' for (i = 0, iLen = this.matches.length; i < iLen; i++) {',\r
+' if (newMatch === this.matches[i]) {',\r
+' newMatchIndex = i;',\r
+' break;',\r
+' }',\r
+' }',\r
+' setCurrentMatchIndex(newMatchIndex);',\r
+' }',\r
+' } else {',\r
+' currentMatchIndex = null;',\r
+' displayNoMatches();',\r
+' }',\r
+' }',\r
+' };',\r
+'',\r
+' function getPageOffsetTop(el, container) {',\r
+' var currentEl = el;',\r
+' var y = 0;',\r
+' while (currentEl && currentEl != container) {',\r
+' y += currentEl.offsetTop;',\r
+' currentEl = currentEl.offsetParent;',\r
+' }',\r
+' return y;',\r
+' }',\r
+'',\r
+' function scrollIntoView(el) {',\r
+' var logContainer = logMainContainer;',\r
+' // Check if the whole width of the element is visible and centre if not',\r
+' if (!$("wrap").checked) {',\r
+' var logContainerLeft = logContainer.scrollLeft;',\r
+' var logContainerRight = logContainerLeft + logContainer.offsetWidth;',\r
+' var elLeft = el.offsetLeft;',\r
+' var elRight = elLeft + el.offsetWidth;',\r
+' if (elLeft < logContainerLeft || elRight > logContainerRight) {',\r
+' logContainer.scrollLeft = elLeft - (logContainer.offsetWidth - el.offsetWidth) / 2;',\r
+' }',\r
+' }',\r
+' // Check if the whole height of the element is visible and centre if not',\r
+' var logContainerTop = logContainer.scrollTop;',\r
+' var logContainerBottom = logContainerTop + logContainer.offsetHeight;',\r
+' var elTop = getPageOffsetTop(el) - getToolBarsHeight();',\r
+' var elBottom = elTop + el.offsetHeight;',\r
+' if (elTop < logContainerTop || elBottom > logContainerBottom) {',\r
+' logContainer.scrollTop = elTop - (logContainer.offsetHeight - el.offsetHeight) / 2;',\r
+' }',\r
+' }',\r
+'',\r
+' function Match(logEntryLevel, spanInMainDiv, spanInUnwrappedPre, spanInWrappedDiv) {',\r
+' this.logEntryLevel = logEntryLevel;',\r
+' this.spanInMainDiv = spanInMainDiv;',\r
+' if (isIe) {',\r
+' this.spanInUnwrappedPre = spanInUnwrappedPre;',\r
+' this.spanInWrappedDiv = spanInWrappedDiv;',\r
+' }',\r
+' this.mainSpan = isIe ? spanInUnwrappedPre : spanInMainDiv;',\r
+' }',\r
+'',\r
+' Match.prototype = {',\r
+' equals: function(match) {',\r
+' return this.mainSpan === match.mainSpan;',\r
+' },',\r
+'',\r
+' setCurrent: function() {',\r
+' if (isIe) {',\r
+' addClass(this.spanInUnwrappedPre, "currentmatch");',\r
+' addClass(this.spanInWrappedDiv, "currentmatch");',\r
+' // Scroll the visible one into view',\r
+' var elementToScroll = $("wrap").checked ? this.spanInWrappedDiv : this.spanInUnwrappedPre;',\r
+' scrollIntoView(elementToScroll);',\r
+' } else {',\r
+' addClass(this.spanInMainDiv, "currentmatch");',\r
+' scrollIntoView(this.spanInMainDiv);',\r
+' }',\r
+' },',\r
+'',\r
+' belongsTo: function(logEntry) {',\r
+' if (isIe) {',\r
+' return isDescendant(this.spanInUnwrappedPre, logEntry.unwrappedPre);',\r
+' } else {',\r
+' return isDescendant(this.spanInMainDiv, logEntry.mainDiv);',\r
+' }',\r
+' },',\r
+'',\r
+' setNotCurrent: function() {',\r
+' if (isIe) {',\r
+' removeClass(this.spanInUnwrappedPre, "currentmatch");',\r
+' removeClass(this.spanInWrappedDiv, "currentmatch");',\r
+' } else {',\r
+' removeClass(this.spanInMainDiv, "currentmatch");',\r
+' }',\r
+' },',\r
+'',\r
+' isOrphan: function() {',\r
+' return isOrphan(this.mainSpan);',\r
+' },',\r
+'',\r
+' isVisible: function() {',\r
+' return getCheckBox(this.logEntryLevel).checked;',\r
+' },',\r
+'',\r
+' remove: function() {',\r
+' if (isIe) {',\r
+' this.spanInUnwrappedPre = null;',\r
+' this.spanInWrappedDiv = null;',\r
+' } else {',\r
+' this.spanInMainDiv = null;',\r
+' }',\r
+' }',\r
+' };',\r
+'',\r
+' var currentSearch = null;',\r
+' var currentMatchIndex = null;',\r
+'',\r
+' function doSearch() {',\r
+' var searchBox = $("searchBox");',\r
+' var searchTerm = searchBox.value;',\r
+' var isRegex = $("searchRegex").checked;',\r
+' var isCaseSensitive = $("searchCaseSensitive").checked;',\r
+' var i;',\r
+'',\r
+' if (searchTerm === "") {',\r
+' $("searchReset").disabled = true;',\r
+' $("searchNav").style.display = "none";',\r
+' removeClass(document.body, "searching");',\r
+' removeClass(searchBox, "hasmatches");',\r
+' removeClass(searchBox, "nomatches");',\r
+' for (i = 0; i < logEntries.length; i++) {',\r
+' logEntries[i].clearSearch();',\r
+' logEntries[i].setContent(logEntries[i].formattedMessage, logEntries[i].formattedMessage);',\r
+' }',\r
+' currentSearch = null;',\r
+' setLogContainerHeight();',\r
+' } else {',\r
+' $("searchReset").disabled = false;',\r
+' $("searchNav").style.display = "block";',\r
+' var searchRegex;',\r
+' var regexValid;',\r
+' if (isRegex) {',\r
+' try {',\r
+' searchRegex = isCaseSensitive ? new RegExp(searchTerm, "g") : new RegExp(searchTerm, "gi");',\r
+' regexValid = true;',\r
+' replaceClass(searchBox, "validregex", "invalidregex");',\r
+' searchBox.title = "Valid regex";',\r
+' } catch (ex) {',\r
+' regexValid = false;',\r
+' replaceClass(searchBox, "invalidregex", "validregex");',\r
+' searchBox.title = "Invalid regex: " + (ex.message ? ex.message : (ex.description ? ex.description : "unknown error"));',\r
+' return;',\r
+' }',\r
+' } else {',\r
+' searchBox.title = "";',\r
+' removeClass(searchBox, "validregex");',\r
+' removeClass(searchBox, "invalidregex");',\r
+' }',\r
+' addClass(document.body, "searching");',\r
+' currentSearch = new Search(searchTerm, isRegex, searchRegex, isCaseSensitive);',\r
+' for (i = 0; i < logEntries.length; i++) {',\r
+' currentSearch.applyTo(logEntries[i]);',\r
+' }',\r
+' setLogContainerHeight();',\r
+'',\r
+' // Highlight the first search match',\r
+' if (currentSearch.hasVisibleMatches()) {',\r
+' setCurrentMatchIndex(0);',\r
+' displayMatches();',\r
+' } else {',\r
+' displayNoMatches();',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function updateSearchFromFilters() {',\r
+' if (currentSearch) {',\r
+' if (currentSearch.hasMatches()) {',\r
+' if (currentMatchIndex === null) {',\r
+' currentMatchIndex = 0;',\r
+' }',\r
+' var currentMatch = currentSearch.matches[currentMatchIndex];',\r
+' if (currentMatch.isVisible()) {',\r
+' displayMatches();',\r
+' setCurrentMatchIndex(currentMatchIndex);',\r
+' } else {',\r
+' currentMatch.setNotCurrent();',\r
+' // Find the next visible match, if one exists',\r
+' var nextVisibleMatchIndex = currentSearch.getNextVisibleMatchIndex();',\r
+' if (nextVisibleMatchIndex > -1) {',\r
+' setCurrentMatchIndex(nextVisibleMatchIndex);',\r
+' displayMatches();',\r
+' } else {',\r
+' displayNoMatches();',\r
+' }',\r
+' }',\r
+' } else {',\r
+' displayNoMatches();',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function refreshCurrentMatch() {',\r
+' if (currentSearch && currentSearch.hasVisibleMatches()) {',\r
+' setCurrentMatchIndex(currentMatchIndex);',\r
+' }',\r
+' }',\r
+'',\r
+' function displayMatches() {',\r
+' replaceClass($("searchBox"), "hasmatches", "nomatches");',\r
+' $("searchBox").title = "" + currentSearch.matches.length + " matches found";',\r
+' $("searchNav").style.display = "block";',\r
+' setLogContainerHeight();',\r
+' }',\r
+'',\r
+' function displayNoMatches() {',\r
+' replaceClass($("searchBox"), "nomatches", "hasmatches");',\r
+' $("searchBox").title = "No matches found";',\r
+' $("searchNav").style.display = "none";',\r
+' setLogContainerHeight();',\r
+' }',\r
+'',\r
+' function toggleSearchEnabled(enable) {',\r
+' enable = (typeof enable == "undefined") ? !$("searchDisable").checked : enable;',\r
+' $("searchBox").disabled = !enable;',\r
+' $("searchReset").disabled = !enable;',\r
+' $("searchRegex").disabled = !enable;',\r
+' $("searchNext").disabled = !enable;',\r
+' $("searchPrevious").disabled = !enable;',\r
+' $("searchCaseSensitive").disabled = !enable;',\r
+' $("searchNav").style.display = (enable && ($("searchBox").value !== "") &&',\r
+' currentSearch && currentSearch.hasVisibleMatches()) ?',\r
+' "block" : "none";',\r
+' if (enable) {',\r
+' removeClass($("search"), "greyedout");',\r
+' addClass(document.body, "searching");',\r
+' if ($("searchHighlight").checked) {',\r
+' addClass(logMainContainer, "searchhighlight");',\r
+' } else {',\r
+' removeClass(logMainContainer, "searchhighlight");',\r
+' }',\r
+' if ($("searchFilter").checked) {',\r
+' addClass(logMainContainer, "searchfilter");',\r
+' } else {',\r
+' removeClass(logMainContainer, "searchfilter");',\r
+' }',\r
+' $("searchDisable").checked = !enable;',\r
+' } else {',\r
+' addClass($("search"), "greyedout");',\r
+' removeClass(document.body, "searching");',\r
+' removeClass(logMainContainer, "searchhighlight");',\r
+' removeClass(logMainContainer, "searchfilter");',\r
+' }',\r
+' setLogContainerHeight();',\r
+' }',\r
+'',\r
+' function toggleSearchFilter() {',\r
+' var enable = $("searchFilter").checked;',\r
+' if (enable) {',\r
+' addClass(logMainContainer, "searchfilter");',\r
+' } else {',\r
+' removeClass(logMainContainer, "searchfilter");',\r
+' }',\r
+' refreshCurrentMatch();',\r
+' }',\r
+'',\r
+' function toggleSearchHighlight() {',\r
+' var enable = $("searchHighlight").checked;',\r
+' if (enable) {',\r
+' addClass(logMainContainer, "searchhighlight");',\r
+' } else {',\r
+' removeClass(logMainContainer, "searchhighlight");',\r
+' }',\r
+' }',\r
+'',\r
+' function clearSearch() {',\r
+' $("searchBox").value = "";',\r
+' doSearch();',\r
+' }',\r
+'',\r
+' function searchNext() {',\r
+' if (currentSearch !== null && currentMatchIndex !== null) {',\r
+' currentSearch.matches[currentMatchIndex].setNotCurrent();',\r
+' var nextMatchIndex = currentSearch.getNextVisibleMatchIndex();',\r
+' if (nextMatchIndex > currentMatchIndex || confirm("Reached the end of the page. Start from the top?")) {',\r
+' setCurrentMatchIndex(nextMatchIndex);',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function searchPrevious() {',\r
+' if (currentSearch !== null && currentMatchIndex !== null) {',\r
+' currentSearch.matches[currentMatchIndex].setNotCurrent();',\r
+' var previousMatchIndex = currentSearch.getPreviousVisibleMatchIndex();',\r
+' if (previousMatchIndex < currentMatchIndex || confirm("Reached the start of the page. Continue from the bottom?")) {',\r
+' setCurrentMatchIndex(previousMatchIndex);',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function setCurrentMatchIndex(index) {',\r
+' currentMatchIndex = index;',\r
+' currentSearch.matches[currentMatchIndex].setCurrent();',\r
+' }',\r
+'',\r
+' /* ------------------------------------------------------------------------- */',\r
+'',\r
+' // CSS Utilities',\r
+'',\r
+' function addClass(el, cssClass) {',\r
+' if (!hasClass(el, cssClass)) {',\r
+' if (el.className) {',\r
+' el.className += " " + cssClass;',\r
+' } else {',\r
+' el.className = cssClass;',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function hasClass(el, cssClass) {',\r
+' if (el.className) {',\r
+' var classNames = el.className.split(" ");',\r
+' return array_contains(classNames, cssClass);',\r
+' }',\r
+' return false;',\r
+' }',\r
+'',\r
+' function removeClass(el, cssClass) {',\r
+' if (hasClass(el, cssClass)) {',\r
+' // Rebuild the className property',\r
+' var existingClasses = el.className.split(" ");',\r
+' var newClasses = [];',\r
+' for (var i = 0, len = existingClasses.length; i < len; i++) {',\r
+' if (existingClasses[i] != cssClass) {',\r
+' newClasses[newClasses.length] = existingClasses[i];',\r
+' }',\r
+' }',\r
+' el.className = newClasses.join(" ");',\r
+' }',\r
+' }',\r
+'',\r
+' function replaceClass(el, newCssClass, oldCssClass) {',\r
+' removeClass(el, oldCssClass);',\r
+' addClass(el, newCssClass);',\r
+' }',\r
+'',\r
+' /* ------------------------------------------------------------------------- */',\r
+'',\r
+' // Other utility functions',\r
+'',\r
+' function getElementsByClass(el, cssClass, tagName) {',\r
+' var elements = el.getElementsByTagName(tagName);',\r
+' var matches = [];',\r
+' for (var i = 0, len = elements.length; i < len; i++) {',\r
+' if (hasClass(elements[i], cssClass)) {',\r
+' matches.push(elements[i]);',\r
+' }',\r
+' }',\r
+' return matches;',\r
+' }',\r
+'',\r
+' // Syntax borrowed from Prototype library',\r
+' function $(id) {',\r
+' return document.getElementById(id);',\r
+' }',\r
+'',\r
+' function isDescendant(node, ancestorNode) {',\r
+' while (node != null) {',\r
+' if (node === ancestorNode) {',\r
+' return true;',\r
+' }',\r
+' node = node.parentNode;',\r
+' }',\r
+' return false;',\r
+' }',\r
+'',\r
+' function isOrphan(node) {',\r
+' var currentNode = node;',\r
+' while (currentNode) {',\r
+' if (currentNode == document.body) {',\r
+' return false;',\r
+' }',\r
+' currentNode = currentNode.parentNode;',\r
+' }',\r
+' return true;',\r
+' }',\r
+'',\r
+' function escapeHtml(str) {',\r
+' return str.replace(/&/g, "&").replace(/[<]/g, "<").replace(/>/g, ">");',\r
+' }',\r
+'',\r
+' function getWindowWidth() {',\r
+' if (window.innerWidth) {',\r
+' return window.innerWidth;',\r
+' } else if (document.documentElement && document.documentElement.clientWidth) {',\r
+' return document.documentElement.clientWidth;',\r
+' } else if (document.body) {',\r
+' return document.body.clientWidth;',\r
+' }',\r
+' return 0;',\r
+' }',\r
+'',\r
+' function getWindowHeight() {',\r
+' if (window.innerHeight) {',\r
+' return window.innerHeight;',\r
+' } else if (document.documentElement && document.documentElement.clientHeight) {',\r
+' return document.documentElement.clientHeight;',\r
+' } else if (document.body) {',\r
+' return document.body.clientHeight;',\r
+' }',\r
+' return 0;',\r
+' }',\r
+'',\r
+' function getToolBarsHeight() {',\r
+' return $("switches").offsetHeight;',\r
+' }',\r
+'',\r
+' function getChromeHeight() {',\r
+' var height = getToolBarsHeight();',\r
+' if (showCommandLine) {',\r
+' height += $("commandLine").offsetHeight;',\r
+' }',\r
+' return height;',\r
+' }',\r
+'',\r
+' function setLogContainerHeight() {',\r
+' if (logMainContainer) {',\r
+' var windowHeight = getWindowHeight();',\r
+' $("body").style.height = getWindowHeight() + "px";',\r
+' logMainContainer.style.height = "" +',\r
+' Math.max(0, windowHeight - getChromeHeight()) + "px";',\r
+' }',\r
+' }',\r
+'',\r
+' function setCommandInputWidth() {',\r
+' if (showCommandLine) {',\r
+' $("command").style.width = "" + Math.max(0, $("commandLineContainer").offsetWidth -',\r
+' ($("evaluateButton").offsetWidth + 13)) + "px";',\r
+' }',\r
+' }',\r
+'',\r
+' window.onresize = function() {',\r
+' setCommandInputWidth();',\r
+' setLogContainerHeight();',\r
+' };',\r
+'',\r
+' if (!Array.prototype.push) {',\r
+' Array.prototype.push = function() {',\r
+' for (var i = 0, len = arguments.length; i < len; i++){',\r
+' this[this.length] = arguments[i];',\r
+' }',\r
+' return this.length;',\r
+' };',\r
+' }',\r
+'',\r
+' if (!Array.prototype.pop) {',\r
+' Array.prototype.pop = function() {',\r
+' if (this.length > 0) {',\r
+' var val = this[this.length - 1];',\r
+' this.length = this.length - 1;',\r
+' return val;',\r
+' }',\r
+' };',\r
+' }',\r
+'',\r
+' if (!Array.prototype.shift) {',\r
+' Array.prototype.shift = function() {',\r
+' if (this.length > 0) {',\r
+' var firstItem = this[0];',\r
+' for (var i = 0, len = this.length - 1; i < len; i++) {',\r
+' this[i] = this[i + 1];',\r
+' }',\r
+' this.length = this.length - 1;',\r
+' return firstItem;',\r
+' }',\r
+' };',\r
+' }',\r
+'',\r
+' if (!Array.prototype.splice) {',\r
+' Array.prototype.splice = function(startIndex, deleteCount) {',\r
+' var itemsAfterDeleted = this.slice(startIndex + deleteCount);',\r
+' var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);',\r
+' this.length = startIndex;',\r
+' // Copy the arguments into a proper Array object',\r
+' var argumentsArray = [];',\r
+' for (var i = 0, len = arguments.length; i < len; i++) {',\r
+' argumentsArray[i] = arguments[i];',\r
+' }',\r
+' var itemsToAppend = (argumentsArray.length > 2) ?',\r
+' itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;',\r
+' for (i = 0, len = itemsToAppend.length; i < len; i++) {',\r
+' this.push(itemsToAppend[i]);',\r
+' }',\r
+' return itemsDeleted;',\r
+' };',\r
+' }',\r
+'',\r
+' function array_remove(arr, val) {',\r
+' var index = -1;',\r
+' for (var i = 0, len = arr.length; i < len; i++) {',\r
+' if (arr[i] === val) {',\r
+' index = i;',\r
+' break;',\r
+' }',\r
+' }',\r
+' if (index >= 0) {',\r
+' arr.splice(index, 1);',\r
+' return index;',\r
+' } else {',\r
+' return false;',\r
+' }',\r
+' }',\r
+'',\r
+' function array_removeFromStart(array, numberToRemove) {',\r
+' if (Array.prototype.splice) {',\r
+' array.splice(0, numberToRemove);',\r
+' } else {',\r
+' for (var i = numberToRemove, len = array.length; i < len; i++) {',\r
+' array[i - numberToRemove] = array[i];',\r
+' }',\r
+' array.length = array.length - numberToRemove;',\r
+' }',\r
+' return array;',\r
+' }',\r
+'',\r
+' function array_contains(arr, val) {',\r
+' for (var i = 0, len = arr.length; i < len; i++) {',\r
+' if (arr[i] == val) {',\r
+' return true;',\r
+' }',\r
+' }',\r
+' return false;',\r
+' }',\r
+'',\r
+' function getErrorMessage(ex) {',\r
+' if (ex.message) {',\r
+' return ex.message;',\r
+' } else if (ex.description) {',\r
+' return ex.description;',\r
+' }',\r
+' return "" + ex;',\r
+' }',\r
+'',\r
+' function moveCaretToEnd(input) {',\r
+' if (input.setSelectionRange) {',\r
+' input.focus();',\r
+' var length = input.value.length;',\r
+' input.setSelectionRange(length, length);',\r
+' } else if (input.createTextRange) {',\r
+' var range = input.createTextRange();',\r
+' range.collapse(false);',\r
+' range.select();',\r
+' }',\r
+' input.focus();',\r
+' }',\r
+'',\r
+' function stopPropagation(evt) {',\r
+' if (evt.stopPropagation) {',\r
+' evt.stopPropagation();',\r
+' } else if (typeof evt.cancelBubble != "undefined") {',\r
+' evt.cancelBubble = true;',\r
+' }',\r
+' }',\r
+'',\r
+' function getEvent(evt) {',\r
+' return evt ? evt : event;',\r
+' }',\r
+'',\r
+' function getTarget(evt) {',\r
+' return evt.target ? evt.target : evt.srcElement;',\r
+' }',\r
+'',\r
+' function getRelatedTarget(evt) {',\r
+' if (evt.relatedTarget) {',\r
+' return evt.relatedTarget;',\r
+' } else if (evt.srcElement) {',\r
+' switch(evt.type) {',\r
+' case "mouseover":',\r
+' return evt.fromElement;',\r
+' case "mouseout":',\r
+' return evt.toElement;',\r
+' default:',\r
+' return evt.srcElement;',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function cancelKeyEvent(evt) {',\r
+' evt.returnValue = false;',\r
+' stopPropagation(evt);',\r
+' }',\r
+'',\r
+' function evalCommandLine() {',\r
+' var expr = $("command").value;',\r
+' evalCommand(expr);',\r
+' $("command").value = "";',\r
+' }',\r
+'',\r
+' function evalLastCommand() {',\r
+' if (lastCommand != null) {',\r
+' evalCommand(lastCommand);',\r
+' }',\r
+' }',\r
+'',\r
+' var lastCommand = null;',\r
+' var commandHistory = [];',\r
+' var currentCommandIndex = 0;',\r
+'',\r
+' function evalCommand(expr) {',\r
+' if (appender) {',\r
+' appender.evalCommandAndAppend(expr);',\r
+' } else {',\r
+' var prefix = ">>> " + expr + "\\r\\n";',\r
+' try {',\r
+' log("INFO", prefix + eval(expr));',\r
+' } catch (ex) {',\r
+' log("ERROR", prefix + "Error: " + getErrorMessage(ex));',\r
+' }',\r
+' }',\r
+' // Update command history',\r
+' if (expr != commandHistory[commandHistory.length - 1]) {',\r
+' commandHistory.push(expr);',\r
+' // Update the appender',\r
+' if (appender) {',\r
+' appender.storeCommandHistory(commandHistory);',\r
+' }',\r
+' }',\r
+' currentCommandIndex = (expr == commandHistory[currentCommandIndex]) ? currentCommandIndex + 1 : commandHistory.length;',\r
+' lastCommand = expr;',\r
+' }',\r
+' //]]>',\r
+' </script>',\r
+' <style type="text/css">',\r
+' body {',\r
+' background-color: white;',\r
+' color: black;',\r
+' padding: 0;',\r
+' margin: 0;',\r
+' font-family: tahoma, verdana, arial, helvetica, sans-serif;',\r
+' overflow: hidden;',\r
+' }',\r
+'',\r
+' div#switchesContainer input {',\r
+' margin-bottom: 0;',\r
+' }',\r
+'',\r
+' div.toolbar {',\r
+' border-top: solid #ffffff 1px;',\r
+' border-bottom: solid #aca899 1px;',\r
+' background-color: #f1efe7;',\r
+' padding: 3px 5px;',\r
+' font-size: 68.75%;',\r
+' }',\r
+'',\r
+' div.toolbar, div#search input {',\r
+' font-family: tahoma, verdana, arial, helvetica, sans-serif;',\r
+' }',\r
+'',\r
+' div.toolbar input.button {',\r
+' padding: 0 5px;',\r
+' font-size: 100%;',\r
+' }',\r
+'',\r
+' div.toolbar input.hidden {',\r
+' display: none;',\r
+' }',\r
+'',\r
+' div#switches input#clearButton {',\r
+' margin-left: 20px;',\r
+' }',\r
+'',\r
+' div#levels label {',\r
+' font-weight: bold;',\r
+' }',\r
+'',\r
+' div#levels label, div#options label {',\r
+' margin-right: 5px;',\r
+' }',\r
+'',\r
+' div#levels label#wrapLabel {',\r
+' font-weight: normal;',\r
+' }',\r
+'',\r
+' div#search label {',\r
+' margin-right: 10px;',\r
+' }',\r
+'',\r
+' div#search label.searchboxlabel {',\r
+' margin-right: 0;',\r
+' }',\r
+'',\r
+' div#search input {',\r
+' font-size: 100%;',\r
+' }',\r
+'',\r
+' div#search input.validregex {',\r
+' color: green;',\r
+' }',\r
+'',\r
+' div#search input.invalidregex {',\r
+' color: red;',\r
+' }',\r
+'',\r
+' div#search input.nomatches {',\r
+' color: white;',\r
+' background-color: #ff6666;',\r
+' }',\r
+'',\r
+' div#search input.nomatches {',\r
+' color: white;',\r
+' background-color: #ff6666;',\r
+' }',\r
+'',\r
+' div#searchNav {',\r
+' display: none;',\r
+' }',\r
+'',\r
+' div#commandLine {',\r
+' display: none;',\r
+' }',\r
+'',\r
+' div#commandLine input#command {',\r
+' font-size: 100%;',\r
+' font-family: Courier New, Courier;',\r
+' }',\r
+'',\r
+' div#commandLine input#evaluateButton {',\r
+' }',\r
+'',\r
+' *.greyedout {',\r
+' color: gray !important;',\r
+' border-color: gray !important;',\r
+' }',\r
+'',\r
+' *.greyedout *.alwaysenabled { color: black; }',\r
+'',\r
+' *.unselectable {',\r
+' -khtml-user-select: none;',\r
+' -moz-user-select: none;',\r
+' user-select: none;',\r
+' }',\r
+'',\r
+' div#log {',\r
+' font-family: Courier New, Courier;',\r
+' font-size: 75%;',\r
+' width: 100%;',\r
+' overflow: auto;',\r
+' clear: both;',\r
+' position: relative;',\r
+' }',\r
+'',\r
+' div.group {',\r
+' border-color: #cccccc;',\r
+' border-style: solid;',\r
+' border-width: 1px 0 1px 1px;',\r
+' overflow: visible;',\r
+' }',\r
+'',\r
+' div.oldIe div.group, div.oldIe div.group *, div.oldIe *.logentry {',\r
+' height: 1%;',\r
+' }',\r
+'',\r
+' div.group div.groupheading span.expander {',\r
+' border: solid black 1px;',\r
+' font-family: Courier New, Courier;',\r
+' font-size: 0.833em;',\r
+' background-color: #eeeeee;',\r
+' position: relative;',\r
+' top: -1px;',\r
+' color: black;',\r
+' padding: 0 2px;',\r
+' cursor: pointer;',\r
+' cursor: hand;',\r
+' height: 1%;',\r
+' }',\r
+'',\r
+' div.group div.groupcontent {',\r
+' margin-left: 10px;',\r
+' padding-bottom: 2px;',\r
+' overflow: visible;',\r
+' }',\r
+'',\r
+' div.group div.expanded {',\r
+' display: block;',\r
+' }',\r
+'',\r
+' div.group div.collapsed {',\r
+' display: none;',\r
+' }',\r
+'',\r
+' *.logentry {',\r
+' overflow: visible;',\r
+' display: none;',\r
+' white-space: pre;',\r
+' }',\r
+'',\r
+' span.pre {',\r
+' white-space: pre;',\r
+' }',\r
+' ',\r
+' pre.unwrapped {',\r
+' display: inline !important;',\r
+' }',\r
+'',\r
+' pre.unwrapped pre.pre, div.wrapped pre.pre {',\r
+' display: inline;',\r
+' }',\r
+'',\r
+' div.wrapped pre.pre {',\r
+' white-space: normal;',\r
+' }',\r
+'',\r
+' div.wrapped {',\r
+' display: none;',\r
+' }',\r
+'',\r
+' body.searching *.logentry span.currentmatch {',\r
+' color: white !important;',\r
+' background-color: green !important;',\r
+' }',\r
+'',\r
+' body.searching div.searchhighlight *.logentry span.searchterm {',\r
+' color: black;',\r
+' background-color: yellow;',\r
+' }',\r
+'',\r
+' div.wrap *.logentry {',\r
+' white-space: normal !important;',\r
+' border-width: 0 0 1px 0;',\r
+' border-color: #dddddd;',\r
+' border-style: dotted;',\r
+' }',\r
+'',\r
+' div.wrap #log_wrapped, #log_unwrapped {',\r
+' display: block;',\r
+' }',\r
+'',\r
+' div.wrap #log_unwrapped, #log_wrapped {',\r
+' display: none;',\r
+' }',\r
+'',\r
+' div.wrap *.logentry span.pre {',\r
+' overflow: visible;',\r
+' white-space: normal;',\r
+' }',\r
+'',\r
+' div.wrap *.logentry pre.unwrapped {',\r
+' display: none;',\r
+' }',\r
+'',\r
+' div.wrap *.logentry span.wrapped {',\r
+' display: inline;',\r
+' }',\r
+'',\r
+' div.searchfilter *.searchnonmatch {',\r
+' display: none !important;',\r
+' }',\r
+'',\r
+' div#log *.TRACE, label#label_TRACE {',\r
+' color: #666666;',\r
+' }',\r
+'',\r
+' div#log *.DEBUG, label#label_DEBUG {',\r
+' color: green;',\r
+' }',\r
+'',\r
+' div#log *.INFO, label#label_INFO {',\r
+' color: #000099;',\r
+' }',\r
+'',\r
+' div#log *.WARN, label#label_WARN {',\r
+' color: #999900;',\r
+' }',\r
+'',\r
+' div#log *.ERROR, label#label_ERROR {',\r
+' color: red;',\r
+' }',\r
+'',\r
+' div#log *.FATAL, label#label_FATAL {',\r
+' color: #660066;',\r
+' }',\r
+'',\r
+' div.TRACE#log *.TRACE,',\r
+' div.DEBUG#log *.DEBUG,',\r
+' div.INFO#log *.INFO,',\r
+' div.WARN#log *.WARN,',\r
+' div.ERROR#log *.ERROR,',\r
+' div.FATAL#log *.FATAL {',\r
+' display: block;',\r
+' }',\r
+'',\r
+' div#log div.separator {',\r
+' background-color: #cccccc;',\r
+' margin: 5px 0;',\r
+' line-height: 1px;',\r
+' }',\r
+' </style>',\r
+' </head>',\r
+'',\r
+' <body id="body">',\r
+' <div id="switchesContainer">',\r
+' <div id="switches">',\r
+' <div id="levels" class="toolbar">',\r
+' Filters:',\r
+' <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>',\r
+' <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>',\r
+' <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>',\r
+' <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>',\r
+' <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>',\r
+' <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>',\r
+' <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>',\r
+' </div>',\r
+' <div id="search" class="toolbar">',\r
+' <label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />',\r
+' <input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />',\r
+' <input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>',\r
+' <input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>',\r
+' <input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>',\r
+' <div id="searchNav">',\r
+' <input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />',\r
+' <input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />',\r
+' <input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>',\r
+' <input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>',\r
+' </div>',\r
+' </div>',\r
+' <div id="options" class="toolbar">',\r
+' Options:',\r
+' <input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>',\r
+' <input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>',\r
+' <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>',\r
+' <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>',\r
+' <input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages" />',\r
+' <input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />',\r
+' <input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />',\r
+' </div>',\r
+' </div>',\r
+' </div>',\r
+' <div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>',\r
+' <div id="commandLine" class="toolbar">',\r
+' <div id="commandLineContainer">',\r
+' <input type="text" id="command" title="Enter a JavaScript command here and hit return or press \'Evaluate\'" />',\r
+' <input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />',\r
+' </div>',\r
+' </div>',\r
+' </body>',\r
+'</html>',\r
+''\r
+];\r
+ };\r
+\r
+ var defaultCommandLineFunctions = [];\r
+\r
+ ConsoleAppender = function() {};\r
+\r
+ var consoleAppenderIdCounter = 1;\r
+ ConsoleAppender.prototype = new Appender();\r
+\r
+ ConsoleAppender.prototype.create = function(inPage, container,\r
+ lazyInit, initiallyMinimized, useDocumentWrite, width, height, focusConsoleWindow) {\r
+ var appender = this;\r
+\r
+ // Common properties\r
+ var initialized = false;\r
+ var consoleWindowCreated = false;\r
+ var consoleWindowLoaded = false;\r
+ var consoleClosed = false;\r
+\r
+ var queuedLoggingEvents = [];\r
+ var isSupported = true;\r
+ var consoleAppenderId = consoleAppenderIdCounter++;\r
+\r
+ // Local variables\r
+ initiallyMinimized = extractBooleanFromParam(initiallyMinimized, this.defaults.initiallyMinimized);\r
+ lazyInit = extractBooleanFromParam(lazyInit, this.defaults.lazyInit);\r
+ useDocumentWrite = extractBooleanFromParam(useDocumentWrite, this.defaults.useDocumentWrite);\r
+ var newestMessageAtTop = this.defaults.newestMessageAtTop;\r
+ var scrollToLatestMessage = this.defaults.scrollToLatestMessage;\r
+ width = width ? width : this.defaults.width;\r
+ height = height ? height : this.defaults.height;\r
+ var maxMessages = this.defaults.maxMessages;\r
+ var showCommandLine = this.defaults.showCommandLine;\r
+ var commandLineObjectExpansionDepth = this.defaults.commandLineObjectExpansionDepth;\r
+ var showHideButton = this.defaults.showHideButton;\r
+ var showCloseButton = this.defaults.showCloseButton;\r
+ var showLogEntryDeleteButtons = this.defaults.showLogEntryDeleteButtons;\r
+\r
+ this.setLayout(this.defaults.layout);\r
+\r
+ // Functions whose implementations vary between subclasses\r
+ var init, createWindow, safeToAppend, getConsoleWindow, open;\r
+\r
+ // Configuration methods. The function scope is used to prevent\r
+ // direct alteration to the appender configuration properties.\r
+ var appenderName = inPage ? "InPageAppender" : "PopUpAppender";\r
+ var checkCanConfigure = function(configOptionName) {\r
+ if (consoleWindowCreated) {\r
+ handleError(appenderName + ": configuration option '" + configOptionName + "' may not be set after the appender has been initialized");\r
+ return false;\r
+ }\r
+ return true;\r
+ };\r
+\r
+ var consoleWindowExists = function() {\r
+ return (consoleWindowLoaded && isSupported && !consoleClosed);\r
+ };\r
+\r
+ this.isNewestMessageAtTop = function() { return newestMessageAtTop; };\r
+ this.setNewestMessageAtTop = function(newestMessageAtTopParam) {\r
+ newestMessageAtTop = bool(newestMessageAtTopParam);\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().setNewestAtTop(newestMessageAtTop);\r
+ }\r
+ };\r
+\r
+ this.isScrollToLatestMessage = function() { return scrollToLatestMessage; };\r
+ this.setScrollToLatestMessage = function(scrollToLatestMessageParam) {\r
+ scrollToLatestMessage = bool(scrollToLatestMessageParam);\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().setScrollToLatest(scrollToLatestMessage);\r
+ }\r
+ };\r
+\r
+ this.getWidth = function() { return width; };\r
+ this.setWidth = function(widthParam) {\r
+ if (checkCanConfigure("width")) {\r
+ width = extractStringFromParam(widthParam, width);\r
+ }\r
+ };\r
+\r
+ this.getHeight = function() { return height; };\r
+ this.setHeight = function(heightParam) {\r
+ if (checkCanConfigure("height")) {\r
+ height = extractStringFromParam(heightParam, height);\r
+ }\r
+ };\r
+\r
+ this.getMaxMessages = function() { return maxMessages; };\r
+ this.setMaxMessages = function(maxMessagesParam) {\r
+ maxMessages = extractIntFromParam(maxMessagesParam, maxMessages);\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().setMaxMessages(maxMessages);\r
+ }\r
+ };\r
+\r
+ this.isShowCommandLine = function() { return showCommandLine; };\r
+ this.setShowCommandLine = function(showCommandLineParam) {\r
+ showCommandLine = bool(showCommandLineParam);\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().setShowCommandLine(showCommandLine);\r
+ }\r
+ };\r
+\r
+ this.isShowHideButton = function() { return showHideButton; };\r
+ this.setShowHideButton = function(showHideButtonParam) {\r
+ showHideButton = bool(showHideButtonParam);\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().setShowHideButton(showHideButton);\r
+ }\r
+ };\r
+\r
+ this.isShowCloseButton = function() { return showCloseButton; };\r
+ this.setShowCloseButton = function(showCloseButtonParam) {\r
+ showCloseButton = bool(showCloseButtonParam);\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().setShowCloseButton(showCloseButton);\r
+ }\r
+ };\r
+\r
+ this.getCommandLineObjectExpansionDepth = function() { return commandLineObjectExpansionDepth; };\r
+ this.setCommandLineObjectExpansionDepth = function(commandLineObjectExpansionDepthParam) {\r
+ commandLineObjectExpansionDepth = extractIntFromParam(commandLineObjectExpansionDepthParam, commandLineObjectExpansionDepth);\r
+ };\r
+\r
+ var minimized = initiallyMinimized;\r
+ this.isInitiallyMinimized = function() { return initiallyMinimized; };\r
+ this.setInitiallyMinimized = function(initiallyMinimizedParam) {\r
+ if (checkCanConfigure("initiallyMinimized")) {\r
+ initiallyMinimized = bool(initiallyMinimizedParam);\r
+ minimized = initiallyMinimized;\r
+ }\r
+ };\r
+\r
+ this.isUseDocumentWrite = function() { return useDocumentWrite; };\r
+ this.setUseDocumentWrite = function(useDocumentWriteParam) {\r
+ if (checkCanConfigure("useDocumentWrite")) {\r
+ useDocumentWrite = bool(useDocumentWriteParam);\r
+ }\r
+ };\r
+\r
+ // Common methods\r
+ function QueuedLoggingEvent(loggingEvent, formattedMessage) {\r
+ this.loggingEvent = loggingEvent;\r
+ this.levelName = loggingEvent.level.name;\r
+ this.formattedMessage = formattedMessage;\r
+ }\r
+\r
+ QueuedLoggingEvent.prototype.append = function() {\r
+ getConsoleWindow().log(this.levelName, this.formattedMessage);\r
+ };\r
+\r
+ function QueuedGroup(name, initiallyExpanded) {\r
+ this.name = name;\r
+ this.initiallyExpanded = initiallyExpanded;\r
+ }\r
+\r
+ QueuedGroup.prototype.append = function() {\r
+ getConsoleWindow().group(this.name, this.initiallyExpanded);\r
+ };\r
+\r
+ function QueuedGroupEnd() {}\r
+\r
+ QueuedGroupEnd.prototype.append = function() {\r
+ getConsoleWindow().groupEnd();\r
+ };\r
+\r
+ var checkAndAppend = function() {\r
+ // Next line forces a check of whether the window has been closed\r
+ safeToAppend();\r
+ if (!initialized) {\r
+ init();\r
+ } else if (consoleClosed && reopenWhenClosed) {\r
+ createWindow();\r
+ }\r
+ if (safeToAppend()) {\r
+ appendQueuedLoggingEvents();\r
+ }\r
+ };\r
+\r
+ this.append = function(loggingEvent) {\r
+ if (isSupported) {\r
+ // Format the message\r
+ var formattedMessage = appender.getLayout().format(loggingEvent);\r
+ if (this.getLayout().ignoresThrowable()) {\r
+ formattedMessage += loggingEvent.getThrowableStrRep();\r
+ }\r
+ queuedLoggingEvents.push(new QueuedLoggingEvent(loggingEvent, formattedMessage));\r
+ checkAndAppend();\r
+ }\r
+ };\r
+\r
+ this.group = function(name, initiallyExpanded) {\r
+ if (isSupported) {\r
+ queuedLoggingEvents.push(new QueuedGroup(name, initiallyExpanded));\r
+ checkAndAppend();\r
+ }\r
+ };\r
+\r
+ this.groupEnd = function() {\r
+ if (isSupported) {\r
+ queuedLoggingEvents.push(new QueuedGroupEnd());\r
+ checkAndAppend();\r
+ }\r
+ };\r
+\r
+ var appendQueuedLoggingEvents = function() {\r
+ var currentLoggingEvent;\r
+ while (queuedLoggingEvents.length > 0) {\r
+ queuedLoggingEvents.shift().append();\r
+ }\r
+ if (focusConsoleWindow) {\r
+ getConsoleWindow().focus();\r
+ }\r
+ };\r
+\r
+ this.setAddedToLogger = function(logger) {\r
+ this.loggers.push(logger);\r
+ if (enabled && !lazyInit) {\r
+ init();\r
+ }\r
+ };\r
+\r
+ this.clear = function() {\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().clearLog();\r
+ }\r
+ queuedLoggingEvents.length = 0;\r
+ };\r
+\r
+ this.focus = function() {\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().focus();\r
+ }\r
+ };\r
+\r
+ this.focusCommandLine = function() {\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().focusCommandLine();\r
+ }\r
+ };\r
+\r
+ this.focusSearch = function() {\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().focusSearch();\r
+ }\r
+ };\r
+\r
+ var commandWindow = window;\r
+\r
+ this.getCommandWindow = function() { return commandWindow; };\r
+ this.setCommandWindow = function(commandWindowParam) {\r
+ commandWindow = commandWindowParam;\r
+ };\r
+\r
+ this.executeLastCommand = function() {\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().evalLastCommand();\r
+ }\r
+ };\r
+\r
+ var commandLayout = new PatternLayout("%m");\r
+ this.getCommandLayout = function() { return commandLayout; };\r
+ this.setCommandLayout = function(commandLayoutParam) {\r
+ commandLayout = commandLayoutParam;\r
+ };\r
+\r
+ this.evalCommandAndAppend = function(expr) {\r
+ var commandReturnValue = { appendResult: true, isError: false };\r
+ var commandOutput = "";\r
+ // Evaluate the command\r
+ try {\r
+ var result, i;\r
+ // The next three lines constitute a workaround for IE. Bizarrely, iframes seem to have no\r
+ // eval method on the window object initially, but once execScript has been called on\r
+ // it once then the eval method magically appears. See http://www.thismuchiknow.co.uk/?p=25\r
+ if (!commandWindow.eval && commandWindow.execScript) {\r
+ commandWindow.execScript("null");\r
+ }\r
+\r
+ var commandLineFunctionsHash = {};\r
+ for (i = 0, len = commandLineFunctions.length; i < len; i++) {\r
+ commandLineFunctionsHash[commandLineFunctions[i][0]] = commandLineFunctions[i][1];\r
+ }\r
+\r
+ // Keep an array of variables that are being changed in the command window so that they\r
+ // can be restored to their original values afterwards\r
+ var objectsToRestore = [];\r
+ var addObjectToRestore = function(name) {\r
+ objectsToRestore.push([name, commandWindow[name]]);\r
+ };\r
+\r
+ addObjectToRestore("appender");\r
+ commandWindow.appender = appender;\r
+\r
+ addObjectToRestore("commandReturnValue");\r
+ commandWindow.commandReturnValue = commandReturnValue;\r
+\r
+ addObjectToRestore("commandLineFunctionsHash");\r
+ commandWindow.commandLineFunctionsHash = commandLineFunctionsHash;\r
+\r
+ var addFunctionToWindow = function(name) {\r
+ addObjectToRestore(name);\r
+ commandWindow[name] = function() {\r
+ return this.commandLineFunctionsHash[name](appender, arguments, commandReturnValue);\r
+ };\r
+ };\r
+\r
+ for (i = 0, len = commandLineFunctions.length; i < len; i++) {\r
+ addFunctionToWindow(commandLineFunctions[i][0]);\r
+ }\r
+\r
+ // Another bizarre workaround to get IE to eval in the global scope\r
+ if (commandWindow === window && commandWindow.execScript) {\r
+ addObjectToRestore("evalExpr");\r
+ addObjectToRestore("result");\r
+ window.evalExpr = expr;\r
+ commandWindow.execScript("window.result=eval(window.evalExpr);");\r
+ result = window.result;\r
+ } else {\r
+ result = commandWindow.eval(expr);\r
+ }\r
+ commandOutput = isUndefined(result) ? result : formatObjectExpansion(result, commandLineObjectExpansionDepth);\r
+\r
+ // Restore variables in the command window to their original state\r
+ for (i = 0, len = objectsToRestore.length; i < len; i++) {\r
+ commandWindow[objectsToRestore[i][0]] = objectsToRestore[i][1];\r
+ }\r
+ } catch (ex) {\r
+ commandOutput = "Error evaluating command: " + getExceptionStringRep(ex);\r
+ commandReturnValue.isError = true;\r
+ }\r
+ // Append command output\r
+ if (commandReturnValue.appendResult) {\r
+ var message = ">>> " + expr;\r
+ if (!isUndefined(commandOutput)) {\r
+ message += newLine + commandOutput;\r
+ }\r
+ var level = commandReturnValue.isError ? Level.ERROR : Level.INFO;\r
+ var loggingEvent = new LoggingEvent(null, new Date(), level, [message], null);\r
+ var mainLayout = this.getLayout();\r
+ this.setLayout(commandLayout);\r
+ this.append(loggingEvent);\r
+ this.setLayout(mainLayout);\r
+ }\r
+ };\r
+\r
+ var commandLineFunctions = defaultCommandLineFunctions.concat([]);\r
+\r
+ this.addCommandLineFunction = function(functionName, commandLineFunction) {\r
+ commandLineFunctions.push([functionName, commandLineFunction]);\r
+ };\r
+\r
+ var commandHistoryCookieName = "log4javascriptCommandHistory";\r
+ this.storeCommandHistory = function(commandHistory) {\r
+ setCookie(commandHistoryCookieName, commandHistory.join(","));\r
+ };\r
+\r
+ var writeHtml = function(doc) {\r
+ var lines = getConsoleHtmlLines();\r
+ doc.open();\r
+ for (var i = 0, len = lines.length; i < len; i++) {\r
+ doc.writeln(lines[i]);\r
+ }\r
+ doc.close();\r
+ };\r
+\r
+ // Set up event listeners\r
+ this.setEventTypes(["load", "unload"]);\r
+\r
+ var consoleWindowLoadHandler = function() {\r
+ var win = getConsoleWindow();\r
+ win.setAppender(appender);\r
+ win.setNewestAtTop(newestMessageAtTop);\r
+ win.setScrollToLatest(scrollToLatestMessage);\r
+ win.setMaxMessages(maxMessages);\r
+ win.setShowCommandLine(showCommandLine);\r
+ win.setShowHideButton(showHideButton);\r
+ win.setShowCloseButton(showCloseButton);\r
+ win.setMainWindow(window);\r
+\r
+ // Restore command history stored in cookie\r
+ var storedValue = getCookie(commandHistoryCookieName);\r
+ if (storedValue) {\r
+ win.commandHistory = storedValue.split(",");\r
+ win.currentCommandIndex = win.commandHistory.length;\r
+ }\r
+\r
+ appender.dispatchEvent("load", { "win" : win });\r
+ };\r
+\r
+ this.unload = function() {\r
+ logLog.debug("unload " + this + ", caller: " + this.unload.caller);\r
+ if (!consoleClosed) {\r
+ logLog.debug("really doing unload " + this);\r
+ consoleClosed = true;\r
+ consoleWindowLoaded = false;\r
+ consoleWindowCreated = false;\r
+ appender.dispatchEvent("unload", {});\r
+ }\r
+ };\r
+\r
+ var pollConsoleWindow = function(windowTest, interval, successCallback, errorMessage) {\r
+ function doPoll() {\r
+ try {\r
+ // Test if the console has been closed while polling\r
+ if (consoleClosed) {\r
+ clearInterval(poll);\r
+ }\r
+ if (windowTest(getConsoleWindow())) {\r
+ clearInterval(poll);\r
+ successCallback();\r
+ }\r
+ } catch (ex) {\r
+ clearInterval(poll);\r
+ isSupported = false;\r
+ handleError(errorMessage, ex);\r
+ }\r
+ }\r
+\r
+ // Poll the pop-up since the onload event is not reliable\r
+ var poll = setInterval(doPoll, interval);\r
+ };\r
+\r
+ var getConsoleUrl = function() {\r
+ var documentDomainSet = (document.domain != location.hostname);\r
+ return useDocumentWrite ? "" : getBaseUrl() + "console_uncompressed.html" +\r
+ (documentDomainSet ? "?log4javascript_domain=" + escape(document.domain) : "");\r
+ };\r
+\r
+ // Define methods and properties that vary between subclasses\r
+ if (inPage) {\r
+ // InPageAppender\r
+\r
+ var containerElement = null;\r
+\r
+ // Configuration methods. The function scope is used to prevent\r
+ // direct alteration to the appender configuration properties.\r
+ var cssProperties = [];\r
+ this.addCssProperty = function(name, value) {\r
+ if (checkCanConfigure("cssProperties")) {\r
+ cssProperties.push([name, value]);\r
+ }\r
+ };\r
+\r
+ // Define useful variables\r
+ var windowCreationStarted = false;\r
+ var iframeContainerDiv;\r
+ var iframeId = uniqueId + "_InPageAppender_" + consoleAppenderId;\r
+\r
+ this.hide = function() {\r
+ if (initialized && consoleWindowCreated) {\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().$("command").blur();\r
+ }\r
+ iframeContainerDiv.style.display = "none";\r
+ minimized = true;\r
+ }\r
+ };\r
+\r
+ this.show = function() {\r
+ if (initialized) {\r
+ if (consoleWindowCreated) {\r
+ iframeContainerDiv.style.display = "block";\r
+ this.setShowCommandLine(showCommandLine); // Force IE to update\r
+ minimized = false;\r
+ } else if (!windowCreationStarted) {\r
+ createWindow(true);\r
+ }\r
+ }\r
+ };\r
+\r
+ this.isVisible = function() {\r
+ return !minimized && !consoleClosed;\r
+ };\r
+\r
+ this.close = function(fromButton) {\r
+ if (!consoleClosed && (!fromButton || confirm("This will permanently remove the console from the page. No more messages will be logged. Do you wish to continue?"))) {\r
+ iframeContainerDiv.parentNode.removeChild(iframeContainerDiv);\r
+ this.unload();\r
+ }\r
+ };\r
+\r
+ // Create open, init, getConsoleWindow and safeToAppend functions\r
+ open = function() {\r
+ var initErrorMessage = "InPageAppender.open: unable to create console iframe";\r
+\r
+ function finalInit() {\r
+ try {\r
+ if (!initiallyMinimized) {\r
+ appender.show();\r
+ }\r
+ consoleWindowLoadHandler();\r
+ consoleWindowLoaded = true;\r
+ appendQueuedLoggingEvents();\r
+ } catch (ex) {\r
+ isSupported = false;\r
+ handleError(initErrorMessage, ex);\r
+ }\r
+ }\r
+\r
+ function writeToDocument() {\r
+ try {\r
+ var windowTest = function(win) { return isLoaded(win); };\r
+ if (useDocumentWrite) {\r
+ writeHtml(getConsoleWindow().document);\r
+ }\r
+ if (windowTest(getConsoleWindow())) {\r
+ finalInit();\r
+ } else {\r
+ pollConsoleWindow(windowTest, 100, finalInit, initErrorMessage);\r
+ }\r
+ } catch (ex) {\r
+ isSupported = false;\r
+ handleError(initErrorMessage, ex);\r
+ }\r
+ }\r
+\r
+ minimized = false;\r
+ iframeContainerDiv = containerElement.appendChild(document.createElement("div"));\r
+\r
+ iframeContainerDiv.style.width = width;\r
+ iframeContainerDiv.style.height = height;\r
+ iframeContainerDiv.style.border = "solid gray 1px";\r
+\r
+ for (var i = 0, len = cssProperties.length; i < len; i++) {\r
+ iframeContainerDiv.style[cssProperties[i][0]] = cssProperties[i][1];\r
+ }\r
+\r
+ var iframeSrc = useDocumentWrite ? "" : " src='" + getConsoleUrl() + "'";\r
+\r
+ // Adding an iframe using the DOM would be preferable, but it doesn't work\r
+ // in IE5 on Windows, or in Konqueror prior to version 3.5 - in Konqueror\r
+ // it creates the iframe fine but I haven't been able to find a way to obtain\r
+ // the iframe's window object\r
+ iframeContainerDiv.innerHTML = "<iframe id='" + iframeId + "' name='" + iframeId +\r
+ "' width='100%' height='100%' frameborder='0'" + iframeSrc +\r
+ " scrolling='no'></iframe>";\r
+ consoleClosed = false;\r
+\r
+ // Write the console HTML to the iframe\r
+ var iframeDocumentExistsTest = function(win) {\r
+ try {\r
+ return bool(win) && bool(win.document);\r
+ } catch (ex) {\r
+ return false;\r
+ }\r
+ };\r
+ if (iframeDocumentExistsTest(getConsoleWindow())) {\r
+ writeToDocument();\r
+ } else {\r
+ pollConsoleWindow(iframeDocumentExistsTest, 100, writeToDocument, initErrorMessage);\r
+ }\r
+ consoleWindowCreated = true;\r
+ };\r
+\r
+ createWindow = function(show) {\r
+ if (show || !initiallyMinimized) {\r
+ var pageLoadHandler = function() {\r
+ if (!container) {\r
+ // Set up default container element\r
+ containerElement = document.createElement("div");\r
+ containerElement.style.position = "fixed";\r
+ containerElement.style.left = "0";\r
+ containerElement.style.right = "0";\r
+ containerElement.style.bottom = "0";\r
+ document.body.appendChild(containerElement);\r
+ appender.addCssProperty("borderWidth", "1px 0 0 0");\r
+ appender.addCssProperty("zIndex", 1000000); // Can't find anything authoritative that says how big z-index can be\r
+ open();\r
+ } else {\r
+ try {\r
+ var el = document.getElementById(container);\r
+ if (el.nodeType == 1) {\r
+ containerElement = el;\r
+ }\r
+ open();\r
+ } catch (ex) {\r
+ handleError("InPageAppender.init: invalid container element '" + container + "' supplied", ex);\r
+ }\r
+ }\r
+ };\r
+\r
+ // Test the type of the container supplied. First, check if it's an element\r
+ if (pageLoaded && container && container.appendChild) {\r
+ containerElement = container;\r
+ open();\r
+ } else if (pageLoaded) {\r
+ pageLoadHandler();\r
+ } else {\r
+ log4javascript.addEventListener("load", pageLoadHandler);\r
+ }\r
+ windowCreationStarted = true;\r
+ }\r
+ };\r
+\r
+ init = function() {\r
+ createWindow();\r
+ initialized = true;\r
+ };\r
+\r
+ getConsoleWindow = function() {\r
+ var iframe = window.frames[iframeId];\r
+ if (iframe) {\r
+ return iframe;\r
+ }\r
+ };\r
+\r
+ safeToAppend = function() {\r
+ if (isSupported && !consoleClosed) {\r
+ if (consoleWindowCreated && !consoleWindowLoaded && getConsoleWindow() && isLoaded(getConsoleWindow())) {\r
+ consoleWindowLoaded = true;\r
+ }\r
+ return consoleWindowLoaded;\r
+ }\r
+ return false;\r
+ };\r
+ } else {\r
+ // PopUpAppender\r
+\r
+ // Extract params\r
+ var useOldPopUp = appender.defaults.useOldPopUp;\r
+ var complainAboutPopUpBlocking = appender.defaults.complainAboutPopUpBlocking;\r
+ var reopenWhenClosed = this.defaults.reopenWhenClosed;\r
+\r
+ // Configuration methods. The function scope is used to prevent\r
+ // direct alteration to the appender configuration properties.\r
+ this.isUseOldPopUp = function() { return useOldPopUp; };\r
+ this.setUseOldPopUp = function(useOldPopUpParam) {\r
+ if (checkCanConfigure("useOldPopUp")) {\r
+ useOldPopUp = bool(useOldPopUpParam);\r
+ }\r
+ };\r
+\r
+ this.isComplainAboutPopUpBlocking = function() { return complainAboutPopUpBlocking; };\r
+ this.setComplainAboutPopUpBlocking = function(complainAboutPopUpBlockingParam) {\r
+ if (checkCanConfigure("complainAboutPopUpBlocking")) {\r
+ complainAboutPopUpBlocking = bool(complainAboutPopUpBlockingParam);\r
+ }\r
+ };\r
+\r
+ this.isFocusPopUp = function() { return focusConsoleWindow; };\r
+ this.setFocusPopUp = function(focusPopUpParam) {\r
+ // This property can be safely altered after logging has started\r
+ focusConsoleWindow = bool(focusPopUpParam);\r
+ };\r
+\r
+ this.isReopenWhenClosed = function() { return reopenWhenClosed; };\r
+ this.setReopenWhenClosed = function(reopenWhenClosedParam) {\r
+ // This property can be safely altered after logging has started\r
+ reopenWhenClosed = bool(reopenWhenClosedParam);\r
+ };\r
+\r
+ this.close = function() {\r
+ logLog.debug("close " + this);\r
+ try {\r
+ popUp.close();\r
+ this.unload();\r
+ } catch (ex) {\r
+ // Do nothing\r
+ }\r
+ };\r
+\r
+ this.hide = function() {\r
+ logLog.debug("hide " + this);\r
+ if (consoleWindowExists()) {\r
+ this.close();\r
+ }\r
+ };\r
+\r
+ this.show = function() {\r
+ logLog.debug("show " + this);\r
+ if (!consoleWindowCreated) {\r
+ open();\r
+ }\r
+ };\r
+\r
+ this.isVisible = function() {\r
+ return safeToAppend();\r
+ };\r
+\r
+ // Define useful variables\r
+ var popUp;\r
+\r
+ // Create open, init, getConsoleWindow and safeToAppend functions\r
+ open = function() {\r
+ var windowProperties = "width=" + width + ",height=" + height + ",status,resizable";\r
+ var frameInfo = "";\r
+ try {\r
+ var frameEl = window.frameElement;\r
+ if (frameEl) {\r
+ frameInfo = "_" + frameEl.tagName + "_" + (frameEl.name || frameEl.id || "");\r
+ }\r
+ } catch (e) {\r
+ frameInfo = "_inaccessibleParentFrame";\r
+ }\r
+ var windowName = "PopUp_" + location.host.replace(/[^a-z0-9]/gi, "_") + "_" + consoleAppenderId + frameInfo;\r
+ if (!useOldPopUp || !useDocumentWrite) {\r
+ // Ensure a previous window isn't used by using a unique name\r
+ windowName = windowName + "_" + uniqueId;\r
+ }\r
+\r
+ var checkPopUpClosed = function(win) {\r
+ if (consoleClosed) {\r
+ return true;\r
+ } else {\r
+ try {\r
+ return bool(win) && win.closed;\r
+ } catch(ex) {}\r
+ }\r
+ return false;\r
+ };\r
+\r
+ var popUpClosedCallback = function() {\r
+ if (!consoleClosed) {\r
+ appender.unload();\r
+ }\r
+ };\r
+\r
+ function finalInit() {\r
+ getConsoleWindow().setCloseIfOpenerCloses(!useOldPopUp || !useDocumentWrite);\r
+ consoleWindowLoadHandler();\r
+ consoleWindowLoaded = true;\r
+ appendQueuedLoggingEvents();\r
+ pollConsoleWindow(checkPopUpClosed, 500, popUpClosedCallback,\r
+ "PopUpAppender.checkPopUpClosed: error checking pop-up window");\r
+ }\r
+\r
+ try {\r
+ popUp = window.open(getConsoleUrl(), windowName, windowProperties);\r
+ consoleClosed = false;\r
+ consoleWindowCreated = true;\r
+ if (popUp && popUp.document) {\r
+ if (useDocumentWrite && useOldPopUp && isLoaded(popUp)) {\r
+ popUp.mainPageReloaded();\r
+ finalInit();\r
+ } else {\r
+ if (useDocumentWrite) {\r
+ writeHtml(popUp.document);\r
+ }\r
+ // Check if the pop-up window object is available\r
+ var popUpLoadedTest = function(win) { return bool(win) && isLoaded(win); };\r
+ if (isLoaded(popUp)) {\r
+ finalInit();\r
+ } else {\r
+ pollConsoleWindow(popUpLoadedTest, 100, finalInit,\r
+ "PopUpAppender.init: unable to create console window");\r
+ }\r
+ }\r
+ } else {\r
+ isSupported = false;\r
+ logLog.warn("PopUpAppender.init: pop-ups blocked, please unblock to use PopUpAppender");\r
+ if (complainAboutPopUpBlocking) {\r
+ handleError("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");\r
+ }\r
+ }\r
+ } catch (ex) {\r
+ handleError("PopUpAppender.init: error creating pop-up", ex);\r
+ }\r
+ };\r
+\r
+ createWindow = function() {\r
+ if (!initiallyMinimized) {\r
+ open();\r
+ }\r
+ };\r
+\r
+ init = function() {\r
+ createWindow();\r
+ initialized = true;\r
+ };\r
+\r
+ getConsoleWindow = function() {\r
+ return popUp;\r
+ };\r
+\r
+ safeToAppend = function() {\r
+ if (isSupported && !isUndefined(popUp) && !consoleClosed) {\r
+ if (popUp.closed ||\r
+ (consoleWindowLoaded && isUndefined(popUp.closed))) { // Extra check for Opera\r
+ appender.unload();\r
+ logLog.debug("PopUpAppender: pop-up closed");\r
+ return false;\r
+ }\r
+ if (!consoleWindowLoaded && isLoaded(popUp)) {\r
+ consoleWindowLoaded = true;\r
+ }\r
+ }\r
+ return isSupported && consoleWindowLoaded && !consoleClosed;\r
+ };\r
+ }\r
+\r
+ // Expose getConsoleWindow so that automated tests can check the DOM\r
+ this.getConsoleWindow = getConsoleWindow;\r
+ };\r
+\r
+ ConsoleAppender.addGlobalCommandLineFunction = function(functionName, commandLineFunction) {\r
+ defaultCommandLineFunctions.push([functionName, commandLineFunction]);\r
+ };\r
+\r
+ /* ------------------------------------------------------------------ */\r
+\r
+ function PopUpAppender(lazyInit, initiallyMinimized, useDocumentWrite,\r
+ width, height) {\r
+ this.create(false, null, lazyInit, initiallyMinimized,\r
+ useDocumentWrite, width, height, this.defaults.focusPopUp);\r
+ }\r
+\r
+ PopUpAppender.prototype = new ConsoleAppender();\r
+\r
+ PopUpAppender.prototype.defaults = {\r
+ layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),\r
+ initiallyMinimized: false,\r
+ focusPopUp: false,\r
+ lazyInit: true,\r
+ useOldPopUp: true,\r
+ complainAboutPopUpBlocking: true,\r
+ newestMessageAtTop: false,\r
+ scrollToLatestMessage: true,\r
+ width: "600",\r
+ height: "400",\r
+ reopenWhenClosed: false,\r
+ maxMessages: null,\r
+ showCommandLine: true,\r
+ commandLineObjectExpansionDepth: 1,\r
+ showHideButton: false,\r
+ showCloseButton: true,\r
+ showLogEntryDeleteButtons: true,\r
+ useDocumentWrite: true\r
+ };\r
+\r
+ PopUpAppender.prototype.toString = function() {\r
+ return "PopUpAppender";\r
+ };\r
+\r
+ log4javascript.PopUpAppender = PopUpAppender;\r
+\r
+ /* ------------------------------------------------------------------ */\r
+\r
+ function InPageAppender(container, lazyInit, initiallyMinimized,\r
+ useDocumentWrite, width, height) {\r
+ this.create(true, container, lazyInit, initiallyMinimized,\r
+ useDocumentWrite, width, height, false);\r
+ }\r
+\r
+ InPageAppender.prototype = new ConsoleAppender();\r
+\r
+ InPageAppender.prototype.defaults = {\r
+ layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),\r
+ initiallyMinimized: false,\r
+ lazyInit: true,\r
+ newestMessageAtTop: false,\r
+ scrollToLatestMessage: true,\r
+ width: "100%",\r
+ height: "220px",\r
+ maxMessages: null,\r
+ showCommandLine: true,\r
+ commandLineObjectExpansionDepth: 1,\r
+ showHideButton: false,\r
+ showCloseButton: false,\r
+ showLogEntryDeleteButtons: true,\r
+ useDocumentWrite: true\r
+ };\r
+\r
+ InPageAppender.prototype.toString = function() {\r
+ return "InPageAppender";\r
+ };\r
+\r
+ log4javascript.InPageAppender = InPageAppender;\r
+\r
+ // Next line for backwards compatibility\r
+ log4javascript.InlineAppender = InPageAppender;\r
+ })();\r
+ /* ---------------------------------------------------------------------- */\r
+ // Console extension functions\r
+\r
+ function padWithSpaces(str, len) {\r
+ if (str.length < len) {\r
+ var spaces = [];\r
+ var numberOfSpaces = Math.max(0, len - str.length);\r
+ for (var i = 0; i < numberOfSpaces; i++) {\r
+ spaces[i] = " ";\r
+ }\r
+ str += spaces.join("");\r
+ }\r
+ return str;\r
+ }\r
+\r
+ (function() {\r
+ function dir(obj) {\r
+ var maxLen = 0;\r
+ // Obtain the length of the longest property name\r
+ for (var p in obj) {\r
+ maxLen = Math.max(toStr(p).length, maxLen);\r
+ }\r
+ // Create the nicely formatted property list\r
+ var propList = [];\r
+ for (p in obj) {\r
+ var propNameStr = " " + padWithSpaces(toStr(p), maxLen + 2);\r
+ var propVal;\r
+ try {\r
+ propVal = splitIntoLines(toStr(obj[p])).join(padWithSpaces(newLine, maxLen + 6));\r
+ } catch (ex) {\r
+ propVal = "[Error obtaining property. Details: " + getExceptionMessage(ex) + "]";\r
+ }\r
+ propList.push(propNameStr + propVal);\r
+ }\r
+ return propList.join(newLine);\r
+ }\r
+\r
+ var nodeTypes = {\r
+ ELEMENT_NODE: 1,\r
+ ATTRIBUTE_NODE: 2,\r
+ TEXT_NODE: 3,\r
+ CDATA_SECTION_NODE: 4,\r
+ ENTITY_REFERENCE_NODE: 5,\r
+ ENTITY_NODE: 6,\r
+ PROCESSING_INSTRUCTION_NODE: 7,\r
+ COMMENT_NODE: 8,\r
+ DOCUMENT_NODE: 9,\r
+ DOCUMENT_TYPE_NODE: 10,\r
+ DOCUMENT_FRAGMENT_NODE: 11,\r
+ NOTATION_NODE: 12\r
+ };\r
+\r
+ var preFormattedElements = ["script", "pre"];\r
+\r
+ // This should be the definitive list, as specified by the XHTML 1.0 Transitional DTD\r
+ var emptyElements = ["br", "img", "hr", "param", "link", "area", "input", "col", "base", "meta"];\r
+ var indentationUnit = " ";\r
+\r
+ // Create and return an XHTML string from the node specified\r
+ function getXhtml(rootNode, includeRootNode, indentation, startNewLine, preformatted) {\r
+ includeRootNode = (typeof includeRootNode == "undefined") ? true : !!includeRootNode;\r
+ if (typeof indentation != "string") {\r
+ indentation = "";\r
+ }\r
+ startNewLine = !!startNewLine;\r
+ preformatted = !!preformatted;\r
+ var xhtml;\r
+\r
+ function isWhitespace(node) {\r
+ return ((node.nodeType == nodeTypes.TEXT_NODE) && /^[ \t\r\n]*$/.test(node.nodeValue));\r
+ }\r
+\r
+ function fixAttributeValue(attrValue) {\r
+ return attrValue.toString().replace(/&/g, "&").replace(/</g, "<").replace(/"/g, """);\r
+ }\r
+\r
+ function getStyleAttributeValue(el) {\r
+ var stylePairs = el.style.cssText.split(";");\r
+ var styleValue = "";\r
+ var isFirst = true;\r
+ for (var j = 0, len = stylePairs.length; j < len; j++) {\r
+ var nameValueBits = stylePairs[j].split(":");\r
+ var props = [];\r
+ if (!/^\s*$/.test(nameValueBits[0])) {\r
+ props.push(trim(nameValueBits[0]).toLowerCase() + ":" + trim(nameValueBits[1]));\r
+ }\r
+ styleValue = props.join(";");\r
+ }\r
+ return styleValue;\r
+ }\r
+\r
+ function getNamespace(el) {\r
+ if (el.prefix) {\r
+ return el.prefix;\r
+ } else if (el.outerHTML) {\r
+ var regex = new RegExp("<([^:]+):" + el.tagName + "[^>]*>", "i");\r
+ if (regex.test(el.outerHTML)) {\r
+ return RegExp.$1.toLowerCase();\r
+ }\r
+ }\r
+ return "";\r
+ }\r
+\r
+ var lt = "<";\r
+ var gt = ">";\r
+\r
+ if (includeRootNode && rootNode.nodeType != nodeTypes.DOCUMENT_FRAGMENT_NODE) {\r
+ switch (rootNode.nodeType) {\r
+ case nodeTypes.ELEMENT_NODE:\r
+ var tagName = rootNode.tagName.toLowerCase();\r
+ xhtml = startNewLine ? newLine + indentation : "";\r
+ xhtml += lt;\r
+ // Allow for namespaces, where present\r
+ var prefix = getNamespace(rootNode);\r
+ var hasPrefix = !!prefix;\r
+ if (hasPrefix) {\r
+ xhtml += prefix + ":";\r
+ }\r
+ xhtml += tagName;\r
+ for (i = 0, len = rootNode.attributes.length; i < len; i++) {\r
+ var currentAttr = rootNode.attributes[i];\r
+ // Check the attribute is valid.\r
+ if (! currentAttr.specified ||\r
+ currentAttr.nodeValue === null ||\r
+ currentAttr.nodeName.toLowerCase() === "style" ||\r
+ typeof currentAttr.nodeValue !== "string" ||\r
+ currentAttr.nodeName.indexOf("_moz") === 0) {\r
+ continue;\r
+ }\r
+ xhtml += " " + currentAttr.nodeName.toLowerCase() + "=\"";\r
+ xhtml += fixAttributeValue(currentAttr.nodeValue);\r
+ xhtml += "\"";\r
+ }\r
+ // Style needs to be done separately as it is not reported as an\r
+ // attribute in IE\r
+ if (rootNode.style.cssText) {\r
+ var styleValue = getStyleAttributeValue(rootNode);\r
+ if (styleValue !== "") {\r
+ xhtml += " style=\"" + getStyleAttributeValue(rootNode) + "\"";\r
+ }\r
+ }\r
+ if (array_contains(emptyElements, tagName) ||\r
+ (hasPrefix && !rootNode.hasChildNodes())) {\r
+ xhtml += "/" + gt;\r
+ } else {\r
+ xhtml += gt;\r
+ // Add output for childNodes collection (which doesn't include attribute nodes)\r
+ var childStartNewLine = !(rootNode.childNodes.length === 1 &&\r
+ rootNode.childNodes[0].nodeType === nodeTypes.TEXT_NODE);\r
+ var childPreformatted = array_contains(preFormattedElements, tagName);\r
+ for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {\r
+ xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit,\r
+ childStartNewLine, childPreformatted);\r
+ }\r
+ // Add the end tag\r
+ var endTag = lt + "/" + tagName + gt;\r
+ xhtml += childStartNewLine ? newLine + indentation + endTag : endTag;\r
+ }\r
+ return xhtml;\r
+ case nodeTypes.TEXT_NODE:\r
+ if (isWhitespace(rootNode)) {\r
+ xhtml = "";\r
+ } else {\r
+ if (preformatted) {\r
+ xhtml = rootNode.nodeValue;\r
+ } else {\r
+ // Trim whitespace from each line of the text node\r
+ var lines = splitIntoLines(trim(rootNode.nodeValue));\r
+ var trimmedLines = [];\r
+ for (var i = 0, len = lines.length; i < len; i++) {\r
+ trimmedLines[i] = trim(lines[i]);\r
+ }\r
+ xhtml = trimmedLines.join(newLine + indentation);\r
+ }\r
+ if (startNewLine) {\r
+ xhtml = newLine + indentation + xhtml;\r
+ }\r
+ }\r
+ return xhtml;\r
+ case nodeTypes.CDATA_SECTION_NODE:\r
+ return "<![CDA" + "TA[" + rootNode.nodeValue + "]" + "]>" + newLine;\r
+ case nodeTypes.DOCUMENT_NODE:\r
+ xhtml = "";\r
+ // Add output for childNodes collection (which doesn't include attribute nodes)\r
+ for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {\r
+ xhtml += getXhtml(rootNode.childNodes[i], true, indentation);\r
+ }\r
+ return xhtml;\r
+ default:\r
+ return "";\r
+ }\r
+ } else {\r
+ xhtml = "";\r
+ // Add output for childNodes collection (which doesn't include attribute nodes)\r
+ for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {\r
+ xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit);\r
+ }\r
+ return xhtml;\r
+ }\r
+ }\r
+\r
+ function createCommandLineFunctions() {\r
+ ConsoleAppender.addGlobalCommandLineFunction("$", function(appender, args, returnValue) {\r
+ return document.getElementById(args[0]);\r
+ });\r
+\r
+ ConsoleAppender.addGlobalCommandLineFunction("dir", function(appender, args, returnValue) {\r
+ var lines = [];\r
+ for (var i = 0, len = args.length; i < len; i++) {\r
+ lines[i] = dir(args[i]);\r
+ }\r
+ return lines.join(newLine + newLine);\r
+ });\r
+\r
+ ConsoleAppender.addGlobalCommandLineFunction("dirxml", function(appender, args, returnValue) {\r
+ var lines = [];\r
+ for (var i = 0, len = args.length; i < len; i++) {\r
+ var win = appender.getCommandWindow();\r
+ lines[i] = getXhtml(args[i]);\r
+ }\r
+ return lines.join(newLine + newLine);\r
+ });\r
+\r
+ ConsoleAppender.addGlobalCommandLineFunction("cd", function(appender, args, returnValue) {\r
+ var win, message;\r
+ if (args.length === 0 || args[0] === "") {\r
+ win = window;\r
+ message = "Command line set to run in main window";\r
+ } else {\r
+ if (args[0].window == args[0]) {\r
+ win = args[0];\r
+ message = "Command line set to run in frame '" + args[0].name + "'";\r
+ } else {\r
+ win = window.frames[args[0]];\r
+ if (win) {\r
+ message = "Command line set to run in frame '" + args[0] + "'";\r
+ } else {\r
+ returnValue.isError = true;\r
+ message = "Frame '" + args[0] + "' does not exist";\r
+ win = appender.getCommandWindow();\r
+ }\r
+ }\r
+ }\r
+ appender.setCommandWindow(win);\r
+ return message;\r
+ });\r
+\r
+ ConsoleAppender.addGlobalCommandLineFunction("clear", function(appender, args, returnValue) {\r
+ returnValue.appendResult = false;\r
+ appender.clear();\r
+ });\r
+\r
+ ConsoleAppender.addGlobalCommandLineFunction("keys", function(appender, args, returnValue) {\r
+ var keys = [];\r
+ for (var k in args[0]) {\r
+ keys.push(k);\r
+ }\r
+ return keys;\r
+ });\r
+\r
+ ConsoleAppender.addGlobalCommandLineFunction("values", function(appender, args, returnValue) {\r
+ var values = [];\r
+ for (var k in args[0]) {\r
+ try {\r
+ values.push(args[0][k]);\r
+ } catch (ex) {\r
+ logLog.warn("values(): Unable to obtain value for key " + k + ". Details: " + getExceptionMessage(ex));\r
+ }\r
+ }\r
+ return values;\r
+ });\r
+\r
+ ConsoleAppender.addGlobalCommandLineFunction("expansionDepth", function(appender, args, returnValue) {\r
+ var expansionDepth = parseInt(args[0], 10);\r
+ if (isNaN(expansionDepth) || expansionDepth < 0) {\r
+ returnValue.isError = true;\r
+ return "" + args[0] + " is not a valid expansion depth";\r
+ } else {\r
+ appender.setCommandLineObjectExpansionDepth(expansionDepth);\r
+ return "Object expansion depth set to " + expansionDepth;\r
+ }\r
+ });\r
+ }\r
+\r
+ function init() {\r
+ // Add command line functions\r
+ createCommandLineFunctions();\r
+ }\r
+\r
+ /* ------------------------------------------------------------------ */\r
+\r
+ init();\r
+ })();\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Main load\r
+\r
+ log4javascript.setDocumentReady = function() {\r
+ pageLoaded = true;\r
+ log4javascript.dispatchEvent("load", {});\r
+ };\r
+\r
+ if (window.addEventListener) {\r
+ window.addEventListener("load", log4javascript.setDocumentReady, false);\r
+ } else if (window.attachEvent) {\r
+ window.attachEvent("onload", log4javascript.setDocumentReady);\r
+ } else {\r
+ var oldOnload = window.onload;\r
+ if (typeof window.onload != "function") {\r
+ window.onload = log4javascript.setDocumentReady;\r
+ } else {\r
+ window.onload = function(evt) {\r
+ if (oldOnload) {\r
+ oldOnload(evt);\r
+ }\r
+ log4javascript.setDocumentReady();\r
+ };\r
+ }\r
+ }\r
+\r
+ // Ensure that the log4javascript object is available in the window. This\r
+ // is necessary for log4javascript to be available in IE if loaded using\r
+ // Dojo's module system\r
+ window.log4javascript = log4javascript;\r
+\r
+ return log4javascript;\r
+})();
\ No newline at end of file
--- /dev/null
+/**\r
+ * Copyright 2013 Tim Down.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+\r
+var log4javascript_stub=(function(){var log4javascript;function ff(){return function(){};}\r
+function copy(obj,props){for(var i in props){obj[i]=props[i];}}\r
+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(){}\r
+copy(EventSupport.prototype,{setEventTypes:f,addEventListener:f,removeEventListener:f,dispatchEvent:f,eventTypes:[],eventListeners:{}});function Log4JavaScript(){}\r
+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(){}\r
+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;}\r
--- /dev/null
+/**\r
+ * Copyright 2013 Tim Down.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+\r
+var log4javascript_stub=(function(){var log4javascript;function ff(){return function(){};}\r
+function copy(obj,props){for(var i in props){obj[i]=props[i];}}\r
+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(){}\r
+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;}\r
--- /dev/null
+/**\r
+ * Copyright 2013 Tim Down.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+var log4javascript_stub = (function() {\r
+ var log4javascript;\r
+\r
+ function ff() {\r
+ return function() {};\r
+ }\r
+ function copy(obj, props) {\r
+ for (var i in props) {\r
+ obj[i] = props[i];\r
+ }\r
+ }\r
+ var f = ff();\r
+\r
+ // Loggers\r
+ var Logger = ff();\r
+ copy(Logger.prototype, {\r
+ setLevel: f,\r
+ getLevel: f,\r
+ trace: f,\r
+ debug: f,\r
+ info: f,\r
+ warn: f,\r
+ error: f,\r
+ fatal: f,\r
+ isEnabledFor: f,\r
+ isTraceEnabled: f,\r
+ isDebugEnabled: f,\r
+ isInfoEnabled: f,\r
+ isWarnEnabled: f,\r
+ isErrorEnabled: f,\r
+ isFatalEnabled: f\r
+ });\r
+\r
+ var getLogger = function() {\r
+ return new Logger();\r
+ };\r
+\r
+ function Log4JavaScript() {}\r
+ log4javascript = new Log4JavaScript();\r
+\r
+ log4javascript = {\r
+ isStub: true,\r
+ version: "1.4.6",\r
+ edition: "log4javascript_lite",\r
+ setEnabled: f,\r
+ isEnabled: f,\r
+ setShowStackTraces: f,\r
+ getDefaultLogger: getLogger,\r
+ getLogger: getLogger,\r
+ getNullLogger: getLogger,\r
+ Level: ff(),\r
+ LoggingEvent: ff(),\r
+ Appender: ff()\r
+ };\r
+\r
+ // LoggingEvents\r
+ log4javascript.LoggingEvent.prototype = {\r
+ getThrowableStrRep: f,\r
+ getCombinedMessages: f\r
+ };\r
+\r
+ // Levels\r
+ log4javascript.Level.prototype = {\r
+ toString: f,\r
+ equals: f,\r
+ isGreaterOrEqual: f\r
+ };\r
+ var level = new log4javascript.Level();\r
+ copy(log4javascript.Level, {\r
+ ALL: level,\r
+ TRACE: level,\r
+ DEBUG: level,\r
+ INFO: level,\r
+ WARN: level,\r
+ ERROR: level,\r
+ FATAL: level,\r
+ OFF: level\r
+ });\r
+ \r
+ log4javascript.Appender.prototype.append = f;\r
+\r
+ return log4javascript;\r
+})();\r
+if (typeof window.log4javascript == "undefined") {\r
+ var log4javascript = log4javascript_stub;\r
+}\r
--- /dev/null
+/**\r
+ * Copyright 2013 Tim Down.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+\r
+var log4javascript_stub=(function(){var log4javascript;function ff(){return function(){};}\r
+function copy(obj,props){for(var i in props){obj[i]=props[i];}}\r
+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(){}\r
+copy(EventSupport.prototype,{setEventTypes:f,addEventListener:f,removeEventListener:f,dispatchEvent:f,eventTypes:[],eventListeners:{}});function Log4JavaScript(){}\r
+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;}\r
--- /dev/null
+/**\r
+ * Copyright 2013 Tim Down.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+var log4javascript_stub = (function() {\r
+ var log4javascript;\r
+\r
+ function ff() {\r
+ return function() {};\r
+ }\r
+ function copy(obj, props) {\r
+ for (var i in props) {\r
+ obj[i] = props[i];\r
+ }\r
+ }\r
+ var f = ff();\r
+\r
+ // Loggers\r
+ var Logger = ff();\r
+ copy(Logger.prototype, {\r
+ addChild: f,\r
+ getEffectiveAppenders: f,\r
+ invalidateAppenderCache: f,\r
+ getAdditivity: f,\r
+ setAdditivity: f,\r
+ addAppender: f,\r
+ removeAppender: f,\r
+ removeAllAppenders: f,\r
+ log: f,\r
+ setLevel: f,\r
+ getLevel: f,\r
+ getEffectiveLevel: f,\r
+ trace: f,\r
+ debug: f,\r
+ info: f,\r
+ warn: f,\r
+ error: f,\r
+ fatal: f,\r
+ isEnabledFor: f,\r
+ isTraceEnabled: f,\r
+ isDebugEnabled: f,\r
+ isInfoEnabled: f,\r
+ isWarnEnabled: f,\r
+ isErrorEnabled: f,\r
+ isFatalEnabled: f,\r
+ callAppenders: f,\r
+ group: f,\r
+ groupEnd: f,\r
+ time: f,\r
+ timeEnd: f,\r
+ assert: f,\r
+ parent: new Logger()\r
+ });\r
+\r
+ var getLogger = function() {\r
+ return new Logger();\r
+ };\r
+\r
+ function EventSupport() {}\r
+\r
+ copy(EventSupport.prototype, {\r
+ setEventTypes: f,\r
+ addEventListener: f,\r
+ removeEventListener: f,\r
+ dispatchEvent: f,\r
+ eventTypes: [],\r
+ eventListeners: {}\r
+ });\r
+\r
+ function Log4JavaScript() {}\r
+ Log4JavaScript.prototype = new EventSupport();\r
+ log4javascript = new Log4JavaScript();\r
+\r
+ log4javascript = {\r
+ isStub: true,\r
+ version: "1.4.6",\r
+ edition: "log4javascript_production",\r
+ setDocumentReady: f,\r
+ setEventTypes: f,\r
+ addEventListener: f,\r
+ removeEventListener: f,\r
+ dispatchEvent: f,\r
+ eventTypes: [],\r
+ eventListeners: {},\r
+ logLog: {\r
+ setQuietMode: f,\r
+ setAlertAllErrors: f,\r
+ debug: f,\r
+ displayDebug: f,\r
+ warn: f,\r
+ error: f\r
+ },\r
+ handleError: f,\r
+ setEnabled: f,\r
+ isEnabled: f,\r
+ setTimeStampsInMilliseconds: f,\r
+ isTimeStampsInMilliseconds: f,\r
+ evalInScope: f,\r
+ setShowStackTraces: f,\r
+ getLogger: getLogger,\r
+ getDefaultLogger: getLogger,\r
+ getNullLogger: getLogger,\r
+ getRootLogger: getLogger,\r
+ resetConfiguration: f,\r
+ Level: ff(),\r
+ LoggingEvent: ff(),\r
+ Layout: ff(),\r
+ Appender: ff()\r
+ };\r
+\r
+ // LoggingEvents\r
+ log4javascript.LoggingEvent.prototype = {\r
+ getThrowableStrRep: f,\r
+ getCombinedMessages: f\r
+ };\r
+\r
+ // Levels\r
+ log4javascript.Level.prototype = {\r
+ toString: f,\r
+ equals: f,\r
+ isGreaterOrEqual: f\r
+ };\r
+ var level = new log4javascript.Level();\r
+ copy(log4javascript.Level, {\r
+ ALL: level,\r
+ TRACE: level,\r
+ DEBUG: level,\r
+ INFO: level,\r
+ WARN: level,\r
+ ERROR: level,\r
+ FATAL: level,\r
+ OFF: level\r
+ });\r
+\r
+ // Layouts\r
+ log4javascript.Layout.prototype = {\r
+ defaults: {},\r
+ format: f,\r
+ ignoresThrowable: f,\r
+ getContentType: f,\r
+ allowBatching: f,\r
+ getDataValues: f,\r
+ setKeys: f,\r
+ setCustomField: f,\r
+ hasCustomFields: f,\r
+ setTimeStampsInMilliseconds: f,\r
+ isTimeStampsInMilliseconds: f,\r
+ getTimeStampValue: f,\r
+ toString: f\r
+ };\r
+\r
+ // PatternLayout related\r
+ log4javascript.SimpleDateFormat = ff();\r
+ log4javascript.SimpleDateFormat.prototype = {\r
+ setMinimalDaysInFirstWeek: f,\r
+ getMinimalDaysInFirstWeek: f,\r
+ format: f\r
+ };\r
+\r
+ // PatternLayout\r
+ log4javascript.PatternLayout = ff();\r
+ log4javascript.PatternLayout.prototype = new log4javascript.Layout();\r
+\r
+ // Appenders\r
+ log4javascript.Appender = ff();\r
+ log4javascript.Appender.prototype = new EventSupport();\r
+\r
+ copy(log4javascript.Appender.prototype, {\r
+ layout: new log4javascript.PatternLayout(),\r
+ threshold: log4javascript.Level.ALL,\r
+ loggers: [],\r
+ doAppend: f,\r
+ append: f,\r
+ setLayout: f,\r
+ getLayout: f,\r
+ setThreshold: f,\r
+ getThreshold: f,\r
+ setAddedToLogger: f,\r
+ setRemovedFromLogger: f,\r
+ group: f,\r
+ groupEnd: f,\r
+ toString: f\r
+ });\r
+ // SimpleLayout\r
+ log4javascript.SimpleLayout = ff();\r
+ log4javascript.SimpleLayout.prototype = new log4javascript.Layout();\r
+ // NullLayout\r
+ log4javascript.NullLayout = ff();\r
+ log4javascript.NullLayout.prototype = new log4javascript.Layout();\r
+ // ZmlLayout\r
+ log4javascript.XmlLayout = ff();\r
+ log4javascript.XmlLayout.prototype = new log4javascript.Layout();\r
+ copy(log4javascript.XmlLayout.prototype, {\r
+ escapeCdata: f,\r
+ isCombinedMessages: f\r
+ });\r
+ // JsonLayout\r
+ log4javascript.JsonLayout = ff();\r
+ log4javascript.JsonLayout.prototype = new log4javascript.Layout();\r
+ copy(log4javascript.JsonLayout.prototype, {\r
+ isReadable: f,\r
+ isCombinedMessages: f\r
+ });\r
+ // HttpPostDataLayout \r
+ log4javascript.HttpPostDataLayout = ff();\r
+ log4javascript.HttpPostDataLayout.prototype = new log4javascript.Layout();\r
+ // PatternLayout\r
+ log4javascript.PatternLayout = ff();\r
+ log4javascript.PatternLayout.prototype = new log4javascript.Layout();\r
+ // AjaxAppender\r
+ log4javascript.AjaxAppender = ff();\r
+ log4javascript.AjaxAppender.prototype = new log4javascript.Appender();\r
+ copy(log4javascript.AjaxAppender.prototype, {\r
+ getSessionId: f,\r
+ setSessionId: f,\r
+ isTimed: f,\r
+ setTimed: f,\r
+ getTimerInterval: f,\r
+ setTimerInterval: f,\r
+ isWaitForResponse: f,\r
+ setWaitForResponse: f,\r
+ getBatchSize: f,\r
+ setBatchSize: f,\r
+ isSendAllOnUnload: f,\r
+ setSendAllOnUnload: f,\r
+ setRequestSuccessCallback: f,\r
+ setFailCallback: f,\r
+ getPostVarName: f,\r
+ setPostVarName: f,\r
+ sendAll: f,\r
+ sendAllRemaining: f,\r
+ defaults: {\r
+ requestSuccessCallback: null,\r
+ failCallback: null\r
+ }\r
+ });\r
+ return log4javascript;\r
+})();\r
+if (typeof window.log4javascript == "undefined") {\r
+ var log4javascript = log4javascript_stub;\r
+}\r
--- /dev/null
+/**\r
+ * Copyright 2013 Tim Down.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+var log4javascript_stub = (function() {\r
+ var log4javascript;\r
+\r
+ function ff() {\r
+ return function() {};\r
+ }\r
+ function copy(obj, props) {\r
+ for (var i in props) {\r
+ obj[i] = props[i];\r
+ }\r
+ }\r
+ var f = ff();\r
+\r
+ // Loggers\r
+ var Logger = ff();\r
+ copy(Logger.prototype, {\r
+ addChild: f,\r
+ getEffectiveAppenders: f,\r
+ invalidateAppenderCache: f,\r
+ getAdditivity: f,\r
+ setAdditivity: f,\r
+ addAppender: f,\r
+ removeAppender: f,\r
+ removeAllAppenders: f,\r
+ log: f,\r
+ setLevel: f,\r
+ getLevel: f,\r
+ getEffectiveLevel: f,\r
+ trace: f,\r
+ debug: f,\r
+ info: f,\r
+ warn: f,\r
+ error: f,\r
+ fatal: f,\r
+ isEnabledFor: f,\r
+ isTraceEnabled: f,\r
+ isDebugEnabled: f,\r
+ isInfoEnabled: f,\r
+ isWarnEnabled: f,\r
+ isErrorEnabled: f,\r
+ isFatalEnabled: f,\r
+ callAppenders: f,\r
+ group: f,\r
+ groupEnd: f,\r
+ time: f,\r
+ timeEnd: f,\r
+ assert: f,\r
+ parent: new Logger()\r
+ });\r
+\r
+ var getLogger = function() {\r
+ return new Logger();\r
+ };\r
+\r
+ function EventSupport() {}\r
+\r
+ copy(EventSupport.prototype, {\r
+ setEventTypes: f,\r
+ addEventListener: f,\r
+ removeEventListener: f,\r
+ dispatchEvent: f,\r
+ eventTypes: [],\r
+ eventListeners: {}\r
+ });\r
+\r
+ function Log4JavaScript() {}\r
+ Log4JavaScript.prototype = new EventSupport();\r
+ log4javascript = new Log4JavaScript();\r
+\r
+ log4javascript = {\r
+ isStub: true,\r
+ version: "1.4.6",\r
+ edition: "log4javascript",\r
+ setDocumentReady: f,\r
+ setEventTypes: f,\r
+ addEventListener: f,\r
+ removeEventListener: f,\r
+ dispatchEvent: f,\r
+ eventTypes: [],\r
+ eventListeners: {},\r
+ logLog: {\r
+ setQuietMode: f,\r
+ setAlertAllErrors: f,\r
+ debug: f,\r
+ displayDebug: f,\r
+ warn: f,\r
+ error: f\r
+ },\r
+ handleError: f,\r
+ setEnabled: f,\r
+ isEnabled: f,\r
+ setTimeStampsInMilliseconds: f,\r
+ isTimeStampsInMilliseconds: f,\r
+ evalInScope: f,\r
+ setShowStackTraces: f,\r
+ getLogger: getLogger,\r
+ getDefaultLogger: getLogger,\r
+ getNullLogger: getLogger,\r
+ getRootLogger: getLogger,\r
+ resetConfiguration: f,\r
+ Level: ff(),\r
+ LoggingEvent: ff(),\r
+ Layout: ff(),\r
+ Appender: ff()\r
+ };\r
+\r
+ // LoggingEvents\r
+ log4javascript.LoggingEvent.prototype = {\r
+ getThrowableStrRep: f,\r
+ getCombinedMessages: f\r
+ };\r
+\r
+ // Levels\r
+ log4javascript.Level.prototype = {\r
+ toString: f,\r
+ equals: f,\r
+ isGreaterOrEqual: f\r
+ };\r
+ var level = new log4javascript.Level();\r
+ copy(log4javascript.Level, {\r
+ ALL: level,\r
+ TRACE: level,\r
+ DEBUG: level,\r
+ INFO: level,\r
+ WARN: level,\r
+ ERROR: level,\r
+ FATAL: level,\r
+ OFF: level\r
+ });\r
+\r
+ // Layouts\r
+ log4javascript.Layout.prototype = {\r
+ defaults: {},\r
+ format: f,\r
+ ignoresThrowable: f,\r
+ getContentType: f,\r
+ allowBatching: f,\r
+ getDataValues: f,\r
+ setKeys: f,\r
+ setCustomField: f,\r
+ hasCustomFields: f,\r
+ setTimeStampsInMilliseconds: f,\r
+ isTimeStampsInMilliseconds: f,\r
+ getTimeStampValue: f,\r
+ toString: f\r
+ };\r
+\r
+ // PatternLayout related\r
+ log4javascript.SimpleDateFormat = ff();\r
+ log4javascript.SimpleDateFormat.prototype = {\r
+ setMinimalDaysInFirstWeek: f,\r
+ getMinimalDaysInFirstWeek: f,\r
+ format: f\r
+ };\r
+\r
+ // PatternLayout\r
+ log4javascript.PatternLayout = ff();\r
+ log4javascript.PatternLayout.prototype = new log4javascript.Layout();\r
+\r
+ // Appenders\r
+ log4javascript.Appender = ff();\r
+ log4javascript.Appender.prototype = new EventSupport();\r
+\r
+ copy(log4javascript.Appender.prototype, {\r
+ layout: new log4javascript.PatternLayout(),\r
+ threshold: log4javascript.Level.ALL,\r
+ loggers: [],\r
+ doAppend: f,\r
+ append: f,\r
+ setLayout: f,\r
+ getLayout: f,\r
+ setThreshold: f,\r
+ getThreshold: f,\r
+ setAddedToLogger: f,\r
+ setRemovedFromLogger: f,\r
+ group: f,\r
+ groupEnd: f,\r
+ toString: f\r
+ });\r
+ // SimpleLayout\r
+ log4javascript.SimpleLayout = ff();\r
+ log4javascript.SimpleLayout.prototype = new log4javascript.Layout();\r
+ // NullLayout\r
+ log4javascript.NullLayout = ff();\r
+ log4javascript.NullLayout.prototype = new log4javascript.Layout();\r
+ // ZmlLayout\r
+ log4javascript.XmlLayout = ff();\r
+ log4javascript.XmlLayout.prototype = new log4javascript.Layout();\r
+ copy(log4javascript.XmlLayout.prototype, {\r
+ escapeCdata: f,\r
+ isCombinedMessages: f\r
+ });\r
+ // JsonLayout\r
+ log4javascript.JsonLayout = ff();\r
+ log4javascript.JsonLayout.prototype = new log4javascript.Layout();\r
+ copy(log4javascript.JsonLayout.prototype, {\r
+ isReadable: f,\r
+ isCombinedMessages: f\r
+ });\r
+ // HttpPostDataLayout \r
+ log4javascript.HttpPostDataLayout = ff();\r
+ log4javascript.HttpPostDataLayout.prototype = new log4javascript.Layout();\r
+ // PatternLayout\r
+ log4javascript.PatternLayout = ff();\r
+ log4javascript.PatternLayout.prototype = new log4javascript.Layout();\r
+ // AlertAppender\r
+ log4javascript.AlertAppender = ff();\r
+ log4javascript.AlertAppender.prototype = new log4javascript.Appender();\r
+ // BrowserConsoleAppender\r
+ log4javascript.BrowserConsoleAppender = ff();\r
+ log4javascript.BrowserConsoleAppender.prototype = new log4javascript.Appender();\r
+ // AjaxAppender\r
+ log4javascript.AjaxAppender = ff();\r
+ log4javascript.AjaxAppender.prototype = new log4javascript.Appender();\r
+ copy(log4javascript.AjaxAppender.prototype, {\r
+ getSessionId: f,\r
+ setSessionId: f,\r
+ isTimed: f,\r
+ setTimed: f,\r
+ getTimerInterval: f,\r
+ setTimerInterval: f,\r
+ isWaitForResponse: f,\r
+ setWaitForResponse: f,\r
+ getBatchSize: f,\r
+ setBatchSize: f,\r
+ isSendAllOnUnload: f,\r
+ setSendAllOnUnload: f,\r
+ setRequestSuccessCallback: f,\r
+ setFailCallback: f,\r
+ getPostVarName: f,\r
+ setPostVarName: f,\r
+ sendAll: f,\r
+ sendAllRemaining: f,\r
+ defaults: {\r
+ requestSuccessCallback: null,\r
+ failCallback: null\r
+ }\r
+ });\r
+ // ConsoleAppender\r
+ function ConsoleAppender() {}\r
+ ConsoleAppender.prototype = new log4javascript.Appender();\r
+ copy(ConsoleAppender.prototype, {\r
+ create: f,\r
+ isNewestMessageAtTop: f,\r
+ setNewestMessageAtTop: f,\r
+ isScrollToLatestMessage: f,\r
+ setScrollToLatestMessage: f,\r
+ getWidth: f,\r
+ setWidth: f,\r
+ getHeight: f,\r
+ setHeight: f,\r
+ getMaxMessages: f,\r
+ setMaxMessages: f,\r
+ isShowCommandLine: f,\r
+ setShowCommandLine: f,\r
+ isShowHideButton: f,\r
+ setShowHideButton: f,\r
+ isShowCloseButton: f,\r
+ setShowCloseButton: f,\r
+ getCommandLineObjectExpansionDepth: f,\r
+ setCommandLineObjectExpansionDepth: f,\r
+ isInitiallyMinimized: f,\r
+ setInitiallyMinimized: f,\r
+ isUseDocumentWrite: f,\r
+ setUseDocumentWrite: f,\r
+ group: f,\r
+ groupEnd: f,\r
+ clear: f,\r
+ focus: f,\r
+ focusCommandLine: f,\r
+ focusSearch: f,\r
+ getCommandWindow: f,\r
+ setCommandWindow: f,\r
+ executeLastCommand: f,\r
+ getCommandLayout: f,\r
+ setCommandLayout: f,\r
+ evalCommandAndAppend: f,\r
+ addCommandLineFunction: f,\r
+ storeCommandHistory: f,\r
+ unload: f\r
+ });\r
+\r
+ ConsoleAppender.addGlobalCommandLineFunction = f;\r
+\r
+ // InPageAppender\r
+ log4javascript.InPageAppender = ff();\r
+ log4javascript.InPageAppender.prototype = new ConsoleAppender();\r
+ copy(log4javascript.InPageAppender.prototype, {\r
+ addCssProperty: f,\r
+ hide: f,\r
+ show: f,\r
+ isVisible: f,\r
+ close: f,\r
+ defaults: {\r
+ layout: new log4javascript.PatternLayout(),\r
+ maxMessages: null\r
+ }\r
+ });\r
+ log4javascript.InlineAppender = log4javascript.InPageAppender;\r
+\r
+ // PopUpAppender\r
+ log4javascript.PopUpAppender = ff();\r
+ log4javascript.PopUpAppender.prototype = new ConsoleAppender();\r
+ copy(log4javascript.PopUpAppender.prototype, {\r
+ isUseOldPopUp: f,\r
+ setUseOldPopUp: f,\r
+ isComplainAboutPopUpBlocking: f,\r
+ setComplainAboutPopUpBlocking: f,\r
+ isFocusPopUp: f,\r
+ setFocusPopUp: f,\r
+ isReopenWhenClosed: f,\r
+ setReopenWhenClosed: f,\r
+ close: f,\r
+ hide: f,\r
+ show: f,\r
+ defaults: {\r
+ layout: new log4javascript.PatternLayout(),\r
+ maxMessages: null\r
+ }\r
+ });\r
+ return log4javascript;\r
+})();\r
+if (typeof window.log4javascript == "undefined") {\r
+ var log4javascript = log4javascript_stub;\r
+}\r
--- /dev/null
+/**\r
+ * Copyright 2013 Tim Down.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+\r
+function array_contains(arr,val){for(var i=0;i<arr.length;i++){if(arr[i]==val){return true;}}\r
+return false;}\r
+function compareObjectInterface(obj1,obj1_name,obj2,obj2_name,namePrefix){if(!namePrefix){namePrefix="";}\r
+var obj1PropertyNames=new Array();for(var i in obj1){if(i!="prototype"&&i!="arguments"){obj1PropertyNames.push(i);}}\r
+if(obj1&&obj1.prototype&&!array_contains(obj1PropertyNames,"prototype")){}\r
+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);}}}\r
+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)\r
+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);}\r
+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();}\r
+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();}\r
+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×tamp=\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×tamp=\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×tamp=\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: "+\r
+log4javascript.logLog.debugMessages.join("\r\n");}\r
+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");}}\r
+window.setTimeout(checkDom,300);}else{appender.close();t.fail("Console mistakenly raised load event");}}\r
+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);});});\r
--- /dev/null
+/**\r
+ * Copyright 2013 Tim Down.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
--- /dev/null
+/**\r
+ * Copyright 2013 Tim Down.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
--- /dev/null
+/**\r
+ * Copyright 2013 Tim Down.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+\r
+function array_contains(arr,val){for(var i=0;i<arr.length;i++){if(arr[i]==val){return true;}}\r
+return false;}\r
+function compareObjectInterface(obj1,obj1_name,obj2,obj2_name,namePrefix){if(!namePrefix){namePrefix="";}\r
+var obj1PropertyNames=new Array();for(var i in obj1){if(i!="prototype"&&i!="arguments"){obj1PropertyNames.push(i);}}\r
+if(obj1&&obj1.prototype&&!array_contains(obj1PropertyNames,"prototype")){}\r
+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);}}}\r
+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)\r
+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);}\r
+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();}\r
+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();}\r
+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×tamp=\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×tamp=\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×tamp=\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]);});});\r
--- /dev/null
+/**\r
+ * Copyright 2013 Tim Down.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+function array_contains(arr, val) {\r
+ for (var i = 0; i < arr.length; i++) {\r
+ if (arr[i] == val) {\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+}\r
+\r
+// Recursively checks that obj2's interface contains all of obj1's\r
+// interface (functions and objects only)\r
+function compareObjectInterface(obj1, obj1_name, obj2, obj2_name, namePrefix) {\r
+ if (!namePrefix) {\r
+ namePrefix = "";\r
+ }\r
+ var obj1PropertyNames = new Array();\r
+ for (var i in obj1) {\r
+ if (i != "prototype" && i != "arguments") {\r
+ obj1PropertyNames.push(i);\r
+ }\r
+ }\r
+ if (obj1 && obj1.prototype && !array_contains(obj1PropertyNames, "prototype")) {\r
+ //obj1PropertyNames.push("prototype");\r
+ }\r
+ for (var j = 0; j < obj1PropertyNames.length; j++) {\r
+ var propertyName = obj1PropertyNames[j];\r
+ if ((typeof obj1[propertyName] == "function" || typeof obj1[propertyName] == "object") && !(obj1[propertyName] instanceof Array)) {\r
+ var propertyFullyQualifiedName = (namePrefix == "") ? propertyName : namePrefix + "." + propertyName;\r
+ try {\r
+ if (typeof obj2[propertyName] == "undefined") {\r
+ throw new Error(obj2_name + " does not contain " + propertyFullyQualifiedName + " in " + obj1_name);\r
+ } else if (typeof obj2[propertyName] != typeof obj1[propertyName]){\r
+ 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);\r
+ } else if (obj1[propertyName] != Function.prototype.apply) {\r
+ if (!compareObjectInterface(obj1[propertyName], obj1_name, obj2[propertyName], obj2_name, propertyFullyQualifiedName)) {\r
+ throw new Error("Interfaces don't match");\r
+ }\r
+ }\r
+ } catch(ex) {\r
+ throw new Error("Exception while checking property name " + propertyFullyQualifiedName + " in " + obj2_name + ": " + ex.message);\r
+ }\r
+ }\r
+ }\r
+ return true;\r
+};\r
+\r
+// Simply tests a layout for exceptions when formatting\r
+var testLayoutWithVariables = function(layout, t) {\r
+ var emptyObject = {};\r
+ var emptyArray = [];\r
+ var emptyString = "";\r
+ var localUndefined = emptyArray[0];\r
+ var oneLevelObject = {\r
+ "name": "One-level object"\r
+ };\r
+ var twoLevelObject = {\r
+ "name": "Two-level object",\r
+ "data": oneLevelObject\r
+ };\r
+ var threeLevelObject = {\r
+ "name": "Three-level object",\r
+ "data": twoLevelObject\r
+ };\r
+ var anArray = [\r
+ 3,\r
+ "stuff",\r
+ true,\r
+ false,\r
+ 0,\r
+ null,\r
+ localUndefined,\r
+ 3.14,\r
+ function(p) { return "I'm a function"; },\r
+ [1, "things"]\r
+ ];\r
+ var arrayOfTestItems = [emptyObject, emptyString, emptyString, localUndefined, oneLevelObject,\r
+ twoLevelObject, threeLevelObject, anArray];\r
+\r
+ t.log("Testing layout " + layout)\r
+ for (var i = 0; i < arrayOfTestItems.length; i++) {\r
+ var ex = new Error("Test error");\r
+ var loggingEvent = new log4javascript.LoggingEvent(t.logger, new Date(), log4javascript.Level.INFO,\r
+ [arrayOfTestItems[i]], null);\r
+ t.log("Formatting", arrayOfTestItems[i], result);\r
+ var result = layout.format(loggingEvent);\r
+ // Now try with an exception\r
+ loggingEvent.exception = ex;\r
+ t.log("Formatting with exception", arrayOfTestItems[i], result);\r
+ result = layout.format(loggingEvent);\r
+ }\r
+};\r
+\r
+xn.test.enableTestDebug = true;\r
+xn.test.enable_log4javascript = false;\r
+\r
+xn.test.suite("log4javascript tests", function(s) {\r
+ log4javascript.logLog.setQuietMode(true);\r
+ var ArrayAppender = function(layout) {\r
+ if (layout) {\r
+ this.setLayout(layout);\r
+ }\r
+ this.logMessages = [];\r
+ };\r
+\r
+ ArrayAppender.prototype = new log4javascript.Appender();\r
+\r
+ ArrayAppender.prototype.layout = new log4javascript.NullLayout();\r
+\r
+ ArrayAppender.prototype.append = function(loggingEvent) {\r
+ var formattedMessage = this.getLayout().format(loggingEvent);\r
+ if (this.getLayout().ignoresThrowable()) {\r
+ formattedMessage += loggingEvent.getThrowableStrRep();\r
+ }\r
+ this.logMessages.push(formattedMessage);\r
+ };\r
+\r
+ ArrayAppender.prototype.toString = function() {\r
+ return "[ArrayAppender]";\r
+ };\r
+\r
+ s.setUp = function(t) {\r
+ t.logger = log4javascript.getLogger("test");\r
+ t.logger.removeAllAppenders();\r
+ t.appender = new ArrayAppender();\r
+ t.logger.addAppender(t.appender);\r
+ };\r
+\r
+ s.tearDown = function(t) {\r
+ t.logger.removeAppender(t.appender);\r
+ log4javascript.resetConfiguration();\r
+ };\r
+\r
+ s.test("Stub script interface test", function(t) {\r
+ try {\r
+ compareObjectInterface(log4javascript, "log4javascript", log4javascript_stub, "log4javascript_stub");\r
+ } catch (ex) {\r
+ t.fail(ex);\r
+ }\r
+ });\r
+\r
+ s.test("Disable log4javascript test", function(t) {\r
+ log4javascript.setEnabled(false);\r
+ t.logger.debug("TEST");\r
+ t.assertEquals(t.appender.logMessages.length, 0);\r
+ log4javascript.setEnabled(true);\r
+ });\r
+\r
+ s.test("Array.splice test 1", function(t) {\r
+ var a = ["Marlon", "Ashley", "Darius", "Lloyd"];\r
+ var deletedItems = a.splice(1, 2);\r
+ t.assertEquals(a.join(","), "Marlon,Lloyd");\r
+ t.assertEquals(deletedItems.join(","), "Ashley,Darius");\r
+ });\r
+\r
+ s.test("Array.splice test 2", function(t) {\r
+ var a = ["Marlon", "Ashley", "Darius", "Lloyd"];\r
+ var deletedItems = a.splice(1, 1, "Malky", "Jay");\r
+ t.assertEquals(a.join(","), "Marlon,Malky,Jay,Darius,Lloyd");\r
+ t.assertEquals(deletedItems.join(","), "Ashley");\r
+ });\r
+\r
+ s.test("array_remove test", function(t) {\r
+ var array_remove = log4javascript.evalInScope("array_remove");\r
+ var a = ["Marlon", "Ashley", "Darius"];\r
+ array_remove(a, "Darius");\r
+ t.assertEquals(a.join(","), "Marlon,Ashley");\r
+ });\r
+\r
+ s.test("array_remove with empty array test", function(t) {\r
+ var array_remove = log4javascript.evalInScope("array_remove");\r
+ var a = [];\r
+ array_remove(a, "Darius");\r
+ t.assertEquals(a.join(","), "");\r
+ });\r
+\r
+ s.test("Logger logging test", function(t) {\r
+ // Should log since the default level for loggers is DEBUG and\r
+ // the default threshold for appenders is ALL\r
+ t.logger.debug("TEST");\r
+ t.assertEquals(t.appender.logMessages.length, 1);\r
+ });\r
+\r
+ s.test("Logger levels test", function(t) {\r
+ var originalLevel = t.logger.getEffectiveLevel();\r
+ t.logger.setLevel(log4javascript.Level.INFO);\r
+ t.logger.debug("TEST");\r
+ t.logger.setLevel(originalLevel);\r
+ t.assertEquals(t.appender.logMessages.length, 0);\r
+ });\r
+\r
+ s.test("Logger getEffectiveLevel inheritance test 1", function(t) {\r
+ var parentLogger = log4javascript.getLogger("test1");\r
+ var childLogger = log4javascript.getLogger("test1.test2");\r
+ parentLogger.setLevel(log4javascript.Level.ERROR);\r
+ t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.ERROR);\r
+ });\r
+\r
+ s.test("Logger getEffectiveLevel inheritance test 2", function(t) {\r
+ var grandParentLogger = log4javascript.getLogger("test1");\r
+ var childLogger = log4javascript.getLogger("test1.test2.test3");\r
+ grandParentLogger.setLevel(log4javascript.Level.ERROR);\r
+ t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.ERROR);\r
+ });\r
+\r
+ s.test("Logger getEffectiveLevel inheritance test 3", function(t) {\r
+ var parentLogger = log4javascript.getLogger("test1");\r
+ var childLogger = log4javascript.getLogger("test1.test2");\r
+ parentLogger.setLevel(log4javascript.Level.ERROR);\r
+ childLogger.setLevel(log4javascript.Level.INFO);\r
+ t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.INFO);\r
+ });\r
+\r
+ s.test("Logger getEffectiveLevel root inheritance test", function(t) {\r
+ var rootLogger = log4javascript.getRootLogger();\r
+ var childLogger = log4javascript.getLogger("test1.test2.test3");\r
+ rootLogger.setLevel(log4javascript.Level.WARN);\r
+ t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.WARN);\r
+ });\r
+\r
+ s.test("Logger null level test", function(t) {\r
+ t.logger.setLevel(null);\r
+ // Should default to root logger level, which is DEBUG\r
+ t.assertEquals(t.logger.getEffectiveLevel(), log4javascript.Level.DEBUG);\r
+ });\r
+\r
+ s.test("Logger appender additivity test 1", function(t) {\r
+ var parentLogger = log4javascript.getLogger("test1");\r
+ var childLogger = log4javascript.getLogger("test1.test2");\r
+ var parentLoggerAppender = new ArrayAppender();\r
+ var childLoggerAppender = new ArrayAppender();\r
+\r
+ parentLogger.addAppender(parentLoggerAppender);\r
+ childLogger.addAppender(childLoggerAppender);\r
+\r
+ parentLogger.info("Parent logger test message");\r
+ childLogger.info("Child logger test message");\r
+\r
+ t.assertEquals(parentLoggerAppender.logMessages.length, 2);\r
+ t.assertEquals(childLoggerAppender.logMessages.length, 1);\r
+ });\r
+\r
+ s.test("Logger appender additivity test 2", function(t) {\r
+ var parentLogger = log4javascript.getLogger("test1");\r
+ var childLogger = log4javascript.getLogger("test1.test2");\r
+ var parentLoggerAppender = new ArrayAppender();\r
+ var childLoggerAppender = new ArrayAppender();\r
+\r
+ parentLogger.addAppender(parentLoggerAppender);\r
+ childLogger.addAppender(childLoggerAppender);\r
+\r
+ childLogger.setAdditivity(false);\r
+\r
+ parentLogger.info("Parent logger test message");\r
+ childLogger.info("Child logger test message");\r
+\r
+ t.assertEquals(parentLoggerAppender.logMessages.length, 1);\r
+ t.assertEquals(childLoggerAppender.logMessages.length, 1);\r
+ });\r
+\r
+ s.test("Logger appender additivity test 3", function(t) {\r
+ var parentLogger = log4javascript.getLogger("test1");\r
+ var childLogger = log4javascript.getLogger("test1.test2");\r
+ var parentLoggerAppender = new ArrayAppender();\r
+ var childLoggerAppender = new ArrayAppender();\r
+\r
+ parentLogger.addAppender(parentLoggerAppender);\r
+ childLogger.addAppender(childLoggerAppender);\r
+\r
+ childLogger.setAdditivity(false);\r
+\r
+ parentLogger.info("Parent logger test message");\r
+ childLogger.info("Child logger test message");\r
+\r
+ childLogger.setAdditivity(true);\r
+\r
+ childLogger.info("Child logger test message 2");\r
+\r
+ t.assertEquals(parentLoggerAppender.logMessages.length, 2);\r
+ t.assertEquals(childLoggerAppender.logMessages.length, 2);\r
+ });\r
+\r
+ s.test("Appender threshold test", function(t) {\r
+ t.appender.setThreshold(log4javascript.Level.INFO);\r
+ t.logger.debug("TEST");\r
+ t.assertEquals(t.appender.logMessages.length, 0);\r
+ });\r
+\r
+ s.test("Basic appender / layout test", function(t) {\r
+ t.logger.debug("TEST");\r
+ t.assertEquals(t.appender.logMessages[0], "TEST");\r
+ });\r
+\r
+ s.test("Appender uniqueness within logger test", function(t) {\r
+ // Add the same appender to the logger for a second time\r
+ t.logger.addAppender(t.appender);\r
+ t.logger.debug("TEST");\r
+ t.assertEquals(t.appender.logMessages.length, 1);\r
+ });\r
+\r
+ s.test("Logger remove appender test", function(t) {\r
+ t.logger.debug("TEST");\r
+ t.logger.removeAppender(t.appender);\r
+ t.logger.debug("TEST AGAIN");\r
+ t.assertEquals(t.appender.logMessages.length, 1);\r
+ });\r
+\r
+ s.test("", function(t) {\r
+ t.logger.debug("TEST");\r
+ t.logger.removeAppender(t.appender);\r
+ t.logger.debug("TEST AGAIN");\r
+ t.assertEquals(t.appender.logMessages.length, 1);\r
+ });\r
+ s.test("SimpleLayout format test", function(t) {\r
+ var layout = new log4javascript.SimpleLayout();\r
+ testLayoutWithVariables(layout, t);\r
+ });\r
+\r
+ s.test("SimpleLayout test", function(t) {\r
+ t.appender.setLayout(new log4javascript.SimpleLayout());\r
+ t.logger.debug("TEST");\r
+ t.assertEquals(t.appender.logMessages[0], "DEBUG - TEST");\r
+ });\r
+ s.test("NullLayout format test", function(t) {\r
+ var layout = new log4javascript.NullLayout();\r
+ testLayoutWithVariables(layout, t);\r
+ });\r
+\r
+ s.test("NullLayout test", function(t) {\r
+ t.appender.setLayout(new log4javascript.NullLayout());\r
+ t.logger.debug("TEST");\r
+ t.assertEquals(t.appender.logMessages[0], "TEST");\r
+ });\r
+ s.test("XmlLayout format test", function(t) {\r
+ var layout = new log4javascript.XmlLayout();\r
+ testLayoutWithVariables(layout, t);\r
+ });\r
+\r
+ s.test("XmlLayout test", function(t) {\r
+ t.appender.setLayout(new log4javascript.XmlLayout());\r
+ t.logger.debug("TEST");\r
+ 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]);\r
+ });\r
+\r
+ s.test("XmlLayout with exception test", function(t) {\r
+ t.appender.setLayout(new log4javascript.XmlLayout());\r
+ t.logger.debug("TEST", new Error("Test error"));\r
+ 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]);\r
+ });\r
+\r
+ var setUpXmlLayoutMillisecondsTest = function(t) {\r
+ t.date = new Date();\r
+ t.timeInMilliseconds = t.date.getTime();\r
+ t.timeInSeconds = Math.floor(t.timeInMilliseconds / 1000);\r
+ t.milliseconds = t.date.getMilliseconds();\r
+ \r
+ t.loggingEvent = new log4javascript.LoggingEvent(t.logger, t.date, log4javascript.Level.DEBUG, ["TEST"], null);\r
+ t.layout = new log4javascript.XmlLayout();\r
+ }\r
+\r
+ s.test("XmlLayout seconds/milliseconds test 1", function(t) {\r
+ setUpXmlLayoutMillisecondsTest(t);\r
+\r
+ // Test default (i.e. timestamps in milliseconds) first\r
+ var regex = new RegExp('^<log4javascript:event logger="test" timestamp="' + t.timeInMilliseconds + '" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');\r
+ t.assertRegexMatches(regex, t.layout.format(t.loggingEvent));\r
+ });\r
+ \r
+ s.test("XmlLayout seconds/milliseconds test 2", function(t) {\r
+ setUpXmlLayoutMillisecondsTest(t);\r
+\r
+ // Change the global setting\r
+ log4javascript.setTimeStampsInMilliseconds(false);\r
+ var formatted = t.layout.format(t.loggingEvent);\r
+ log4javascript.setTimeStampsInMilliseconds(true);\r
+ 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*$');\r
+ t.assertRegexMatches(regex, formatted);\r
+ });\r
+\r
+ s.test("XmlLayout seconds/milliseconds test 3", function(t) {\r
+ setUpXmlLayoutMillisecondsTest(t);\r
+\r
+ // Change the layout setting\r
+ t.layout.setTimeStampsInMilliseconds(false);\r
+ var formatted = t.layout.format(t.loggingEvent);\r
+ 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*$');\r
+ t.assertRegexMatches(regex, formatted);\r
+ });\r
+ s.test("escapeNewLines test", function(t) {\r
+ var escapeNewLines = log4javascript.evalInScope("escapeNewLines");\r
+ var str = "1\r2\n3\n4\r\n5\r6\r\n7";\r
+ t.assertEquals(escapeNewLines(str), "1\\r\\n2\\r\\n3\\r\\n4\\r\\n5\\r\\n6\\r\\n7");\r
+ });\r
+\r
+ s.test("JsonLayout format test", function(t) {\r
+ var layout = new log4javascript.JsonLayout();\r
+ testLayoutWithVariables(layout, t);\r
+ });\r
+\r
+ s.test("JsonLayout test", function(t) {\r
+ t.appender.setLayout(new log4javascript.JsonLayout());\r
+ t.logger.debug("TEST");\r
+ t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST"}$/, t.appender.logMessages[0]);\r
+ });\r
+\r
+ s.test("JsonLayout JSON validity test", function(t) {\r
+ t.appender.setLayout(new log4javascript.JsonLayout());\r
+ t.logger.debug("TEST");\r
+ eval("var o = " + t.appender.logMessages[0]);\r
+ t.assertEquals(o.message, "TEST");\r
+ });\r
+\r
+ s.test("JsonLayout with number type message test", function(t) {\r
+ t.appender.setLayout(new log4javascript.JsonLayout());\r
+ t.logger.debug(15);\r
+ t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":15}$/, t.appender.logMessages[0]);\r
+ });\r
+\r
+ s.test("JsonLayout with object type message test", function(t) {\r
+ t.appender.setLayout(new log4javascript.JsonLayout());\r
+ t.logger.debug({});\r
+ t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"\[object Object\]"}$/, t.appender.logMessages[0]);\r
+ });\r
+\r
+ s.test("JsonLayout with boolean type message test", function(t) {\r
+ t.appender.setLayout(new log4javascript.JsonLayout());\r
+ t.logger.debug(false);\r
+ t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":false}$/, t.appender.logMessages[0]);\r
+ });\r
+\r
+ s.test("JsonLayout with quote test", function(t) {\r
+ t.appender.setLayout(new log4javascript.JsonLayout());\r
+ t.logger.debug("TE\"S\"T");\r
+ t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TE\\"S\\"T"}$/, t.appender.logMessages[0]);\r
+ });\r
+\r
+ s.test("JsonLayout with exception test", function(t) {\r
+ t.appender.setLayout(new log4javascript.JsonLayout());\r
+ t.logger.debug("TEST", new Error("Test error"));\r
+ t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST","exception":.*}$/, t.appender.logMessages[0]);\r
+ });\r
+\r
+ var setUpJsonLayoutMillisecondsTest = function(t) {\r
+ t.date = new Date();\r
+ t.timeInMilliseconds = t.date.getTime();\r
+ t.timeInSeconds = Math.floor(t.timeInMilliseconds / 1000);\r
+ t.milliseconds = t.date.getMilliseconds();\r
+ \r
+ t.loggingEvent = new log4javascript.LoggingEvent(t.logger, t.date, log4javascript.Level.DEBUG, ["TEST"], null);\r
+ t.layout = new log4javascript.JsonLayout();\r
+ };\r
+\r
+ s.test("JsonLayout seconds/milliseconds test 1", function(t) {\r
+ setUpJsonLayoutMillisecondsTest(t);\r
+\r
+ // Test default (i.e. timestamps in milliseconds) first\r
+ var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInMilliseconds + ',"level":"DEBUG","url":".*","message":"TEST"}$');\r
+ t.assertRegexMatches(regex, t.layout.format(t.loggingEvent));\r
+ });\r
+ \r
+ s.test("JsonLayout seconds/milliseconds test 2", function(t) {\r
+ setUpJsonLayoutMillisecondsTest(t);\r
+\r
+ // Change the global setting\r
+ log4javascript.setTimeStampsInMilliseconds(false);\r
+ var formatted = t.layout.format(t.loggingEvent);\r
+ log4javascript.setTimeStampsInMilliseconds(true);\r
+ var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInSeconds + ',"level":"DEBUG","url":".*","message":"TEST","milliseconds":' + t.milliseconds + '}$');\r
+ t.assertRegexMatches(regex, formatted);\r
+ });\r
+\r
+ s.test("JsonLayout seconds/milliseconds test 3", function(t) {\r
+ setUpJsonLayoutMillisecondsTest(t);\r
+\r
+ // Change the layout setting\r
+ t.layout.setTimeStampsInMilliseconds(false);\r
+ var formatted = t.layout.format(t.loggingEvent);\r
+ var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInSeconds + ',"level":"DEBUG","url":".*","message":"TEST","milliseconds":' + t.milliseconds + '}$');\r
+ t.assertRegexMatches(regex, formatted);\r
+ });\r
+ s.test("HttpPostDataLayout format test", function(t) {\r
+ var layout = new log4javascript.HttpPostDataLayout();\r
+ testLayoutWithVariables(layout, t);\r
+ });\r
+\r
+ s.test("HttpPostDataLayout test", function(t) {\r
+ t.appender.setLayout(new log4javascript.HttpPostDataLayout());\r
+ t.logger.debug("TEST");\r
+ t.assertRegexMatches(/^logger=test×tamp=\d+&level=DEBUG&url=.*&message=TEST$/, t.appender.logMessages[0]);\r
+ });\r
+\r
+ s.test("HttpPostDataLayout URL encoding test", function(t) {\r
+ t.appender.setLayout(new log4javascript.HttpPostDataLayout());\r
+ t.logger.debug("TEST +\"1\"");\r
+ t.assertRegexMatches(/^logger=test×tamp=\d+&level=DEBUG&url=.*&message=TEST%20%2B%221%22$/, t.appender.logMessages[0]);\r
+ });\r
+\r
+ s.test("HttpPostDataLayout with exception test", function(t) {\r
+ t.appender.setLayout(new log4javascript.HttpPostDataLayout());\r
+ t.logger.debug("TEST", new Error("Test error"));\r
+ t.assertRegexMatches(/^logger=test×tamp=\d+&level=DEBUG&url=.*&message=TEST&exception=.*$/, t.appender.logMessages[0]);\r
+ });\r
+\r
+ (function() {\r
+ var formatObjectExpansion = log4javascript.evalInScope("formatObjectExpansion");\r
+ var newLine = log4javascript.evalInScope("newLine");\r
+ var arr = [\r
+ null,\r
+ undefined,\r
+ 1.2,\r
+ "A string",\r
+ [1, "test"],\r
+ {\r
+ a: {\r
+ b: 1\r
+ }\r
+ }\r
+ ];\r
+\r
+ s.test("Basic formatObjectExpansion array test (depth: 1)", function(t) {\r
+ t.assertEquals(formatObjectExpansion(arr, 1),\r
+ "[" + newLine +\r
+ " null," + newLine +\r
+ " undefined," + newLine +\r
+ " 1.2," + newLine +\r
+ " A string," + newLine +\r
+ " 1,test," + newLine +\r
+ " [object Object]" + newLine +\r
+ "]"\r
+ );\r
+ });\r
+\r
+ s.test("Basic formatObjectExpansion array test (depth: 2)", function(t) {\r
+ t.assertEquals(formatObjectExpansion(arr, 2),\r
+ "[" + newLine +\r
+ " null," + newLine +\r
+ " undefined," + newLine +\r
+ " 1.2," + newLine +\r
+ " A string," + newLine +\r
+ " [" + newLine +\r
+ " 1," + newLine +\r
+ " test" + newLine +\r
+ " ]," + newLine +\r
+ " {" + newLine +\r
+ " a: [object Object]" + newLine +\r
+ " }" + newLine +\r
+ "]"\r
+ );\r
+ });\r
+\r
+ s.test("formatObjectExpansion simple object test", function(t) {\r
+ var obj = {\r
+ STRING: "A string"\r
+ };\r
+ t.assertEquals(formatObjectExpansion(obj, 1), \r
+ "{" + newLine +\r
+ " STRING: A string" + newLine +\r
+ "}"\r
+ );\r
+ });\r
+\r
+ s.test("formatObjectExpansion simple circular object test", function(t) {\r
+ var obj = {};\r
+ obj.a = obj;\r
+ \r
+ t.assertEquals(formatObjectExpansion(obj, 2), \r
+ "{" + newLine +\r
+ " a: [object Object] [already expanded]" + newLine +\r
+ "}"\r
+ );\r
+ });\r
+ })(); /* ---------------------------------------------------------- */\r
+\r
+ var getSampleDate = function() {\r
+ var date = new Date();\r
+ date.setFullYear(2006);\r
+ date.setMonth(7);\r
+ date.setDate(30);\r
+ date.setHours(15);\r
+ date.setMinutes(38);\r
+ date.setSeconds(45);\r
+ return date;\r
+ };\r
+\r
+ /* ---------------------------------------------------------- */\r
+\r
+ s.test("String.replace test", function(t) {\r
+ t.assertEquals("Hello world".replace(/o/g, "Z"), "HellZ wZrld");\r
+ });\r
+\r
+ s.test("PatternLayout format test", function(t) {\r
+ var layout = new log4javascript.PatternLayout();\r
+ testLayoutWithVariables(layout, t);\r
+ });\r
+\r
+ s.test("PatternLayout dates test", function(t) {\r
+ var layout = new log4javascript.PatternLayout("%d %d{DATE} %d{HH:ss}");\r
+ t.appender.setLayout(layout);\r
+ t.logger.debug("TEST");\r
+ 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]);\r
+ });\r
+\r
+ s.test("PatternLayout modifiers test", function(t) {\r
+ var layout = new log4javascript.PatternLayout("%m|%3m|%-3m|%6m|%-6m|%.2m|%1.2m|%6.8m|%-1.2m|%-6.8m|");\r
+ t.appender.setLayout(layout);\r
+ t.logger.debug("TEST");\r
+ t.assertEquals(t.appender.logMessages[0], "TEST|TEST|TEST| TEST|TEST |ST|ST| TEST|ST|TEST |");\r
+ });\r
+\r
+ s.test("PatternLayout conversion characters test", function(t) {\r
+ var layout = new log4javascript.PatternLayout("%c %n %p %r literal %%");\r
+ t.appender.setLayout(layout);\r
+ t.logger.debug("TEST");\r
+ t.assertRegexMatches(/^test \s+ DEBUG \d+ literal %$/, t.appender.logMessages[0]);\r
+ });\r
+\r
+ s.test("PatternLayout message test", function(t) {\r
+ var layout = new log4javascript.PatternLayout("%m{1} %m{2}");\r
+ t.appender.setLayout(layout);\r
+ var testObj = {\r
+ strikers: {\r
+ quick: "Marlon"\r
+ }\r
+ };\r
+ t.logger.debug(testObj);\r
+ t.assertEquals("{\r\n strikers: [object Object]\r\n} {\r\n\ strikers: {\r\n quick: Marlon\r\n }\r\n}", t.appender.logMessages[0]);\r
+ });\r
+/*\r
+ s.test("AjaxAppender JsonLayout single message test", function(t) {\r
+ t.async(10000);\r
+ // Create and add an Ajax appender\r
+ var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");\r
+ ajaxAppender.setLayout(new log4javascript.JsonLayout());\r
+ ajaxAppender.setRequestSuccessCallback(\r
+ function(xmlHttp) {\r
+ // Response comes back as JSON array of messages logged\r
+ var jsonResponse = xmlHttp.responseText;\r
+ var arr = eval(jsonResponse);\r
+ t.assertEquals(arr.length, 1);\r
+ t.assertEquals(arr[0], "TEST");\r
+ t.succeed();\r
+ }\r
+ );\r
+ ajaxAppender.setFailCallback(\r
+ function(msg) {\r
+ t.fail(msg);\r
+ ajaxErrorMessage = msg;\r
+ }\r
+ );\r
+ t.logger.addAppender(ajaxAppender);\r
+ t.logger.debug("TEST");\r
+ });\r
+\r
+ s.test("AjaxAppender JsonLayout batched messages test", function(t) {\r
+ t.async(10000);\r
+ var message1 = "TEST 1";\r
+ var message2 = "String with \"lots of 'quotes'\" + plusses in";\r
+ var message3 = "A non-threatening string";\r
+ // Create and add an Ajax appender\r
+ var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");\r
+ ajaxAppender.setLayout(new log4javascript.JsonLayout());\r
+ ajaxAppender.setBatchSize(3);\r
+ ajaxAppender.setRequestSuccessCallback(\r
+ function(xmlHttp) {\r
+ // Response comes back as JSON array of messages logged\r
+ var jsonResponse = xmlHttp.responseText;\r
+ var arr = eval(jsonResponse);\r
+ t.assertEquals(arr.length, 3);\r
+ t.assertEquals(arr[0], message1);\r
+ t.assertEquals(arr[1], message2);\r
+ t.assertEquals(arr[2], message3);\r
+ t.succeed();\r
+ }\r
+ );\r
+ ajaxAppender.setFailCallback(\r
+ function(msg) {\r
+ t.fail(msg);\r
+ ajaxErrorMessage = msg;\r
+ }\r
+ );\r
+ t.logger.addAppender(ajaxAppender);\r
+ t.logger.debug(message1);\r
+ t.logger.info(message2);\r
+ t.logger.warn(message3);\r
+ });\r
+\r
+ s.test("AjaxAppender HttpPostDataLayout single message test", function(t) {\r
+ t.async(10000);\r
+ // Create and add an Ajax appender\r
+ var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");\r
+ var testMessage = "TEST +\"1\"";\r
+ ajaxAppender.setLayout(new log4javascript.HttpPostDataLayout());\r
+ ajaxAppender.setRequestSuccessCallback(\r
+ function(xmlHttp) {\r
+ // Response comes back as JSON array of messages logged\r
+ var jsonResponse = xmlHttp.responseText;\r
+ var arr = eval(jsonResponse);\r
+ t.assertEquals(arr.length, 1);\r
+ t.assertEquals(arr[0], testMessage);\r
+ t.succeed();\r
+ }\r
+ );\r
+ ajaxAppender.setFailCallback(\r
+ function(msg) {\r
+ t.fail(msg);\r
+ ajaxErrorMessage = msg;\r
+ }\r
+ );\r
+ t.logger.addAppender(ajaxAppender);\r
+ t.logger.debug(testMessage);\r
+ });\r
+*/\r
+});
\ No newline at end of file
--- /dev/null
+/**\r
+ * Copyright 2013 Tim Down.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+function array_contains(arr, val) {\r
+ for (var i = 0; i < arr.length; i++) {\r
+ if (arr[i] == val) {\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+}\r
+\r
+// Recursively checks that obj2's interface contains all of obj1's\r
+// interface (functions and objects only)\r
+function compareObjectInterface(obj1, obj1_name, obj2, obj2_name, namePrefix) {\r
+ if (!namePrefix) {\r
+ namePrefix = "";\r
+ }\r
+ var obj1PropertyNames = new Array();\r
+ for (var i in obj1) {\r
+ if (i != "prototype" && i != "arguments") {\r
+ obj1PropertyNames.push(i);\r
+ }\r
+ }\r
+ if (obj1 && obj1.prototype && !array_contains(obj1PropertyNames, "prototype")) {\r
+ //obj1PropertyNames.push("prototype");\r
+ }\r
+ for (var j = 0; j < obj1PropertyNames.length; j++) {\r
+ var propertyName = obj1PropertyNames[j];\r
+ if ((typeof obj1[propertyName] == "function" || typeof obj1[propertyName] == "object") && !(obj1[propertyName] instanceof Array)) {\r
+ var propertyFullyQualifiedName = (namePrefix == "") ? propertyName : namePrefix + "." + propertyName;\r
+ try {\r
+ if (typeof obj2[propertyName] == "undefined") {\r
+ throw new Error(obj2_name + " does not contain " + propertyFullyQualifiedName + " in " + obj1_name);\r
+ } else if (typeof obj2[propertyName] != typeof obj1[propertyName]){\r
+ 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);\r
+ } else if (obj1[propertyName] != Function.prototype.apply) {\r
+ if (!compareObjectInterface(obj1[propertyName], obj1_name, obj2[propertyName], obj2_name, propertyFullyQualifiedName)) {\r
+ throw new Error("Interfaces don't match");\r
+ }\r
+ }\r
+ } catch(ex) {\r
+ throw new Error("Exception while checking property name " + propertyFullyQualifiedName + " in " + obj2_name + ": " + ex.message);\r
+ }\r
+ }\r
+ }\r
+ return true;\r
+};\r
+\r
+// Simply tests a layout for exceptions when formatting\r
+var testLayoutWithVariables = function(layout, t) {\r
+ var emptyObject = {};\r
+ var emptyArray = [];\r
+ var emptyString = "";\r
+ var localUndefined = emptyArray[0];\r
+ var oneLevelObject = {\r
+ "name": "One-level object"\r
+ };\r
+ var twoLevelObject = {\r
+ "name": "Two-level object",\r
+ "data": oneLevelObject\r
+ };\r
+ var threeLevelObject = {\r
+ "name": "Three-level object",\r
+ "data": twoLevelObject\r
+ };\r
+ var anArray = [\r
+ 3,\r
+ "stuff",\r
+ true,\r
+ false,\r
+ 0,\r
+ null,\r
+ localUndefined,\r
+ 3.14,\r
+ function(p) { return "I'm a function"; },\r
+ [1, "things"]\r
+ ];\r
+ var arrayOfTestItems = [emptyObject, emptyString, emptyString, localUndefined, oneLevelObject,\r
+ twoLevelObject, threeLevelObject, anArray];\r
+\r
+ t.log("Testing layout " + layout)\r
+ for (var i = 0; i < arrayOfTestItems.length; i++) {\r
+ var ex = new Error("Test error");\r
+ var loggingEvent = new log4javascript.LoggingEvent(t.logger, new Date(), log4javascript.Level.INFO,\r
+ [arrayOfTestItems[i]], null);\r
+ t.log("Formatting", arrayOfTestItems[i], result);\r
+ var result = layout.format(loggingEvent);\r
+ // Now try with an exception\r
+ loggingEvent.exception = ex;\r
+ t.log("Formatting with exception", arrayOfTestItems[i], result);\r
+ result = layout.format(loggingEvent);\r
+ }\r
+};\r
+\r
+xn.test.enableTestDebug = true;\r
+xn.test.enable_log4javascript = false;\r
+\r
+xn.test.suite("log4javascript tests", function(s) {\r
+ log4javascript.logLog.setQuietMode(true);\r
+ var ArrayAppender = function(layout) {\r
+ if (layout) {\r
+ this.setLayout(layout);\r
+ }\r
+ this.logMessages = [];\r
+ };\r
+\r
+ ArrayAppender.prototype = new log4javascript.Appender();\r
+\r
+ ArrayAppender.prototype.layout = new log4javascript.NullLayout();\r
+\r
+ ArrayAppender.prototype.append = function(loggingEvent) {\r
+ var formattedMessage = this.getLayout().format(loggingEvent);\r
+ if (this.getLayout().ignoresThrowable()) {\r
+ formattedMessage += loggingEvent.getThrowableStrRep();\r
+ }\r
+ this.logMessages.push(formattedMessage);\r
+ };\r
+\r
+ ArrayAppender.prototype.toString = function() {\r
+ return "[ArrayAppender]";\r
+ };\r
+\r
+ s.setUp = function(t) {\r
+ t.logger = log4javascript.getLogger("test");\r
+ t.logger.removeAllAppenders();\r
+ t.appender = new ArrayAppender();\r
+ t.logger.addAppender(t.appender);\r
+ };\r
+\r
+ s.tearDown = function(t) {\r
+ t.logger.removeAppender(t.appender);\r
+ log4javascript.resetConfiguration();\r
+ };\r
+\r
+ s.test("Stub script interface test", function(t) {\r
+ try {\r
+ compareObjectInterface(log4javascript, "log4javascript", log4javascript_stub, "log4javascript_stub");\r
+ } catch (ex) {\r
+ t.fail(ex);\r
+ }\r
+ });\r
+\r
+ s.test("Disable log4javascript test", function(t) {\r
+ log4javascript.setEnabled(false);\r
+ t.logger.debug("TEST");\r
+ t.assertEquals(t.appender.logMessages.length, 0);\r
+ log4javascript.setEnabled(true);\r
+ });\r
+\r
+ s.test("Array.splice test 1", function(t) {\r
+ var a = ["Marlon", "Ashley", "Darius", "Lloyd"];\r
+ var deletedItems = a.splice(1, 2);\r
+ t.assertEquals(a.join(","), "Marlon,Lloyd");\r
+ t.assertEquals(deletedItems.join(","), "Ashley,Darius");\r
+ });\r
+\r
+ s.test("Array.splice test 2", function(t) {\r
+ var a = ["Marlon", "Ashley", "Darius", "Lloyd"];\r
+ var deletedItems = a.splice(1, 1, "Malky", "Jay");\r
+ t.assertEquals(a.join(","), "Marlon,Malky,Jay,Darius,Lloyd");\r
+ t.assertEquals(deletedItems.join(","), "Ashley");\r
+ });\r
+\r
+ s.test("array_remove test", function(t) {\r
+ var array_remove = log4javascript.evalInScope("array_remove");\r
+ var a = ["Marlon", "Ashley", "Darius"];\r
+ array_remove(a, "Darius");\r
+ t.assertEquals(a.join(","), "Marlon,Ashley");\r
+ });\r
+\r
+ s.test("array_remove with empty array test", function(t) {\r
+ var array_remove = log4javascript.evalInScope("array_remove");\r
+ var a = [];\r
+ array_remove(a, "Darius");\r
+ t.assertEquals(a.join(","), "");\r
+ });\r
+\r
+ s.test("Logger logging test", function(t) {\r
+ // Should log since the default level for loggers is DEBUG and\r
+ // the default threshold for appenders is ALL\r
+ t.logger.debug("TEST");\r
+ t.assertEquals(t.appender.logMessages.length, 1);\r
+ });\r
+\r
+ s.test("Logger levels test", function(t) {\r
+ var originalLevel = t.logger.getEffectiveLevel();\r
+ t.logger.setLevel(log4javascript.Level.INFO);\r
+ t.logger.debug("TEST");\r
+ t.logger.setLevel(originalLevel);\r
+ t.assertEquals(t.appender.logMessages.length, 0);\r
+ });\r
+\r
+ s.test("Logger getEffectiveLevel inheritance test 1", function(t) {\r
+ var parentLogger = log4javascript.getLogger("test1");\r
+ var childLogger = log4javascript.getLogger("test1.test2");\r
+ parentLogger.setLevel(log4javascript.Level.ERROR);\r
+ t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.ERROR);\r
+ });\r
+\r
+ s.test("Logger getEffectiveLevel inheritance test 2", function(t) {\r
+ var grandParentLogger = log4javascript.getLogger("test1");\r
+ var childLogger = log4javascript.getLogger("test1.test2.test3");\r
+ grandParentLogger.setLevel(log4javascript.Level.ERROR);\r
+ t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.ERROR);\r
+ });\r
+\r
+ s.test("Logger getEffectiveLevel inheritance test 3", function(t) {\r
+ var parentLogger = log4javascript.getLogger("test1");\r
+ var childLogger = log4javascript.getLogger("test1.test2");\r
+ parentLogger.setLevel(log4javascript.Level.ERROR);\r
+ childLogger.setLevel(log4javascript.Level.INFO);\r
+ t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.INFO);\r
+ });\r
+\r
+ s.test("Logger getEffectiveLevel root inheritance test", function(t) {\r
+ var rootLogger = log4javascript.getRootLogger();\r
+ var childLogger = log4javascript.getLogger("test1.test2.test3");\r
+ rootLogger.setLevel(log4javascript.Level.WARN);\r
+ t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.WARN);\r
+ });\r
+\r
+ s.test("Logger null level test", function(t) {\r
+ t.logger.setLevel(null);\r
+ // Should default to root logger level, which is DEBUG\r
+ t.assertEquals(t.logger.getEffectiveLevel(), log4javascript.Level.DEBUG);\r
+ });\r
+\r
+ s.test("Logger appender additivity test 1", function(t) {\r
+ var parentLogger = log4javascript.getLogger("test1");\r
+ var childLogger = log4javascript.getLogger("test1.test2");\r
+ var parentLoggerAppender = new ArrayAppender();\r
+ var childLoggerAppender = new ArrayAppender();\r
+\r
+ parentLogger.addAppender(parentLoggerAppender);\r
+ childLogger.addAppender(childLoggerAppender);\r
+\r
+ parentLogger.info("Parent logger test message");\r
+ childLogger.info("Child logger test message");\r
+\r
+ t.assertEquals(parentLoggerAppender.logMessages.length, 2);\r
+ t.assertEquals(childLoggerAppender.logMessages.length, 1);\r
+ });\r
+\r
+ s.test("Logger appender additivity test 2", function(t) {\r
+ var parentLogger = log4javascript.getLogger("test1");\r
+ var childLogger = log4javascript.getLogger("test1.test2");\r
+ var parentLoggerAppender = new ArrayAppender();\r
+ var childLoggerAppender = new ArrayAppender();\r
+\r
+ parentLogger.addAppender(parentLoggerAppender);\r
+ childLogger.addAppender(childLoggerAppender);\r
+\r
+ childLogger.setAdditivity(false);\r
+\r
+ parentLogger.info("Parent logger test message");\r
+ childLogger.info("Child logger test message");\r
+\r
+ t.assertEquals(parentLoggerAppender.logMessages.length, 1);\r
+ t.assertEquals(childLoggerAppender.logMessages.length, 1);\r
+ });\r
+\r
+ s.test("Logger appender additivity test 3", function(t) {\r
+ var parentLogger = log4javascript.getLogger("test1");\r
+ var childLogger = log4javascript.getLogger("test1.test2");\r
+ var parentLoggerAppender = new ArrayAppender();\r
+ var childLoggerAppender = new ArrayAppender();\r
+\r
+ parentLogger.addAppender(parentLoggerAppender);\r
+ childLogger.addAppender(childLoggerAppender);\r
+\r
+ childLogger.setAdditivity(false);\r
+\r
+ parentLogger.info("Parent logger test message");\r
+ childLogger.info("Child logger test message");\r
+\r
+ childLogger.setAdditivity(true);\r
+\r
+ childLogger.info("Child logger test message 2");\r
+\r
+ t.assertEquals(parentLoggerAppender.logMessages.length, 2);\r
+ t.assertEquals(childLoggerAppender.logMessages.length, 2);\r
+ });\r
+\r
+ s.test("Appender threshold test", function(t) {\r
+ t.appender.setThreshold(log4javascript.Level.INFO);\r
+ t.logger.debug("TEST");\r
+ t.assertEquals(t.appender.logMessages.length, 0);\r
+ });\r
+\r
+ s.test("Basic appender / layout test", function(t) {\r
+ t.logger.debug("TEST");\r
+ t.assertEquals(t.appender.logMessages[0], "TEST");\r
+ });\r
+\r
+ s.test("Appender uniqueness within logger test", function(t) {\r
+ // Add the same appender to the logger for a second time\r
+ t.logger.addAppender(t.appender);\r
+ t.logger.debug("TEST");\r
+ t.assertEquals(t.appender.logMessages.length, 1);\r
+ });\r
+\r
+ s.test("Logger remove appender test", function(t) {\r
+ t.logger.debug("TEST");\r
+ t.logger.removeAppender(t.appender);\r
+ t.logger.debug("TEST AGAIN");\r
+ t.assertEquals(t.appender.logMessages.length, 1);\r
+ });\r
+\r
+ s.test("", function(t) {\r
+ t.logger.debug("TEST");\r
+ t.logger.removeAppender(t.appender);\r
+ t.logger.debug("TEST AGAIN");\r
+ t.assertEquals(t.appender.logMessages.length, 1);\r
+ });\r
+ s.test("SimpleLayout format test", function(t) {\r
+ var layout = new log4javascript.SimpleLayout();\r
+ testLayoutWithVariables(layout, t);\r
+ });\r
+\r
+ s.test("SimpleLayout test", function(t) {\r
+ t.appender.setLayout(new log4javascript.SimpleLayout());\r
+ t.logger.debug("TEST");\r
+ t.assertEquals(t.appender.logMessages[0], "DEBUG - TEST");\r
+ });\r
+ s.test("NullLayout format test", function(t) {\r
+ var layout = new log4javascript.NullLayout();\r
+ testLayoutWithVariables(layout, t);\r
+ });\r
+\r
+ s.test("NullLayout test", function(t) {\r
+ t.appender.setLayout(new log4javascript.NullLayout());\r
+ t.logger.debug("TEST");\r
+ t.assertEquals(t.appender.logMessages[0], "TEST");\r
+ });\r
+ s.test("XmlLayout format test", function(t) {\r
+ var layout = new log4javascript.XmlLayout();\r
+ testLayoutWithVariables(layout, t);\r
+ });\r
+\r
+ s.test("XmlLayout test", function(t) {\r
+ t.appender.setLayout(new log4javascript.XmlLayout());\r
+ t.logger.debug("TEST");\r
+ 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]);\r
+ });\r
+\r
+ s.test("XmlLayout with exception test", function(t) {\r
+ t.appender.setLayout(new log4javascript.XmlLayout());\r
+ t.logger.debug("TEST", new Error("Test error"));\r
+ 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]);\r
+ });\r
+\r
+ var setUpXmlLayoutMillisecondsTest = function(t) {\r
+ t.date = new Date();\r
+ t.timeInMilliseconds = t.date.getTime();\r
+ t.timeInSeconds = Math.floor(t.timeInMilliseconds / 1000);\r
+ t.milliseconds = t.date.getMilliseconds();\r
+ \r
+ t.loggingEvent = new log4javascript.LoggingEvent(t.logger, t.date, log4javascript.Level.DEBUG, ["TEST"], null);\r
+ t.layout = new log4javascript.XmlLayout();\r
+ }\r
+\r
+ s.test("XmlLayout seconds/milliseconds test 1", function(t) {\r
+ setUpXmlLayoutMillisecondsTest(t);\r
+\r
+ // Test default (i.e. timestamps in milliseconds) first\r
+ var regex = new RegExp('^<log4javascript:event logger="test" timestamp="' + t.timeInMilliseconds + '" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');\r
+ t.assertRegexMatches(regex, t.layout.format(t.loggingEvent));\r
+ });\r
+ \r
+ s.test("XmlLayout seconds/milliseconds test 2", function(t) {\r
+ setUpXmlLayoutMillisecondsTest(t);\r
+\r
+ // Change the global setting\r
+ log4javascript.setTimeStampsInMilliseconds(false);\r
+ var formatted = t.layout.format(t.loggingEvent);\r
+ log4javascript.setTimeStampsInMilliseconds(true);\r
+ 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*$');\r
+ t.assertRegexMatches(regex, formatted);\r
+ });\r
+\r
+ s.test("XmlLayout seconds/milliseconds test 3", function(t) {\r
+ setUpXmlLayoutMillisecondsTest(t);\r
+\r
+ // Change the layout setting\r
+ t.layout.setTimeStampsInMilliseconds(false);\r
+ var formatted = t.layout.format(t.loggingEvent);\r
+ 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*$');\r
+ t.assertRegexMatches(regex, formatted);\r
+ });\r
+ s.test("escapeNewLines test", function(t) {\r
+ var escapeNewLines = log4javascript.evalInScope("escapeNewLines");\r
+ var str = "1\r2\n3\n4\r\n5\r6\r\n7";\r
+ t.assertEquals(escapeNewLines(str), "1\\r\\n2\\r\\n3\\r\\n4\\r\\n5\\r\\n6\\r\\n7");\r
+ });\r
+\r
+ s.test("JsonLayout format test", function(t) {\r
+ var layout = new log4javascript.JsonLayout();\r
+ testLayoutWithVariables(layout, t);\r
+ });\r
+\r
+ s.test("JsonLayout test", function(t) {\r
+ t.appender.setLayout(new log4javascript.JsonLayout());\r
+ t.logger.debug("TEST");\r
+ t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST"}$/, t.appender.logMessages[0]);\r
+ });\r
+\r
+ s.test("JsonLayout JSON validity test", function(t) {\r
+ t.appender.setLayout(new log4javascript.JsonLayout());\r
+ t.logger.debug("TEST");\r
+ eval("var o = " + t.appender.logMessages[0]);\r
+ t.assertEquals(o.message, "TEST");\r
+ });\r
+\r
+ s.test("JsonLayout with number type message test", function(t) {\r
+ t.appender.setLayout(new log4javascript.JsonLayout());\r
+ t.logger.debug(15);\r
+ t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":15}$/, t.appender.logMessages[0]);\r
+ });\r
+\r
+ s.test("JsonLayout with object type message test", function(t) {\r
+ t.appender.setLayout(new log4javascript.JsonLayout());\r
+ t.logger.debug({});\r
+ t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"\[object Object\]"}$/, t.appender.logMessages[0]);\r
+ });\r
+\r
+ s.test("JsonLayout with boolean type message test", function(t) {\r
+ t.appender.setLayout(new log4javascript.JsonLayout());\r
+ t.logger.debug(false);\r
+ t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":false}$/, t.appender.logMessages[0]);\r
+ });\r
+\r
+ s.test("JsonLayout with quote test", function(t) {\r
+ t.appender.setLayout(new log4javascript.JsonLayout());\r
+ t.logger.debug("TE\"S\"T");\r
+ t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TE\\"S\\"T"}$/, t.appender.logMessages[0]);\r
+ });\r
+\r
+ s.test("JsonLayout with exception test", function(t) {\r
+ t.appender.setLayout(new log4javascript.JsonLayout());\r
+ t.logger.debug("TEST", new Error("Test error"));\r
+ t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST","exception":.*}$/, t.appender.logMessages[0]);\r
+ });\r
+\r
+ var setUpJsonLayoutMillisecondsTest = function(t) {\r
+ t.date = new Date();\r
+ t.timeInMilliseconds = t.date.getTime();\r
+ t.timeInSeconds = Math.floor(t.timeInMilliseconds / 1000);\r
+ t.milliseconds = t.date.getMilliseconds();\r
+ \r
+ t.loggingEvent = new log4javascript.LoggingEvent(t.logger, t.date, log4javascript.Level.DEBUG, ["TEST"], null);\r
+ t.layout = new log4javascript.JsonLayout();\r
+ };\r
+\r
+ s.test("JsonLayout seconds/milliseconds test 1", function(t) {\r
+ setUpJsonLayoutMillisecondsTest(t);\r
+\r
+ // Test default (i.e. timestamps in milliseconds) first\r
+ var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInMilliseconds + ',"level":"DEBUG","url":".*","message":"TEST"}$');\r
+ t.assertRegexMatches(regex, t.layout.format(t.loggingEvent));\r
+ });\r
+ \r
+ s.test("JsonLayout seconds/milliseconds test 2", function(t) {\r
+ setUpJsonLayoutMillisecondsTest(t);\r
+\r
+ // Change the global setting\r
+ log4javascript.setTimeStampsInMilliseconds(false);\r
+ var formatted = t.layout.format(t.loggingEvent);\r
+ log4javascript.setTimeStampsInMilliseconds(true);\r
+ var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInSeconds + ',"level":"DEBUG","url":".*","message":"TEST","milliseconds":' + t.milliseconds + '}$');\r
+ t.assertRegexMatches(regex, formatted);\r
+ });\r
+\r
+ s.test("JsonLayout seconds/milliseconds test 3", function(t) {\r
+ setUpJsonLayoutMillisecondsTest(t);\r
+\r
+ // Change the layout setting\r
+ t.layout.setTimeStampsInMilliseconds(false);\r
+ var formatted = t.layout.format(t.loggingEvent);\r
+ var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInSeconds + ',"level":"DEBUG","url":".*","message":"TEST","milliseconds":' + t.milliseconds + '}$');\r
+ t.assertRegexMatches(regex, formatted);\r
+ });\r
+ s.test("HttpPostDataLayout format test", function(t) {\r
+ var layout = new log4javascript.HttpPostDataLayout();\r
+ testLayoutWithVariables(layout, t);\r
+ });\r
+\r
+ s.test("HttpPostDataLayout test", function(t) {\r
+ t.appender.setLayout(new log4javascript.HttpPostDataLayout());\r
+ t.logger.debug("TEST");\r
+ t.assertRegexMatches(/^logger=test×tamp=\d+&level=DEBUG&url=.*&message=TEST$/, t.appender.logMessages[0]);\r
+ });\r
+\r
+ s.test("HttpPostDataLayout URL encoding test", function(t) {\r
+ t.appender.setLayout(new log4javascript.HttpPostDataLayout());\r
+ t.logger.debug("TEST +\"1\"");\r
+ t.assertRegexMatches(/^logger=test×tamp=\d+&level=DEBUG&url=.*&message=TEST%20%2B%221%22$/, t.appender.logMessages[0]);\r
+ });\r
+\r
+ s.test("HttpPostDataLayout with exception test", function(t) {\r
+ t.appender.setLayout(new log4javascript.HttpPostDataLayout());\r
+ t.logger.debug("TEST", new Error("Test error"));\r
+ t.assertRegexMatches(/^logger=test×tamp=\d+&level=DEBUG&url=.*&message=TEST&exception=.*$/, t.appender.logMessages[0]);\r
+ });\r
+\r
+ (function() {\r
+ var formatObjectExpansion = log4javascript.evalInScope("formatObjectExpansion");\r
+ var newLine = log4javascript.evalInScope("newLine");\r
+ var arr = [\r
+ null,\r
+ undefined,\r
+ 1.2,\r
+ "A string",\r
+ [1, "test"],\r
+ {\r
+ a: {\r
+ b: 1\r
+ }\r
+ }\r
+ ];\r
+\r
+ s.test("Basic formatObjectExpansion array test (depth: 1)", function(t) {\r
+ t.assertEquals(formatObjectExpansion(arr, 1),\r
+ "[" + newLine +\r
+ " null," + newLine +\r
+ " undefined," + newLine +\r
+ " 1.2," + newLine +\r
+ " A string," + newLine +\r
+ " 1,test," + newLine +\r
+ " [object Object]" + newLine +\r
+ "]"\r
+ );\r
+ });\r
+\r
+ s.test("Basic formatObjectExpansion array test (depth: 2)", function(t) {\r
+ t.assertEquals(formatObjectExpansion(arr, 2),\r
+ "[" + newLine +\r
+ " null," + newLine +\r
+ " undefined," + newLine +\r
+ " 1.2," + newLine +\r
+ " A string," + newLine +\r
+ " [" + newLine +\r
+ " 1," + newLine +\r
+ " test" + newLine +\r
+ " ]," + newLine +\r
+ " {" + newLine +\r
+ " a: [object Object]" + newLine +\r
+ " }" + newLine +\r
+ "]"\r
+ );\r
+ });\r
+\r
+ s.test("formatObjectExpansion simple object test", function(t) {\r
+ var obj = {\r
+ STRING: "A string"\r
+ };\r
+ t.assertEquals(formatObjectExpansion(obj, 1), \r
+ "{" + newLine +\r
+ " STRING: A string" + newLine +\r
+ "}"\r
+ );\r
+ });\r
+\r
+ s.test("formatObjectExpansion simple circular object test", function(t) {\r
+ var obj = {};\r
+ obj.a = obj;\r
+ \r
+ t.assertEquals(formatObjectExpansion(obj, 2), \r
+ "{" + newLine +\r
+ " a: [object Object] [already expanded]" + newLine +\r
+ "}"\r
+ );\r
+ });\r
+ })(); /* ---------------------------------------------------------- */\r
+\r
+ var getSampleDate = function() {\r
+ var date = new Date();\r
+ date.setFullYear(2006);\r
+ date.setMonth(7);\r
+ date.setDate(30);\r
+ date.setHours(15);\r
+ date.setMinutes(38);\r
+ date.setSeconds(45);\r
+ return date;\r
+ };\r
+\r
+ /* ---------------------------------------------------------- */\r
+\r
+ s.test("String.replace test", function(t) {\r
+ t.assertEquals("Hello world".replace(/o/g, "Z"), "HellZ wZrld");\r
+ });\r
+\r
+ s.test("PatternLayout format test", function(t) {\r
+ var layout = new log4javascript.PatternLayout();\r
+ testLayoutWithVariables(layout, t);\r
+ });\r
+\r
+ s.test("PatternLayout dates test", function(t) {\r
+ var layout = new log4javascript.PatternLayout("%d %d{DATE} %d{HH:ss}");\r
+ t.appender.setLayout(layout);\r
+ t.logger.debug("TEST");\r
+ 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]);\r
+ });\r
+\r
+ s.test("PatternLayout modifiers test", function(t) {\r
+ var layout = new log4javascript.PatternLayout("%m|%3m|%-3m|%6m|%-6m|%.2m|%1.2m|%6.8m|%-1.2m|%-6.8m|");\r
+ t.appender.setLayout(layout);\r
+ t.logger.debug("TEST");\r
+ t.assertEquals(t.appender.logMessages[0], "TEST|TEST|TEST| TEST|TEST |ST|ST| TEST|ST|TEST |");\r
+ });\r
+\r
+ s.test("PatternLayout conversion characters test", function(t) {\r
+ var layout = new log4javascript.PatternLayout("%c %n %p %r literal %%");\r
+ t.appender.setLayout(layout);\r
+ t.logger.debug("TEST");\r
+ t.assertRegexMatches(/^test \s+ DEBUG \d+ literal %$/, t.appender.logMessages[0]);\r
+ });\r
+\r
+ s.test("PatternLayout message test", function(t) {\r
+ var layout = new log4javascript.PatternLayout("%m{1} %m{2}");\r
+ t.appender.setLayout(layout);\r
+ var testObj = {\r
+ strikers: {\r
+ quick: "Marlon"\r
+ }\r
+ };\r
+ t.logger.debug(testObj);\r
+ t.assertEquals("{\r\n strikers: [object Object]\r\n} {\r\n\ strikers: {\r\n quick: Marlon\r\n }\r\n}", t.appender.logMessages[0]);\r
+ });\r
+ // Tests for exceptions when logging\r
+ s.test("Logging/grouping test", function(t) {\r
+ var browserConsoleAppender = new log4javascript.BrowserConsoleAppender();\r
+ t.logger.addAppender(browserConsoleAppender);\r
+\r
+ // Test each level\r
+ t.logger.trace("TEST TRACE");\r
+ t.logger.debug("TEST DEBUG");\r
+ t.logger.info("TEST INFO");\r
+ t.logger.warn("TEST WARN");\r
+ t.logger.error("TEST ERROR");\r
+ t.logger.fatal("TEST FATAL");\r
+ \r
+ // Test with exception\r
+ t.logger.fatal("TEST FATAL", new Error("Fake error"));\r
+ \r
+ // Test multiple messages\r
+ t.logger.info("TEST INFO", "Second message", ["a", "b", "c"]);\r
+ \r
+ // Test groups\r
+ t.logger.group("TEST GROUP");\r
+ t.logger.info("TEST INFO");\r
+ t.logger.groupEnd("TEST GROUP");\r
+ t.logger.info("TEST INFO");\r
+ \r
+ t.logger.removeAppender(browserConsoleAppender);\r
+ });\r
+\r
+/*\r
+ s.test("AjaxAppender JsonLayout single message test", function(t) {\r
+ t.async(10000);\r
+ // Create and add an Ajax appender\r
+ var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");\r
+ ajaxAppender.setLayout(new log4javascript.JsonLayout());\r
+ ajaxAppender.setRequestSuccessCallback(\r
+ function(xmlHttp) {\r
+ // Response comes back as JSON array of messages logged\r
+ var jsonResponse = xmlHttp.responseText;\r
+ var arr = eval(jsonResponse);\r
+ t.assertEquals(arr.length, 1);\r
+ t.assertEquals(arr[0], "TEST");\r
+ t.succeed();\r
+ }\r
+ );\r
+ ajaxAppender.setFailCallback(\r
+ function(msg) {\r
+ t.fail(msg);\r
+ ajaxErrorMessage = msg;\r
+ }\r
+ );\r
+ t.logger.addAppender(ajaxAppender);\r
+ t.logger.debug("TEST");\r
+ });\r
+\r
+ s.test("AjaxAppender JsonLayout batched messages test", function(t) {\r
+ t.async(10000);\r
+ var message1 = "TEST 1";\r
+ var message2 = "String with \"lots of 'quotes'\" + plusses in";\r
+ var message3 = "A non-threatening string";\r
+ // Create and add an Ajax appender\r
+ var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");\r
+ ajaxAppender.setLayout(new log4javascript.JsonLayout());\r
+ ajaxAppender.setBatchSize(3);\r
+ ajaxAppender.setRequestSuccessCallback(\r
+ function(xmlHttp) {\r
+ // Response comes back as JSON array of messages logged\r
+ var jsonResponse = xmlHttp.responseText;\r
+ var arr = eval(jsonResponse);\r
+ t.assertEquals(arr.length, 3);\r
+ t.assertEquals(arr[0], message1);\r
+ t.assertEquals(arr[1], message2);\r
+ t.assertEquals(arr[2], message3);\r
+ t.succeed();\r
+ }\r
+ );\r
+ ajaxAppender.setFailCallback(\r
+ function(msg) {\r
+ t.fail(msg);\r
+ ajaxErrorMessage = msg;\r
+ }\r
+ );\r
+ t.logger.addAppender(ajaxAppender);\r
+ t.logger.debug(message1);\r
+ t.logger.info(message2);\r
+ t.logger.warn(message3);\r
+ });\r
+\r
+ s.test("AjaxAppender HttpPostDataLayout single message test", function(t) {\r
+ t.async(10000);\r
+ // Create and add an Ajax appender\r
+ var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");\r
+ var testMessage = "TEST +\"1\"";\r
+ ajaxAppender.setLayout(new log4javascript.HttpPostDataLayout());\r
+ ajaxAppender.setRequestSuccessCallback(\r
+ function(xmlHttp) {\r
+ // Response comes back as JSON array of messages logged\r
+ var jsonResponse = xmlHttp.responseText;\r
+ var arr = eval(jsonResponse);\r
+ t.assertEquals(arr.length, 1);\r
+ t.assertEquals(arr[0], testMessage);\r
+ t.succeed();\r
+ }\r
+ );\r
+ ajaxAppender.setFailCallback(\r
+ function(msg) {\r
+ t.fail(msg);\r
+ ajaxErrorMessage = msg;\r
+ }\r
+ );\r
+ t.logger.addAppender(ajaxAppender);\r
+ t.logger.debug(testMessage);\r
+ });\r
+*/\r
+ var testConsoleAppender = function(t, appender) {\r
+ var timeoutCallback = function() {\r
+ //alert("Failed. Debug messages follow.");\r
+ //log4javascript.logLog.displayDebug();\r
+ return (windowLoaded ? "Timed out while waiting for messages to appear" :\r
+ "Timed out while waiting for window to load") + ". Debug messages: " +\r
+ log4javascript.logLog.debugMessages.join("\r\n");\r
+ }\r
+\r
+ t.async(60000, timeoutCallback);\r
+\r
+ var windowLoaded = false;\r
+ var domChecked = false;\r
+\r
+ // Set a timeout to allow the pop-up to appear\r
+ var onLoadHandler = function() {\r
+ log4javascript.logLog.debug("onLoadHandler");\r
+ windowLoaded = true;\r
+ var win = appender.getConsoleWindow();\r
+\r
+ if (win && win.loaded) {\r
+ // Check that the log container element contains the log message. Since\r
+ // the console window waits 100 milliseconds before actually rendering the\r
+ // message as a DOM element, we need to use a timer\r
+ var checkDom = function() {\r
+ log4javascript.logLog.debug("checkDom");\r
+ domChecked = true;\r
+ var logContainer = win.logMainContainer;\r
+ if (logContainer.hasChildNodes()) {\r
+ if (logContainer.innerHTML.indexOf("TEST MESSAGE") == -1) {\r
+ appender.close();\r
+ t.fail("Log message not correctly logged (log container innerHTML: " + logContainer.innerHTML + ")");\r
+ } else {\r
+ t.assert(appender.isVisible());\r
+ appender.close();\r
+ t.assert(!appender.isVisible());\r
+ t.succeed();\r
+ }\r
+ } else {\r
+ appender.close();\r
+ t.fail("Console has no log messages");\r
+ }\r
+ }\r
+ window.setTimeout(checkDom, 300);\r
+ } else {\r
+ appender.close();\r
+ t.fail("Console mistakenly raised load event");\r
+ }\r
+ }\r
+\r
+ appender.addEventListener("load", onLoadHandler);\r
+ t.logger.addAppender(appender);\r
+ t.logger.debug("TEST MESSAGE");\r
+ };\r
+\r
+ s.test("InlineAppender test", function(t) {\r
+ var inlineAppender = new log4javascript.InlineAppender();\r
+ inlineAppender.setInitiallyMinimized(false);\r
+ inlineAppender.setNewestMessageAtTop(false);\r
+ inlineAppender.setScrollToLatestMessage(true);\r
+ inlineAppender.setWidth(600);\r
+ inlineAppender.setHeight(200);\r
+\r
+ testConsoleAppender(t, inlineAppender);\r
+ });\r
+\r
+ s.test("InPageAppender with separate console HTML file test", function(t) {\r
+ var inPageAppender = new log4javascript.InPageAppender();\r
+ inPageAppender.setInitiallyMinimized(false);\r
+ inPageAppender.setNewestMessageAtTop(false);\r
+ inPageAppender.setScrollToLatestMessage(true);\r
+ inPageAppender.setUseDocumentWrite(false);\r
+ inPageAppender.setWidth(600);\r
+ inPageAppender.setHeight(200);\r
+\r
+ testConsoleAppender(t, inPageAppender);\r
+ });\r
+\r
+ s.test("PopUpAppender test", function(t) {\r
+ var popUpAppender = new log4javascript.PopUpAppender();\r
+ popUpAppender.setFocusPopUp(true);\r
+ popUpAppender.setUseOldPopUp(false);\r
+ popUpAppender.setNewestMessageAtTop(false);\r
+ popUpAppender.setScrollToLatestMessage(true);\r
+ popUpAppender.setComplainAboutPopUpBlocking(false);\r
+ popUpAppender.setWidth(600);\r
+ popUpAppender.setHeight(200);\r
+\r
+ testConsoleAppender(t, popUpAppender);\r
+ \r
+ \r
+ });\r
+\r
+ s.test("PopUpAppender with separate console HTML file test", function(t) {\r
+ var popUpAppender = new log4javascript.PopUpAppender();\r
+ popUpAppender.setFocusPopUp(true);\r
+ popUpAppender.setUseOldPopUp(false);\r
+ popUpAppender.setNewestMessageAtTop(false);\r
+ popUpAppender.setScrollToLatestMessage(true);\r
+ popUpAppender.setComplainAboutPopUpBlocking(false);\r
+ popUpAppender.setUseDocumentWrite(false);\r
+ popUpAppender.setWidth(600);\r
+ popUpAppender.setHeight(200);\r
+\r
+ testConsoleAppender(t, popUpAppender);\r
+ });\r
+});
\ No newline at end of file
--- /dev/null
+ Apache License\r
+ Version 2.0, January 2004\r
+ http://www.apache.org/licenses/\r
+\r
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r
+\r
+ 1. Definitions.\r
+\r
+ "License" shall mean the terms and conditions for use, reproduction,\r
+ and distribution as defined by Sections 1 through 9 of this document.\r
+\r
+ "Licensor" shall mean the copyright owner or entity authorized by\r
+ the copyright owner that is granting the License.\r
+\r
+ "Legal Entity" shall mean the union of the acting entity and all\r
+ other entities that control, are controlled by, or are under common\r
+ control with that entity. For the purposes of this definition,\r
+ "control" means (i) the power, direct or indirect, to cause the\r
+ direction or management of such entity, whether by contract or\r
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the\r
+ outstanding shares, or (iii) beneficial ownership of such entity.\r
+\r
+ "You" (or "Your") shall mean an individual or Legal Entity\r
+ exercising permissions granted by this License.\r
+\r
+ "Source" form shall mean the preferred form for making modifications,\r
+ including but not limited to software source code, documentation\r
+ source, and configuration files.\r
+\r
+ "Object" form shall mean any form resulting from mechanical\r
+ transformation or translation of a Source form, including but\r
+ not limited to compiled object code, generated documentation,\r
+ and conversions to other media types.\r
+\r
+ "Work" shall mean the work of authorship, whether in Source or\r
+ Object form, made available under the License, as indicated by a\r
+ copyright notice that is included in or attached to the work\r
+ (an example is provided in the Appendix below).\r
+\r
+ "Derivative Works" shall mean any work, whether in Source or Object\r
+ form, that is based on (or derived from) the Work and for which the\r
+ editorial revisions, annotations, elaborations, or other modifications\r
+ represent, as a whole, an original work of authorship. For the purposes\r
+ of this License, Derivative Works shall not include works that remain\r
+ separable from, or merely link (or bind by name) to the interfaces of,\r
+ the Work and Derivative Works thereof.\r
+\r
+ "Contribution" shall mean any work of authorship, including\r
+ the original version of the Work and any modifications or additions\r
+ to that Work or Derivative Works thereof, that is intentionally\r
+ submitted to Licensor for inclusion in the Work by the copyright owner\r
+ or by an individual or Legal Entity authorized to submit on behalf of\r
+ the copyright owner. For the purposes of this definition, "submitted"\r
+ means any form of electronic, verbal, or written communication sent\r
+ to the Licensor or its representatives, including but not limited to\r
+ communication on electronic mailing lists, source code control systems,\r
+ and issue tracking systems that are managed by, or on behalf of, the\r
+ Licensor for the purpose of discussing and improving the Work, but\r
+ excluding communication that is conspicuously marked or otherwise\r
+ designated in writing by the copyright owner as "Not a Contribution."\r
+\r
+ "Contributor" shall mean Licensor and any individual or Legal Entity\r
+ on behalf of whom a Contribution has been received by Licensor and\r
+ subsequently incorporated within the Work.\r
+\r
+ 2. Grant of Copyright License. Subject to the terms and conditions of\r
+ this License, each Contributor hereby grants to You a perpetual,\r
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
+ copyright license to reproduce, prepare Derivative Works of,\r
+ publicly display, publicly perform, sublicense, and distribute the\r
+ Work and such Derivative Works in Source or Object form.\r
+\r
+ 3. Grant of Patent License. Subject to the terms and conditions of\r
+ this License, each Contributor hereby grants to You a perpetual,\r
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
+ (except as stated in this section) patent license to make, have made,\r
+ use, offer to sell, sell, import, and otherwise transfer the Work,\r
+ where such license applies only to those patent claims licensable\r
+ by such Contributor that are necessarily infringed by their\r
+ Contribution(s) alone or by combination of their Contribution(s)\r
+ with the Work to which such Contribution(s) was submitted. If You\r
+ institute patent litigation against any entity (including a\r
+ cross-claim or counterclaim in a lawsuit) alleging that the Work\r
+ or a Contribution incorporated within the Work constitutes direct\r
+ or contributory patent infringement, then any patent licenses\r
+ granted to You under this License for that Work shall terminate\r
+ as of the date such litigation is filed.\r
+\r
+ 4. Redistribution. You may reproduce and distribute copies of the\r
+ Work or Derivative Works thereof in any medium, with or without\r
+ modifications, and in Source or Object form, provided that You\r
+ meet the following conditions:\r
+\r
+ (a) You must give any other recipients of the Work or\r
+ Derivative Works a copy of this License; and\r
+\r
+ (b) You must cause any modified files to carry prominent notices\r
+ stating that You changed the files; and\r
+\r
+ (c) You must retain, in the Source form of any Derivative Works\r
+ that You distribute, all copyright, patent, trademark, and\r
+ attribution notices from the Source form of the Work,\r
+ excluding those notices that do not pertain to any part of\r
+ the Derivative Works; and\r
+\r
+ (d) If the Work includes a "NOTICE" text file as part of its\r
+ distribution, then any Derivative Works that You distribute must\r
+ include a readable copy of the attribution notices contained\r
+ within such NOTICE file, excluding those notices that do not\r
+ pertain to any part of the Derivative Works, in at least one\r
+ of the following places: within a NOTICE text file distributed\r
+ as part of the Derivative Works; within the Source form or\r
+ documentation, if provided along with the Derivative Works; or,\r
+ within a display generated by the Derivative Works, if and\r
+ wherever such third-party notices normally appear. The contents\r
+ of the NOTICE file are for informational purposes only and\r
+ do not modify the License. You may add Your own attribution\r
+ notices within Derivative Works that You distribute, alongside\r
+ or as an addendum to the NOTICE text from the Work, provided\r
+ that such additional attribution notices cannot be construed\r
+ as modifying the License.\r
+\r
+ You may add Your own copyright statement to Your modifications and\r
+ may provide additional or different license terms and conditions\r
+ for use, reproduction, or distribution of Your modifications, or\r
+ for any such Derivative Works as a whole, provided Your use,\r
+ reproduction, and distribution of the Work otherwise complies with\r
+ the conditions stated in this License.\r
+\r
+ 5. Submission of Contributions. Unless You explicitly state otherwise,\r
+ any Contribution intentionally submitted for inclusion in the Work\r
+ by You to the Licensor shall be under the terms and conditions of\r
+ this License, without any additional terms or conditions.\r
+ Notwithstanding the above, nothing herein shall supersede or modify\r
+ the terms of any separate license agreement you may have executed\r
+ with Licensor regarding such Contributions.\r
+\r
+ 6. Trademarks. This License does not grant permission to use the trade\r
+ names, trademarks, service marks, or product names of the Licensor,\r
+ except as required for reasonable and customary use in describing the\r
+ origin of the Work and reproducing the content of the NOTICE file.\r
+\r
+ 7. Disclaimer of Warranty. Unless required by applicable law or\r
+ agreed to in writing, Licensor provides the Work (and each\r
+ Contributor provides its Contributions) on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r
+ implied, including, without limitation, any warranties or conditions\r
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r
+ PARTICULAR PURPOSE. You are solely responsible for determining the\r
+ appropriateness of using or redistributing the Work and assume any\r
+ risks associated with Your exercise of permissions under this License.\r
+\r
+ 8. Limitation of Liability. In no event and under no legal theory,\r
+ whether in tort (including negligence), contract, or otherwise,\r
+ unless required by applicable law (such as deliberate and grossly\r
+ negligent acts) or agreed to in writing, shall any Contributor be\r
+ liable to You for damages, including any direct, indirect, special,\r
+ incidental, or consequential damages of any character arising as a\r
+ result of this License or out of the use or inability to use the\r
+ Work (including but not limited to damages for loss of goodwill,\r
+ work stoppage, computer failure or malfunction, or any and all\r
+ other commercial damages or losses), even if such Contributor\r
+ has been advised of the possibility of such damages.\r
+\r
+ 9. Accepting Warranty or Additional Liability. While redistributing\r
+ the Work or Derivative Works thereof, You may choose to offer,\r
+ and charge a fee for, acceptance of support, warranty, indemnity,\r
+ or other liability obligations and/or rights consistent with this\r
+ License. However, in accepting such obligations, You may act only\r
+ on Your own behalf and on Your sole responsibility, not on behalf\r
+ of any other Contributor, and only if You agree to indemnify,\r
+ defend, and hold each Contributor harmless for any liability\r
+ incurred by, or claims asserted against, such Contributor by reason\r
+ of your accepting any such warranty or additional liability.\r
+\r
+ END OF TERMS AND CONDITIONS\r
+\r
+ APPENDIX: How to apply the Apache License to your work.\r
+\r
+ To apply the Apache License to your work, attach the following\r
+ boilerplate notice, with the fields enclosed by brackets "[]"\r
+ replaced with your own identifying information. (Don't include\r
+ the brackets!) The text should be enclosed in the appropriate\r
+ comment syntax for the file format. We also recommend that a\r
+ file or class name and description of purpose be included on the\r
+ same "printed page" as the copyright notice for easier\r
+ identification within third-party archives.\r
+\r
+ Copyright [yyyy] [name of copyright owner]\r
+\r
+ Licensed under the Apache License, Version 2.0 (the "License");\r
+ you may not use this file except in compliance with the License.\r
+ You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
--- /dev/null
+/**\r
+ * Copyright 2013 Tim Down.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+\r
+if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}\r
+return this.length;};}\r
+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];}\r
+this.length=this.length-1;return firstItem;}};}\r
+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];}\r
+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]);}\r
+return itemsDeleted;};}\r
+var log4javascript=(function(){function isUndefined(obj){return typeof obj=="undefined";}\r
+function EventSupport(){}\r
+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+"'");}\r
+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+"'");}\r
+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()+"_"+\r
+Math.floor(Math.random()*100000000);var emptyFunction=function(){};var newLine="\r\n";var pageLoaded=false;function Log4JavaScript(){}\r
+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);}}\r
+function getExceptionMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}else{return toStr(ex);}}\r
+function getUrlFileName(url){var lastSlashIndex=Math.max(url.lastIndexOf("/"),url.lastIndexOf("\\"));return url.substr(lastSlashIndex+1);}\r
+function getExceptionStringRep(ex){if(ex){var exStr="Exception: "+getExceptionMessage(ex);try{if(ex.lineNumber){exStr+=" on line number "+ex.lineNumber;}\r
+if(ex.fileName){exStr+=" in file "+getUrlFileName(ex.fileName);}}catch(localEx){logLog.warn("Unable to obtain file and line information for error");}\r
+if(showStackTraces&&ex.stack){exStr+=newLine+"Stack trace:"+newLine+ex.stack;}\r
+return exStr;}\r
+return null;}\r
+function bool(obj){return Boolean(obj);}\r
+function trim(str){return str.replace(/^\s+/,"").replace(/\s+$/,"");}\r
+function splitIntoLines(text){var text2=text.replace(/\r\n/g,"\n").replace(/\r/g,"\n");return text2.split("\n");}\r
+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;}}\r
+if(index>=0){arr.splice(index,1);return true;}else{return false;}}\r
+function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}\r
+return false;}\r
+function extractBooleanFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return bool(param);}}\r
+function extractStringFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return String(param);}}\r
+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;}}}\r
+function extractFunctionFromParam(param,defaultValue){if(typeof param=="function"){return param;}else{return defaultValue;}}\r
+function isError(err){return(err instanceof Error);}\r
+if(!Function.prototype.apply){Function.prototype.apply=function(obj,args){var methodName="__apply__";if(typeof obj[methodName]!="undefined"){methodName+=String(Math.random()).substr(2);}\r
+obj[methodName]=this;var argsStrings=[];for(var i=0,len=args.length;i<len;i++){argsStrings[i]="args["+i+"]";}\r
+var script="obj."+methodName+"("+argsStrings.join(",")+")";var returnValue=eval(script);delete obj[methodName];return returnValue;};}\r
+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];}\r
+return this.apply(obj,args);};}\r
+function getListenersPropertyName(eventName){return"__log4javascript_listeners__"+eventName;}\r
+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);}};}\r
+node[propertyName].push(listener);}}\r
+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);}}}\r
+function getEvent(evt,win){win=win?win:window;return evt?evt:win.event;}\r
+function stopEventPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}\r
+evt.returnValue=false;}\r
+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);}\r
+alert(alertMessage);}}}};log4javascript.logLog=logLog;log4javascript.setEventTypes(["load","error"]);function handleError(message,exception){logLog.error(message,exception);log4javascript.dispatchEvent("error",{"message":message,"exception":exception});}\r
+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();}\r
+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 ('"+\r
+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);}\r
+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;}\r
+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--;}\r
+var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];}\r
+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 "+\r
+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 "+\r
+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]);}\r
+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+"]";};}\r
+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 "+\r
+toStr(loggerName)+" supplied, returning anonymous logger");}\r
+if(loggerName==rootLoggerName){handleError("log4javascript.getLogger: root logger may not be obtained by name");}\r
+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;}\r
+parentLogger.addChild(logger);}\r
+return loggers[loggerName];};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=log4javascript.getLogger(defaultLoggerName);var a=new log4javascript.PopUpAppender();defaultLogger.addAppender(a);}\r
+return defaultLogger;};var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger(nullLoggerName);nullLogger.setLevel(Level.OFF);}\r
+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]);}\r
+if(loggingEvent.exception){dataValues.push([this.exceptionKey,getExceptionStringRep(loggingEvent.exception)]);}\r
+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);}\r
+dataValues.push([this.customFields[i].name,val]);}}\r
+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;}}\r
+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 "+\r
+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 "+\r
+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=[];}\r
+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=[];}\r
+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=[];}\r
+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(/\]\]>/,"]]>]]><![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["+\r
+layout.escapeCdata(message)+"]]></log4javascript:message>";}\r
+var str="<log4javascript:event logger=\""+loggingEvent.logger.name+"\" timestamp=\""+this.getTimeStampValue(loggingEvent)+"\"";if(!this.isTimeStampsInMilliseconds()){str+=" milliseconds=\""+loggingEvent.milliseconds+"\"";}\r
+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;}\r
+str+="</log4javascript:messages>"+newLine;}\r
+if(this.hasCustomFields()){for(i=0,len=this.customFields.length;i<len;i++){str+="<log4javascript:customfield name=\""+\r
+this.customFields[i].name+"\"><![CDATA["+\r
+this.customFields[i].value.toString()+"]]></log4javascript:customfield>"+newLine;}}\r
+if(loggingEvent.exception){str+="<log4javascript:exception><![CDATA["+\r
+getExceptionStringRep(loggingEvent.exception)+"]]></log4javascript:exception>"+newLine;}\r
+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");}\r
+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=[];}\r
+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+=",";}\r
+formattedValue+=layout.lineBreak;}\r
+formattedValue+=prefix+"]";}else if(valType!=="number"&&valType!=="boolean"){formattedValue="\""+escapeNewLines(toStr(val).replace(/\"/g,"\\\""))+"\"";}else{formattedValue=val;}\r
+return formattedValue;}\r
+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+=",";}\r
+str+=this.lineBreak;}\r
+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;}\r
+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));}\r
+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="";}\r
+function formatString(text){var lines=splitIntoLines(text);for(var j=1,jLen=lines.length;j<jLen;j++){lines[j]=indentation+lines[j];}\r
+return lines.join(newLine);}\r
+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);}\r
+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: "+\r
+getExceptionStringRep(ex)+"");}}\r
+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: "+\r
+getExceptionStringRep(ex));}}\r
+expansion+=childLines.join(","+newLine)+newLine+indentation+"}";return expansion;}else{return formatString(toStr(obj));}}\r
+return doFormat(obj,depth,indentation);}\r
+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;}\r
+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--;}\r
+return weekInYear;};Date.prototype.getWeekInMonth=function(minimalDaysInFirstWeek){if(isUndefined(this.minimalDaysInFirstWeek)){minimalDaysInFirstWeek=DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;}\r
+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++;}\r
+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;}\r
+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;}\r
+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);}\r
+break;case MONTH:if(numberOfLetters>=3){formattedString+=formatText(monthNames[rawData],numberOfLetters,numberOfLetters);}else{formattedString+=formatNumber(rawData+1,numberOfLetters);}\r
+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;}}\r
+searchString=searchString.substr(result.index+result[0].length);}\r
+return formattedString;};})();log4javascript.SimpleDateFormat=SimpleDateFormat;function PatternLayout(pattern){if(pattern){this.pattern=pattern;}else{this.pattern=PatternLayout.DEFAULT_CONVERSION_PATTERN;}\r
+this.customFields=[];}\r
+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 '"+\r
+specifier+"' for conversion character '"+conversionCharacter+"' - should be a number");depth=0;}}\r
+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+=" ";}\r
+if(depth===0){replacement+=messages[i];}else{replacement+=formatObjectExpansion(messages[i],depth);}}\r
+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;}\r
+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;}}\r
+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 '"+\r
+specifier+"' for conversion character 'f' - should be a number");}else if(fieldIndex===0){handleError("PatternLayout.format: invalid specifier '"+\r
+specifier+"' for conversion character 'f' - must be greater than zero");}else if(fieldIndex>this.customFields.length){handleError("PatternLayout.format: invalid specifier '"+\r
+specifier+"' for conversion character 'f' - there aren't that many custom fields");}else{fieldIndex=fieldIndex-1;}}\r
+var val=this.customFields[fieldIndex].value;if(typeof val=="function"){val=val(this,loggingEvent);}\r
+replacement=val;}\r
+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;}\r
+var l;if(truncation){l=parseInt(truncation.substr(1),10);var strLen=replacement.length;if(l<strLen){replacement=replacement.substring(strLen-l,strLen);}}\r
+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;}}}\r
+formattedString+=replacement;}\r
+searchString=searchString.substr(result.index+result[0].length);}\r
+return formattedString;};PatternLayout.prototype.ignoresThrowable=function(){return true;};PatternLayout.prototype.toString=function(){return"PatternLayout";};log4javascript.PatternLayout=PatternLayout;function AlertAppender(){}\r
+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();}\r
+alert(formattedMessage);};AlertAppender.prototype.toString=function(){return"AlertAppender";};log4javascript.AlertAppender=AlertAppender;function BrowserConsoleAppender(){}\r
+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();}\r
+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){}}\r
+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;}\r
+function AjaxAppender(url){var appender=this;var isSupported=true;if(!url){handleError("AjaxAppender: URL must be specified in constructor");isSupported=false;}\r
+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 '"+\r
+configOptionName+"' may not be set after the appender has been initialized");return false;}\r
+return true;}\r
+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));}\r
+sending=false;if(timed){scheduleSending();}}}}\r
+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=[];}}\r
+if(batchedLoggingEvents.length>0){queuedRequests.push(batchedLoggingEvents);}\r
+sendingAnything=(queuedRequests.length>0);waitForResponse=false;timed=false;sendAll();}\r
+return sendingAnything;}\r
+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();}\r
+formattedMessages.push(currentFormattedMessage);}\r
+if(batchedLoggingEvents.length==1){postData=formattedMessages.join("");}else{postData=appender.getLayout().batchHeader+\r
+formattedMessages.join(appender.getLayout().batchSeparator)+\r
+appender.getLayout().batchFooter;}\r
+if(contentType==appender.defaults.contentType){postData=appender.getLayout().returnsPostData?postData:urlEncode(postVarName)+"="+urlEncode(postData);if(postData.length>0){postData+="&";}\r
+postData+="layout="+urlEncode(appender.getLayout().toString());}\r
+return postData;}\r
+function scheduleSending(){window.setTimeout(sendAll,timerInterval);}\r
+function xmlHttpErrorHandler(){var msg="AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}}\r
+function sendRequest(postData,successCallback){try{var xmlHttp=getXmlHttp(xmlHttpErrorHandler);if(isSupported){if(xmlHttp.overrideMimeType){xmlHttp.overrideMimeType(appender.getLayout().getContentType());}\r
+xmlHttp.onreadystatechange=function(){if(xmlHttp.readyState==4){if(isHttpRequestSuccessful(xmlHttp)){if(requestSuccessCallback){requestSuccessCallback(xmlHttp);}\r
+if(successCallback){successCallback(xmlHttp);}}else{var msg="AjaxAppender.append: XMLHttpRequest request to URL "+\r
+url+" returned status code "+xmlHttp.status;handleError(msg);if(failCallback){failCallback(msg);}}\r
+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);}\r
+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);}\r
+return;}\r
+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));}}}\r
+this.append=function(loggingEvent){if(isSupported){if(!initialized){init();}\r
+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);}\r
+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();}\r
+if(sendAllRemaining()){return"Sending log messages";}};}\r
+if(timed){scheduleSending();}}}\r
+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="";}\r
+document.cookie=escape(name)+"="+escape(value)+expires+path;}\r
+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);}\r
+if(c.indexOf(nameEquals)===0){return unescape(c.substring(nameEquals.length,c.length));}}\r
+return null;}\r
+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);}}\r
+return null;}\r
+function isLoaded(win){try{return bool(win.loaded);}catch(ex){return false;}}\r
+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=" ";}','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&¤tSearch.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&¤tEl!=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&¤tSearch.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!=="")&¤tSearch&¤tSearch.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&¤tMatchIndex!==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&¤tMatchIndex!==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,"&").replace(/[<]/g,"<").replace(/>/g,">");}','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;}\r
+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;}\r
+QueuedLoggingEvent.prototype.append=function(){getConsoleWindow().log(this.levelName,this.formattedMessage);};function QueuedGroup(name,initiallyExpanded){this.name=name;this.initiallyExpanded=initiallyExpanded;}\r
+QueuedGroup.prototype.append=function(){getConsoleWindow().group(this.name,this.initiallyExpanded);};function QueuedGroupEnd(){}\r
+QueuedGroupEnd.prototype.append=function(){getConsoleWindow().groupEnd();};var checkAndAppend=function(){safeToAppend();if(!initialized){init();}else if(consoleClosed&&reopenWhenClosed){createWindow();}\r
+if(safeToAppend()){appendQueuedLoggingEvents();}};this.append=function(loggingEvent){if(isSupported){var formattedMessage=appender.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();}\r
+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();}\r
+if(focusConsoleWindow){getConsoleWindow().focus();}};this.setAddedToLogger=function(logger){this.loggers.push(logger);if(enabled&&!lazyInit){init();}};this.clear=function(){if(consoleWindowExists()){getConsoleWindow().clearLog();}\r
+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");}\r
+var commandLineFunctionsHash={};for(i=0,len=commandLineFunctions.length;i<len;i++){commandLineFunctionsHash[commandLineFunctions[i][0]]=commandLineFunctions[i][1];}\r
+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]);}\r
+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);}\r
+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;}\r
+if(commandReturnValue.appendResult){var message=">>> "+expr;if(!isUndefined(commandOutput)){message+=newLine+commandOutput;}\r
+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]);}\r
+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;}\r
+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);}\r
+if(windowTest(getConsoleWindow())){clearInterval(poll);successCallback();}}catch(ex){clearInterval(poll);isSupported=false;handleError(errorMessage,ex);}}\r
+var poll=setInterval(doPoll,interval);};var getConsoleUrl=function(){var documentDomainSet=(document.domain!=location.hostname);return useDocumentWrite?"":getBaseUrl()+"console.html"+\r
+(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();}\r
+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();}\r
+consoleWindowLoadHandler();consoleWindowLoaded=true;appendQueuedLoggingEvents();}catch(ex){isSupported=false;handleError(initErrorMessage,ex);}}\r
+function writeToDocument(){try{var windowTest=function(win){return isLoaded(win);};if(useDocumentWrite){writeHtml(getConsoleWindow().document);}\r
+if(windowTest(getConsoleWindow())){finalInit();}else{pollConsoleWindow(windowTest,100,finalInit,initErrorMessage);}}catch(ex){isSupported=false;handleError(initErrorMessage,ex);}}\r
+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];}\r
+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);}\r
+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;}\r
+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);}\r
+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;}\r
+return consoleWindowLoaded;}\r
+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";}\r
+var windowName="PopUp_"+location.host.replace(/[^a-z0-9]/gi,"_")+"_"+consoleAppenderId+frameInfo;if(!useOldPopUp||!useDocumentWrite){windowName=windowName+"_"+uniqueId;}\r
+var checkPopUpClosed=function(win){if(consoleClosed){return true;}else{try{return bool(win)&&win.closed;}catch(ex){}}\r
+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");}\r
+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);}\r
+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;}\r
+if(!consoleWindowLoaded&&isLoaded(popUp)){consoleWindowLoaded=true;}}\r
+return isSupported&&consoleWindowLoaded&&!consoleClosed;};}\r
+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);}\r
+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);}\r
+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]=" ";}\r
+str+=spaces.join("");}\r
+return str;}\r
+(function(){function dir(obj){var maxLen=0;for(var p in obj){maxLen=Math.max(toStr(p).length,maxLen);}\r
+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)+"]";}\r
+propList.push(propNameStr+propVal);}\r
+return propList.join(newLine);}\r
+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="";}\r
+startNewLine=!!startNewLine;preformatted=!!preformatted;var xhtml;function isWhitespace(node){return((node.nodeType==nodeTypes.TEXT_NODE)&&/^[ \t\r\n]*$/.test(node.nodeValue));}\r
+function fixAttributeValue(attrValue){return attrValue.toString().replace(/&/g,"&").replace(/</g,"<").replace(/"/g,""");}\r
+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]));}\r
+styleValue=props.join(";");}\r
+return styleValue;}\r
+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();}}\r
+return"";}\r
+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+":";}\r
+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;}\r
+xhtml+=" "+currentAttr.nodeName.toLowerCase()+"=\"";xhtml+=fixAttributeValue(currentAttr.nodeValue);xhtml+="\"";}\r
+if(rootNode.style.cssText){var styleValue=getStyleAttributeValue(rootNode);if(styleValue!==""){xhtml+=" style=\""+getStyleAttributeValue(rootNode)+"\"";}}\r
+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);}\r
+var endTag=lt+"/"+tagName+gt;xhtml+=childStartNewLine?newLine+indentation+endTag:endTag;}\r
+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]);}\r
+xhtml=trimmedLines.join(newLine+indentation);}\r
+if(startNewLine){xhtml=newLine+indentation+xhtml;}}\r
+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);}\r
+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);}\r
+return xhtml;}}\r
+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]);}\r
+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]);}\r
+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();}}}\r
+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);}\r
+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));}}\r
+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;}});}\r
+function init(){createCommandLineFunctions();}\r
+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);}\r
+log4javascript.setDocumentReady();};}}\r
+window.log4javascript=log4javascript;return log4javascript;})();\r
--- /dev/null
+/**\r
+ * Copyright 2013 Tim Down.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/**\r
+ * log4javascript\r
+ *\r
+ * log4javascript is a logging framework for JavaScript based on log4j\r
+ * for Java. This file contains all core log4javascript code and is the only\r
+ * file required to use log4javascript, unless you require support for\r
+ * document.domain, in which case you will also need console.html, which must be\r
+ * stored in the same directory as the main log4javascript.js file.\r
+ *\r
+ * Author: Tim Down <tim@log4javascript.org>\r
+ * Version: 1.4.6\r
+ * Edition: log4javascript\r
+ * Build date: 19 March 2013\r
+ * Website: http://log4javascript.org\r
+ */\r
+\r
+/* -------------------------------------------------------------------------- */\r
+// Array-related stuff\r
+\r
+// Next three methods are solely for IE5, which is missing them\r
+if (!Array.prototype.push) {\r
+ Array.prototype.push = function() {\r
+ for (var i = 0, len = arguments.length; i < len; i++){\r
+ this[this.length] = arguments[i];\r
+ }\r
+ return this.length;\r
+ };\r
+}\r
+\r
+if (!Array.prototype.shift) {\r
+ Array.prototype.shift = function() {\r
+ if (this.length > 0) {\r
+ var firstItem = this[0];\r
+ for (var i = 0, len = this.length - 1; i < len; i++) {\r
+ this[i] = this[i + 1];\r
+ }\r
+ this.length = this.length - 1;\r
+ return firstItem;\r
+ }\r
+ };\r
+}\r
+\r
+if (!Array.prototype.splice) {\r
+ Array.prototype.splice = function(startIndex, deleteCount) {\r
+ var itemsAfterDeleted = this.slice(startIndex + deleteCount);\r
+ var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);\r
+ this.length = startIndex;\r
+ // Copy the arguments into a proper Array object\r
+ var argumentsArray = [];\r
+ for (var i = 0, len = arguments.length; i < len; i++) {\r
+ argumentsArray[i] = arguments[i];\r
+ }\r
+ var itemsToAppend = (argumentsArray.length > 2) ?\r
+ itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;\r
+ for (i = 0, len = itemsToAppend.length; i < len; i++) {\r
+ this.push(itemsToAppend[i]);\r
+ }\r
+ return itemsDeleted;\r
+ };\r
+}\r
+\r
+/* -------------------------------------------------------------------------- */\r
+\r
+var log4javascript = (function() {\r
+\r
+ function isUndefined(obj) {\r
+ return typeof obj == "undefined";\r
+ }\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Custom event support\r
+\r
+ function EventSupport() {}\r
+\r
+ EventSupport.prototype = {\r
+ eventTypes: [],\r
+ eventListeners: {},\r
+ setEventTypes: function(eventTypesParam) {\r
+ if (eventTypesParam instanceof Array) {\r
+ this.eventTypes = eventTypesParam;\r
+ this.eventListeners = {};\r
+ for (var i = 0, len = this.eventTypes.length; i < len; i++) {\r
+ this.eventListeners[this.eventTypes[i]] = [];\r
+ }\r
+ } else {\r
+ handleError("log4javascript.EventSupport [" + this + "]: setEventTypes: eventTypes parameter must be an Array");\r
+ }\r
+ },\r
+\r
+ addEventListener: function(eventType, listener) {\r
+ if (typeof listener == "function") {\r
+ if (!array_contains(this.eventTypes, eventType)) {\r
+ handleError("log4javascript.EventSupport [" + this + "]: addEventListener: no event called '" + eventType + "'");\r
+ }\r
+ this.eventListeners[eventType].push(listener);\r
+ } else {\r
+ handleError("log4javascript.EventSupport [" + this + "]: addEventListener: listener must be a function");\r
+ }\r
+ },\r
+\r
+ removeEventListener: function(eventType, listener) {\r
+ if (typeof listener == "function") {\r
+ if (!array_contains(this.eventTypes, eventType)) {\r
+ handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: no event called '" + eventType + "'");\r
+ }\r
+ array_remove(this.eventListeners[eventType], listener);\r
+ } else {\r
+ handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: listener must be a function");\r
+ }\r
+ },\r
+\r
+ dispatchEvent: function(eventType, eventArgs) {\r
+ if (array_contains(this.eventTypes, eventType)) {\r
+ var listeners = this.eventListeners[eventType];\r
+ for (var i = 0, len = listeners.length; i < len; i++) {\r
+ listeners[i](this, eventType, eventArgs);\r
+ }\r
+ } else {\r
+ handleError("log4javascript.EventSupport [" + this + "]: dispatchEvent: no event called '" + eventType + "'");\r
+ }\r
+ }\r
+ };\r
+\r
+ /* -------------------------------------------------------------------------- */\r
+\r
+ var applicationStartDate = new Date();\r
+ var uniqueId = "log4javascript_" + applicationStartDate.getTime() + "_" +\r
+ Math.floor(Math.random() * 100000000);\r
+ var emptyFunction = function() {};\r
+ var newLine = "\r\n";\r
+ var pageLoaded = false;\r
+\r
+ // Create main log4javascript object; this will be assigned public properties\r
+ function Log4JavaScript() {}\r
+ Log4JavaScript.prototype = new EventSupport();\r
+\r
+ log4javascript = new Log4JavaScript();\r
+ log4javascript.version = "1.4.6";\r
+ log4javascript.edition = "log4javascript";\r
+\r
+ /* -------------------------------------------------------------------------- */\r
+ // Utility functions\r
+\r
+ function toStr(obj) {\r
+ if (obj && obj.toString) {\r
+ return obj.toString();\r
+ } else {\r
+ return String(obj);\r
+ }\r
+ }\r
+\r
+ function getExceptionMessage(ex) {\r
+ if (ex.message) {\r
+ return ex.message;\r
+ } else if (ex.description) {\r
+ return ex.description;\r
+ } else {\r
+ return toStr(ex);\r
+ }\r
+ }\r
+\r
+ // Gets the portion of the URL after the last slash\r
+ function getUrlFileName(url) {\r
+ var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\"));\r
+ return url.substr(lastSlashIndex + 1);\r
+ }\r
+\r
+ // Returns a nicely formatted representation of an error\r
+ function getExceptionStringRep(ex) {\r
+ if (ex) {\r
+ var exStr = "Exception: " + getExceptionMessage(ex);\r
+ try {\r
+ if (ex.lineNumber) {\r
+ exStr += " on line number " + ex.lineNumber;\r
+ }\r
+ if (ex.fileName) {\r
+ exStr += " in file " + getUrlFileName(ex.fileName);\r
+ }\r
+ } catch (localEx) {\r
+ logLog.warn("Unable to obtain file and line information for error");\r
+ }\r
+ if (showStackTraces && ex.stack) {\r
+ exStr += newLine + "Stack trace:" + newLine + ex.stack;\r
+ }\r
+ return exStr;\r
+ }\r
+ return null;\r
+ }\r
+\r
+ function bool(obj) {\r
+ return Boolean(obj);\r
+ }\r
+\r
+ function trim(str) {\r
+ return str.replace(/^\s+/, "").replace(/\s+$/, "");\r
+ }\r
+\r
+ function splitIntoLines(text) {\r
+ // Ensure all line breaks are \n only\r
+ var text2 = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");\r
+ return text2.split("\n");\r
+ }\r
+\r
+ var urlEncode = (typeof window.encodeURIComponent != "undefined") ?\r
+ function(str) {\r
+ return encodeURIComponent(str);\r
+ }: \r
+ function(str) {\r
+ return escape(str).replace(/\+/g, "%2B").replace(/"/g, "%22").replace(/'/g, "%27").replace(/\//g, "%2F").replace(/=/g, "%3D");\r
+ };\r
+\r
+ var urlDecode = (typeof window.decodeURIComponent != "undefined") ?\r
+ function(str) {\r
+ return decodeURIComponent(str);\r
+ }: \r
+ function(str) {\r
+ return unescape(str).replace(/%2B/g, "+").replace(/%22/g, "\"").replace(/%27/g, "'").replace(/%2F/g, "/").replace(/%3D/g, "=");\r
+ };\r
+\r
+ function array_remove(arr, val) {\r
+ var index = -1;\r
+ for (var i = 0, len = arr.length; i < len; i++) {\r
+ if (arr[i] === val) {\r
+ index = i;\r
+ break;\r
+ }\r
+ }\r
+ if (index >= 0) {\r
+ arr.splice(index, 1);\r
+ return true;\r
+ } else {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ function array_contains(arr, val) {\r
+ for(var i = 0, len = arr.length; i < len; i++) {\r
+ if (arr[i] == val) {\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+\r
+ function extractBooleanFromParam(param, defaultValue) {\r
+ if (isUndefined(param)) {\r
+ return defaultValue;\r
+ } else {\r
+ return bool(param);\r
+ }\r
+ }\r
+\r
+ function extractStringFromParam(param, defaultValue) {\r
+ if (isUndefined(param)) {\r
+ return defaultValue;\r
+ } else {\r
+ return String(param);\r
+ }\r
+ }\r
+\r
+ function extractIntFromParam(param, defaultValue) {\r
+ if (isUndefined(param)) {\r
+ return defaultValue;\r
+ } else {\r
+ try {\r
+ var value = parseInt(param, 10);\r
+ return isNaN(value) ? defaultValue : value;\r
+ } catch (ex) {\r
+ logLog.warn("Invalid int param " + param, ex);\r
+ return defaultValue;\r
+ }\r
+ }\r
+ }\r
+\r
+ function extractFunctionFromParam(param, defaultValue) {\r
+ if (typeof param == "function") {\r
+ return param;\r
+ } else {\r
+ return defaultValue;\r
+ }\r
+ }\r
+\r
+ function isError(err) {\r
+ return (err instanceof Error);\r
+ }\r
+\r
+ if (!Function.prototype.apply){\r
+ Function.prototype.apply = function(obj, args) {\r
+ var methodName = "__apply__";\r
+ if (typeof obj[methodName] != "undefined") {\r
+ methodName += String(Math.random()).substr(2);\r
+ }\r
+ obj[methodName] = this;\r
+\r
+ var argsStrings = [];\r
+ for (var i = 0, len = args.length; i < len; i++) {\r
+ argsStrings[i] = "args[" + i + "]";\r
+ }\r
+ var script = "obj." + methodName + "(" + argsStrings.join(",") + ")";\r
+ var returnValue = eval(script);\r
+ delete obj[methodName];\r
+ return returnValue;\r
+ };\r
+ }\r
+\r
+ if (!Function.prototype.call){\r
+ Function.prototype.call = function(obj) {\r
+ var args = [];\r
+ for (var i = 1, len = arguments.length; i < len; i++) {\r
+ args[i - 1] = arguments[i];\r
+ }\r
+ return this.apply(obj, args);\r
+ };\r
+ }\r
+\r
+ function getListenersPropertyName(eventName) {\r
+ return "__log4javascript_listeners__" + eventName;\r
+ }\r
+\r
+ function addEvent(node, eventName, listener, useCapture, win) {\r
+ win = win ? win : window;\r
+ if (node.addEventListener) {\r
+ node.addEventListener(eventName, listener, useCapture);\r
+ } else if (node.attachEvent) {\r
+ node.attachEvent("on" + eventName, listener);\r
+ } else {\r
+ var propertyName = getListenersPropertyName(eventName);\r
+ if (!node[propertyName]) {\r
+ node[propertyName] = [];\r
+ // Set event handler\r
+ node["on" + eventName] = function(evt) {\r
+ evt = getEvent(evt, win);\r
+ var listenersPropertyName = getListenersPropertyName(eventName);\r
+\r
+ // Clone the array of listeners to leave the original untouched\r
+ var listeners = this[listenersPropertyName].concat([]);\r
+ var currentListener;\r
+\r
+ // Call each listener in turn\r
+ while ((currentListener = listeners.shift())) {\r
+ currentListener.call(this, evt);\r
+ }\r
+ };\r
+ }\r
+ node[propertyName].push(listener);\r
+ }\r
+ }\r
+\r
+ function removeEvent(node, eventName, listener, useCapture) {\r
+ if (node.removeEventListener) {\r
+ node.removeEventListener(eventName, listener, useCapture);\r
+ } else if (node.detachEvent) {\r
+ node.detachEvent("on" + eventName, listener);\r
+ } else {\r
+ var propertyName = getListenersPropertyName(eventName);\r
+ if (node[propertyName]) {\r
+ array_remove(node[propertyName], listener);\r
+ }\r
+ }\r
+ }\r
+\r
+ function getEvent(evt, win) {\r
+ win = win ? win : window;\r
+ return evt ? evt : win.event;\r
+ }\r
+\r
+ function stopEventPropagation(evt) {\r
+ if (evt.stopPropagation) {\r
+ evt.stopPropagation();\r
+ } else if (typeof evt.cancelBubble != "undefined") {\r
+ evt.cancelBubble = true;\r
+ }\r
+ evt.returnValue = false;\r
+ }\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Simple logging for log4javascript itself\r
+\r
+ var logLog = {\r
+ quietMode: false,\r
+\r
+ debugMessages: [],\r
+\r
+ setQuietMode: function(quietMode) {\r
+ this.quietMode = bool(quietMode);\r
+ },\r
+\r
+ numberOfErrors: 0,\r
+\r
+ alertAllErrors: false,\r
+\r
+ setAlertAllErrors: function(alertAllErrors) {\r
+ this.alertAllErrors = alertAllErrors;\r
+ },\r
+\r
+ debug: function(message) {\r
+ this.debugMessages.push(message);\r
+ },\r
+\r
+ displayDebug: function() {\r
+ alert(this.debugMessages.join(newLine));\r
+ },\r
+\r
+ warn: function(message, exception) {\r
+ },\r
+\r
+ error: function(message, exception) {\r
+ if (++this.numberOfErrors == 1 || this.alertAllErrors) {\r
+ if (!this.quietMode) {\r
+ var alertMessage = "log4javascript error: " + message;\r
+ if (exception) {\r
+ alertMessage += newLine + newLine + "Original error: " + getExceptionStringRep(exception);\r
+ }\r
+ alert(alertMessage);\r
+ }\r
+ }\r
+ }\r
+ };\r
+ log4javascript.logLog = logLog;\r
+\r
+ log4javascript.setEventTypes(["load", "error"]);\r
+\r
+ function handleError(message, exception) {\r
+ logLog.error(message, exception);\r
+ log4javascript.dispatchEvent("error", { "message": message, "exception": exception });\r
+ }\r
+\r
+ log4javascript.handleError = handleError;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+\r
+ var enabled = !((typeof log4javascript_disabled != "undefined") &&\r
+ log4javascript_disabled);\r
+\r
+ log4javascript.setEnabled = function(enable) {\r
+ enabled = bool(enable);\r
+ };\r
+\r
+ log4javascript.isEnabled = function() {\r
+ return enabled;\r
+ };\r
+\r
+ var useTimeStampsInMilliseconds = true;\r
+\r
+ log4javascript.setTimeStampsInMilliseconds = function(timeStampsInMilliseconds) {\r
+ useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);\r
+ };\r
+\r
+ log4javascript.isTimeStampsInMilliseconds = function() {\r
+ return useTimeStampsInMilliseconds;\r
+ };\r
+ \r
+\r
+ // This evaluates the given expression in the current scope, thus allowing\r
+ // scripts to access private variables. Particularly useful for testing\r
+ log4javascript.evalInScope = function(expr) {\r
+ return eval(expr);\r
+ };\r
+\r
+ var showStackTraces = false;\r
+\r
+ log4javascript.setShowStackTraces = function(show) {\r
+ showStackTraces = bool(show);\r
+ };\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Levels\r
+\r
+ var Level = function(level, name) {\r
+ this.level = level;\r
+ this.name = name;\r
+ };\r
+\r
+ Level.prototype = {\r
+ toString: function() {\r
+ return this.name;\r
+ },\r
+ equals: function(level) {\r
+ return this.level == level.level;\r
+ },\r
+ isGreaterOrEqual: function(level) {\r
+ return this.level >= level.level;\r
+ }\r
+ };\r
+\r
+ Level.ALL = new Level(Number.MIN_VALUE, "ALL");\r
+ Level.TRACE = new Level(10000, "TRACE");\r
+ Level.DEBUG = new Level(20000, "DEBUG");\r
+ Level.INFO = new Level(30000, "INFO");\r
+ Level.WARN = new Level(40000, "WARN");\r
+ Level.ERROR = new Level(50000, "ERROR");\r
+ Level.FATAL = new Level(60000, "FATAL");\r
+ Level.OFF = new Level(Number.MAX_VALUE, "OFF");\r
+\r
+ log4javascript.Level = Level;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Timers\r
+\r
+ function Timer(name, level) {\r
+ this.name = name;\r
+ this.level = isUndefined(level) ? Level.INFO : level;\r
+ this.start = new Date();\r
+ }\r
+\r
+ Timer.prototype.getElapsedTime = function() {\r
+ return new Date().getTime() - this.start.getTime();\r
+ };\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Loggers\r
+\r
+ var anonymousLoggerName = "[anonymous]";\r
+ var defaultLoggerName = "[default]";\r
+ var nullLoggerName = "[null]";\r
+ var rootLoggerName = "root";\r
+\r
+ function Logger(name) {\r
+ this.name = name;\r
+ this.parent = null;\r
+ this.children = [];\r
+\r
+ var appenders = [];\r
+ var loggerLevel = null;\r
+ var isRoot = (this.name === rootLoggerName);\r
+ var isNull = (this.name === nullLoggerName);\r
+\r
+ var appenderCache = null;\r
+ var appenderCacheInvalidated = false;\r
+ \r
+ this.addChild = function(childLogger) {\r
+ this.children.push(childLogger);\r
+ childLogger.parent = this;\r
+ childLogger.invalidateAppenderCache();\r
+ };\r
+\r
+ // Additivity\r
+ var additive = true;\r
+ this.getAdditivity = function() {\r
+ return additive;\r
+ };\r
+\r
+ this.setAdditivity = function(additivity) {\r
+ var valueChanged = (additive != additivity);\r
+ additive = additivity;\r
+ if (valueChanged) {\r
+ this.invalidateAppenderCache();\r
+ }\r
+ };\r
+\r
+ // Create methods that use the appenders variable in this scope\r
+ this.addAppender = function(appender) {\r
+ if (isNull) {\r
+ handleError("Logger.addAppender: you may not add an appender to the null logger");\r
+ } else {\r
+ if (appender instanceof log4javascript.Appender) {\r
+ if (!array_contains(appenders, appender)) {\r
+ appenders.push(appender);\r
+ appender.setAddedToLogger(this);\r
+ this.invalidateAppenderCache();\r
+ }\r
+ } else {\r
+ handleError("Logger.addAppender: appender supplied ('" +\r
+ toStr(appender) + "') is not a subclass of Appender");\r
+ }\r
+ }\r
+ };\r
+\r
+ this.removeAppender = function(appender) {\r
+ array_remove(appenders, appender);\r
+ appender.setRemovedFromLogger(this);\r
+ this.invalidateAppenderCache();\r
+ };\r
+\r
+ this.removeAllAppenders = function() {\r
+ var appenderCount = appenders.length;\r
+ if (appenderCount > 0) {\r
+ for (var i = 0; i < appenderCount; i++) {\r
+ appenders[i].setRemovedFromLogger(this);\r
+ }\r
+ appenders.length = 0;\r
+ this.invalidateAppenderCache();\r
+ }\r
+ };\r
+\r
+ this.getEffectiveAppenders = function() {\r
+ if (appenderCache === null || appenderCacheInvalidated) {\r
+ // Build appender cache\r
+ var parentEffectiveAppenders = (isRoot || !this.getAdditivity()) ?\r
+ [] : this.parent.getEffectiveAppenders();\r
+ appenderCache = parentEffectiveAppenders.concat(appenders);\r
+ appenderCacheInvalidated = false;\r
+ }\r
+ return appenderCache;\r
+ };\r
+ \r
+ this.invalidateAppenderCache = function() {\r
+ appenderCacheInvalidated = true;\r
+ for (var i = 0, len = this.children.length; i < len; i++) {\r
+ this.children[i].invalidateAppenderCache();\r
+ }\r
+ };\r
+\r
+ this.log = function(level, params) {\r
+ if (enabled && level.isGreaterOrEqual(this.getEffectiveLevel())) {\r
+ // Check whether last param is an exception\r
+ var exception;\r
+ var finalParamIndex = params.length - 1;\r
+ var lastParam = params[finalParamIndex];\r
+ if (params.length > 1 && isError(lastParam)) {\r
+ exception = lastParam;\r
+ finalParamIndex--;\r
+ }\r
+\r
+ // Construct genuine array for the params\r
+ var messages = [];\r
+ for (var i = 0; i <= finalParamIndex; i++) {\r
+ messages[i] = params[i];\r
+ }\r
+\r
+ var loggingEvent = new LoggingEvent(\r
+ this, new Date(), level, messages, exception);\r
+\r
+ this.callAppenders(loggingEvent);\r
+ }\r
+ };\r
+\r
+ this.callAppenders = function(loggingEvent) {\r
+ var effectiveAppenders = this.getEffectiveAppenders();\r
+ for (var i = 0, len = effectiveAppenders.length; i < len; i++) {\r
+ effectiveAppenders[i].doAppend(loggingEvent);\r
+ }\r
+ };\r
+\r
+ this.setLevel = function(level) {\r
+ // Having a level of null on the root logger would be very bad.\r
+ if (isRoot && level === null) {\r
+ handleError("Logger.setLevel: you cannot set the level of the root logger to null");\r
+ } else if (level instanceof Level) {\r
+ loggerLevel = level;\r
+ } else {\r
+ handleError("Logger.setLevel: level supplied to logger " +\r
+ this.name + " is not an instance of log4javascript.Level");\r
+ }\r
+ };\r
+\r
+ this.getLevel = function() {\r
+ return loggerLevel;\r
+ };\r
+\r
+ this.getEffectiveLevel = function() {\r
+ for (var logger = this; logger !== null; logger = logger.parent) {\r
+ var level = logger.getLevel();\r
+ if (level !== null) {\r
+ return level;\r
+ }\r
+ }\r
+ };\r
+\r
+ this.group = function(name, initiallyExpanded) {\r
+ if (enabled) {\r
+ var effectiveAppenders = this.getEffectiveAppenders();\r
+ for (var i = 0, len = effectiveAppenders.length; i < len; i++) {\r
+ effectiveAppenders[i].group(name, initiallyExpanded);\r
+ }\r
+ }\r
+ };\r
+\r
+ this.groupEnd = function() {\r
+ if (enabled) {\r
+ var effectiveAppenders = this.getEffectiveAppenders();\r
+ for (var i = 0, len = effectiveAppenders.length; i < len; i++) {\r
+ effectiveAppenders[i].groupEnd();\r
+ }\r
+ }\r
+ };\r
+\r
+ var timers = {};\r
+\r
+ this.time = function(name, level) {\r
+ if (enabled) {\r
+ if (isUndefined(name)) {\r
+ handleError("Logger.time: a name for the timer must be supplied");\r
+ } else if (level && !(level instanceof Level)) {\r
+ handleError("Logger.time: level supplied to timer " +\r
+ name + " is not an instance of log4javascript.Level");\r
+ } else {\r
+ timers[name] = new Timer(name, level);\r
+ }\r
+ }\r
+ };\r
+\r
+ this.timeEnd = function(name) {\r
+ if (enabled) {\r
+ if (isUndefined(name)) {\r
+ handleError("Logger.timeEnd: a name for the timer must be supplied");\r
+ } else if (timers[name]) {\r
+ var timer = timers[name];\r
+ var milliseconds = timer.getElapsedTime();\r
+ this.log(timer.level, ["Timer " + toStr(name) + " completed in " + milliseconds + "ms"]);\r
+ delete timers[name];\r
+ } else {\r
+ logLog.warn("Logger.timeEnd: no timer found with name " + name);\r
+ }\r
+ }\r
+ };\r
+\r
+ this.assert = function(expr) {\r
+ if (enabled && !expr) {\r
+ var args = [];\r
+ for (var i = 1, len = arguments.length; i < len; i++) {\r
+ args.push(arguments[i]);\r
+ }\r
+ args = (args.length > 0) ? args : ["Assertion Failure"];\r
+ args.push(newLine);\r
+ args.push(expr);\r
+ this.log(Level.ERROR, args);\r
+ }\r
+ };\r
+\r
+ this.toString = function() {\r
+ return "Logger[" + this.name + "]";\r
+ };\r
+ }\r
+\r
+ Logger.prototype = {\r
+ trace: function() {\r
+ this.log(Level.TRACE, arguments);\r
+ },\r
+\r
+ debug: function() {\r
+ this.log(Level.DEBUG, arguments);\r
+ },\r
+\r
+ info: function() {\r
+ this.log(Level.INFO, arguments);\r
+ },\r
+\r
+ warn: function() {\r
+ this.log(Level.WARN, arguments);\r
+ },\r
+\r
+ error: function() {\r
+ this.log(Level.ERROR, arguments);\r
+ },\r
+\r
+ fatal: function() {\r
+ this.log(Level.FATAL, arguments);\r
+ },\r
+\r
+ isEnabledFor: function(level) {\r
+ return level.isGreaterOrEqual(this.getEffectiveLevel());\r
+ },\r
+\r
+ isTraceEnabled: function() {\r
+ return this.isEnabledFor(Level.TRACE);\r
+ },\r
+\r
+ isDebugEnabled: function() {\r
+ return this.isEnabledFor(Level.DEBUG);\r
+ },\r
+\r
+ isInfoEnabled: function() {\r
+ return this.isEnabledFor(Level.INFO);\r
+ },\r
+\r
+ isWarnEnabled: function() {\r
+ return this.isEnabledFor(Level.WARN);\r
+ },\r
+\r
+ isErrorEnabled: function() {\r
+ return this.isEnabledFor(Level.ERROR);\r
+ },\r
+\r
+ isFatalEnabled: function() {\r
+ return this.isEnabledFor(Level.FATAL);\r
+ }\r
+ };\r
+\r
+ Logger.prototype.trace.isEntryPoint = true;\r
+ Logger.prototype.debug.isEntryPoint = true;\r
+ Logger.prototype.info.isEntryPoint = true;\r
+ Logger.prototype.warn.isEntryPoint = true;\r
+ Logger.prototype.error.isEntryPoint = true;\r
+ Logger.prototype.fatal.isEntryPoint = true;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Logger access methods\r
+\r
+ // Hashtable of loggers keyed by logger name\r
+ var loggers = {};\r
+ var loggerNames = [];\r
+\r
+ var ROOT_LOGGER_DEFAULT_LEVEL = Level.DEBUG;\r
+ var rootLogger = new Logger(rootLoggerName);\r
+ rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);\r
+\r
+ log4javascript.getRootLogger = function() {\r
+ return rootLogger;\r
+ };\r
+\r
+ log4javascript.getLogger = function(loggerName) {\r
+ // Use default logger if loggerName is not specified or invalid\r
+ if (!(typeof loggerName == "string")) {\r
+ loggerName = anonymousLoggerName;\r
+ logLog.warn("log4javascript.getLogger: non-string logger name " +\r
+ toStr(loggerName) + " supplied, returning anonymous logger");\r
+ }\r
+\r
+ // Do not allow retrieval of the root logger by name\r
+ if (loggerName == rootLoggerName) {\r
+ handleError("log4javascript.getLogger: root logger may not be obtained by name");\r
+ }\r
+\r
+ // Create the logger for this name if it doesn't already exist\r
+ if (!loggers[loggerName]) {\r
+ var logger = new Logger(loggerName);\r
+ loggers[loggerName] = logger;\r
+ loggerNames.push(loggerName);\r
+\r
+ // Set up parent logger, if it doesn't exist\r
+ var lastDotIndex = loggerName.lastIndexOf(".");\r
+ var parentLogger;\r
+ if (lastDotIndex > -1) {\r
+ var parentLoggerName = loggerName.substring(0, lastDotIndex);\r
+ parentLogger = log4javascript.getLogger(parentLoggerName); // Recursively sets up grandparents etc.\r
+ } else {\r
+ parentLogger = rootLogger;\r
+ }\r
+ parentLogger.addChild(logger);\r
+ }\r
+ return loggers[loggerName];\r
+ };\r
+\r
+ var defaultLogger = null;\r
+ log4javascript.getDefaultLogger = function() {\r
+ if (!defaultLogger) {\r
+ defaultLogger = log4javascript.getLogger(defaultLoggerName);\r
+ var a = new log4javascript.PopUpAppender();\r
+ defaultLogger.addAppender(a);\r
+ }\r
+ return defaultLogger;\r
+ };\r
+\r
+ var nullLogger = null;\r
+ log4javascript.getNullLogger = function() {\r
+ if (!nullLogger) {\r
+ nullLogger = new Logger(nullLoggerName);\r
+ nullLogger.setLevel(Level.OFF);\r
+ }\r
+ return nullLogger;\r
+ };\r
+\r
+ // Destroys all loggers\r
+ log4javascript.resetConfiguration = function() {\r
+ rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);\r
+ loggers = {};\r
+ };\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Logging events\r
+\r
+ var LoggingEvent = function(logger, timeStamp, level, messages,\r
+ exception) {\r
+ this.logger = logger;\r
+ this.timeStamp = timeStamp;\r
+ this.timeStampInMilliseconds = timeStamp.getTime();\r
+ this.timeStampInSeconds = Math.floor(this.timeStampInMilliseconds / 1000);\r
+ this.milliseconds = this.timeStamp.getMilliseconds();\r
+ this.level = level;\r
+ this.messages = messages;\r
+ this.exception = exception;\r
+ };\r
+\r
+ LoggingEvent.prototype = {\r
+ getThrowableStrRep: function() {\r
+ return this.exception ?\r
+ getExceptionStringRep(this.exception) : "";\r
+ },\r
+ getCombinedMessages: function() {\r
+ return (this.messages.length == 1) ? this.messages[0] :\r
+ this.messages.join(newLine);\r
+ },\r
+ toString: function() {\r
+ return "LoggingEvent[" + this.level + "]";\r
+ }\r
+ };\r
+\r
+ log4javascript.LoggingEvent = LoggingEvent;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Layout prototype\r
+\r
+ var Layout = function() {\r
+ };\r
+\r
+ Layout.prototype = {\r
+ defaults: {\r
+ loggerKey: "logger",\r
+ timeStampKey: "timestamp",\r
+ millisecondsKey: "milliseconds",\r
+ levelKey: "level",\r
+ messageKey: "message",\r
+ exceptionKey: "exception",\r
+ urlKey: "url"\r
+ },\r
+ loggerKey: "logger",\r
+ timeStampKey: "timestamp",\r
+ millisecondsKey: "milliseconds",\r
+ levelKey: "level",\r
+ messageKey: "message",\r
+ exceptionKey: "exception",\r
+ urlKey: "url",\r
+ batchHeader: "",\r
+ batchFooter: "",\r
+ batchSeparator: "",\r
+ returnsPostData: false,\r
+ overrideTimeStampsSetting: false,\r
+ useTimeStampsInMilliseconds: null,\r
+\r
+ format: function() {\r
+ handleError("Layout.format: layout supplied has no format() method");\r
+ },\r
+\r
+ ignoresThrowable: function() {\r
+ handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");\r
+ },\r
+\r
+ getContentType: function() {\r
+ return "text/plain";\r
+ },\r
+\r
+ allowBatching: function() {\r
+ return true;\r
+ },\r
+\r
+ setTimeStampsInMilliseconds: function(timeStampsInMilliseconds) {\r
+ this.overrideTimeStampsSetting = true;\r
+ this.useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);\r
+ },\r
+\r
+ isTimeStampsInMilliseconds: function() {\r
+ return this.overrideTimeStampsSetting ?\r
+ this.useTimeStampsInMilliseconds : useTimeStampsInMilliseconds;\r
+ },\r
+\r
+ getTimeStampValue: function(loggingEvent) {\r
+ return this.isTimeStampsInMilliseconds() ?\r
+ loggingEvent.timeStampInMilliseconds : loggingEvent.timeStampInSeconds;\r
+ },\r
+\r
+ getDataValues: function(loggingEvent, combineMessages) {\r
+ var dataValues = [\r
+ [this.loggerKey, loggingEvent.logger.name],\r
+ [this.timeStampKey, this.getTimeStampValue(loggingEvent)],\r
+ [this.levelKey, loggingEvent.level.name],\r
+ [this.urlKey, window.location.href],\r
+ [this.messageKey, combineMessages ? loggingEvent.getCombinedMessages() : loggingEvent.messages]\r
+ ];\r
+ if (!this.isTimeStampsInMilliseconds()) {\r
+ dataValues.push([this.millisecondsKey, loggingEvent.milliseconds]);\r
+ }\r
+ if (loggingEvent.exception) {\r
+ dataValues.push([this.exceptionKey, getExceptionStringRep(loggingEvent.exception)]);\r
+ }\r
+ if (this.hasCustomFields()) {\r
+ for (var i = 0, len = this.customFields.length; i < len; i++) {\r
+ var val = this.customFields[i].value;\r
+\r
+ // Check if the value is a function. If so, execute it, passing it the\r
+ // current layout and the logging event\r
+ if (typeof val === "function") {\r
+ val = val(this, loggingEvent);\r
+ }\r
+ dataValues.push([this.customFields[i].name, val]);\r
+ }\r
+ }\r
+ return dataValues;\r
+ },\r
+\r
+ setKeys: function(loggerKey, timeStampKey, levelKey, messageKey,\r
+ exceptionKey, urlKey, millisecondsKey) {\r
+ this.loggerKey = extractStringFromParam(loggerKey, this.defaults.loggerKey);\r
+ this.timeStampKey = extractStringFromParam(timeStampKey, this.defaults.timeStampKey);\r
+ this.levelKey = extractStringFromParam(levelKey, this.defaults.levelKey);\r
+ this.messageKey = extractStringFromParam(messageKey, this.defaults.messageKey);\r
+ this.exceptionKey = extractStringFromParam(exceptionKey, this.defaults.exceptionKey);\r
+ this.urlKey = extractStringFromParam(urlKey, this.defaults.urlKey);\r
+ this.millisecondsKey = extractStringFromParam(millisecondsKey, this.defaults.millisecondsKey);\r
+ },\r
+\r
+ setCustomField: function(name, value) {\r
+ var fieldUpdated = false;\r
+ for (var i = 0, len = this.customFields.length; i < len; i++) {\r
+ if (this.customFields[i].name === name) {\r
+ this.customFields[i].value = value;\r
+ fieldUpdated = true;\r
+ }\r
+ }\r
+ if (!fieldUpdated) {\r
+ this.customFields.push({"name": name, "value": value});\r
+ }\r
+ },\r
+\r
+ hasCustomFields: function() {\r
+ return (this.customFields.length > 0);\r
+ },\r
+\r
+ toString: function() {\r
+ handleError("Layout.toString: all layouts must override this method");\r
+ }\r
+ };\r
+\r
+ log4javascript.Layout = Layout;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Appender prototype\r
+\r
+ var Appender = function() {};\r
+\r
+ Appender.prototype = new EventSupport();\r
+\r
+ Appender.prototype.layout = new PatternLayout();\r
+ Appender.prototype.threshold = Level.ALL;\r
+ Appender.prototype.loggers = [];\r
+\r
+ // Performs threshold checks before delegating actual logging to the\r
+ // subclass's specific append method.\r
+ Appender.prototype.doAppend = function(loggingEvent) {\r
+ if (enabled && loggingEvent.level.level >= this.threshold.level) {\r
+ this.append(loggingEvent);\r
+ }\r
+ };\r
+\r
+ Appender.prototype.append = function(loggingEvent) {};\r
+\r
+ Appender.prototype.setLayout = function(layout) {\r
+ if (layout instanceof Layout) {\r
+ this.layout = layout;\r
+ } else {\r
+ handleError("Appender.setLayout: layout supplied to " +\r
+ this.toString() + " is not a subclass of Layout");\r
+ }\r
+ };\r
+\r
+ Appender.prototype.getLayout = function() {\r
+ return this.layout;\r
+ };\r
+\r
+ Appender.prototype.setThreshold = function(threshold) {\r
+ if (threshold instanceof Level) {\r
+ this.threshold = threshold;\r
+ } else {\r
+ handleError("Appender.setThreshold: threshold supplied to " +\r
+ this.toString() + " is not a subclass of Level");\r
+ }\r
+ };\r
+\r
+ Appender.prototype.getThreshold = function() {\r
+ return this.threshold;\r
+ };\r
+\r
+ Appender.prototype.setAddedToLogger = function(logger) {\r
+ this.loggers.push(logger);\r
+ };\r
+\r
+ Appender.prototype.setRemovedFromLogger = function(logger) {\r
+ array_remove(this.loggers, logger);\r
+ };\r
+\r
+ Appender.prototype.group = emptyFunction;\r
+ Appender.prototype.groupEnd = emptyFunction;\r
+\r
+ Appender.prototype.toString = function() {\r
+ handleError("Appender.toString: all appenders must override this method");\r
+ };\r
+\r
+ log4javascript.Appender = Appender;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // SimpleLayout \r
+\r
+ function SimpleLayout() {\r
+ this.customFields = [];\r
+ }\r
+\r
+ SimpleLayout.prototype = new Layout();\r
+\r
+ SimpleLayout.prototype.format = function(loggingEvent) {\r
+ return loggingEvent.level.name + " - " + loggingEvent.getCombinedMessages();\r
+ };\r
+\r
+ SimpleLayout.prototype.ignoresThrowable = function() {\r
+ return true;\r
+ };\r
+\r
+ SimpleLayout.prototype.toString = function() {\r
+ return "SimpleLayout";\r
+ };\r
+\r
+ log4javascript.SimpleLayout = SimpleLayout;\r
+ /* ----------------------------------------------------------------------- */\r
+ // NullLayout \r
+\r
+ function NullLayout() {\r
+ this.customFields = [];\r
+ }\r
+\r
+ NullLayout.prototype = new Layout();\r
+\r
+ NullLayout.prototype.format = function(loggingEvent) {\r
+ return loggingEvent.messages;\r
+ };\r
+\r
+ NullLayout.prototype.ignoresThrowable = function() {\r
+ return true;\r
+ };\r
+\r
+ NullLayout.prototype.toString = function() {\r
+ return "NullLayout";\r
+ };\r
+\r
+ log4javascript.NullLayout = NullLayout;\r
+/* ---------------------------------------------------------------------- */\r
+ // XmlLayout\r
+\r
+ function XmlLayout(combineMessages) {\r
+ this.combineMessages = extractBooleanFromParam(combineMessages, true);\r
+ this.customFields = [];\r
+ }\r
+\r
+ XmlLayout.prototype = new Layout();\r
+\r
+ XmlLayout.prototype.isCombinedMessages = function() {\r
+ return this.combineMessages;\r
+ };\r
+\r
+ XmlLayout.prototype.getContentType = function() {\r
+ return "text/xml";\r
+ };\r
+\r
+ XmlLayout.prototype.escapeCdata = function(str) {\r
+ return str.replace(/\]\]>/, "]]>]]><![CDATA[");\r
+ };\r
+\r
+ XmlLayout.prototype.format = function(loggingEvent) {\r
+ var layout = this;\r
+ var i, len;\r
+ function formatMessage(message) {\r
+ message = (typeof message === "string") ? message : toStr(message);\r
+ return "<log4javascript:message><![CDATA[" +\r
+ layout.escapeCdata(message) + "]]></log4javascript:message>";\r
+ }\r
+\r
+ var str = "<log4javascript:event logger=\"" + loggingEvent.logger.name +\r
+ "\" timestamp=\"" + this.getTimeStampValue(loggingEvent) + "\"";\r
+ if (!this.isTimeStampsInMilliseconds()) {\r
+ str += " milliseconds=\"" + loggingEvent.milliseconds + "\"";\r
+ }\r
+ str += " level=\"" + loggingEvent.level.name + "\">" + newLine;\r
+ if (this.combineMessages) {\r
+ str += formatMessage(loggingEvent.getCombinedMessages());\r
+ } else {\r
+ str += "<log4javascript:messages>" + newLine;\r
+ for (i = 0, len = loggingEvent.messages.length; i < len; i++) {\r
+ str += formatMessage(loggingEvent.messages[i]) + newLine;\r
+ }\r
+ str += "</log4javascript:messages>" + newLine;\r
+ }\r
+ if (this.hasCustomFields()) {\r
+ for (i = 0, len = this.customFields.length; i < len; i++) {\r
+ str += "<log4javascript:customfield name=\"" +\r
+ this.customFields[i].name + "\"><![CDATA[" +\r
+ this.customFields[i].value.toString() +\r
+ "]]></log4javascript:customfield>" + newLine;\r
+ }\r
+ }\r
+ if (loggingEvent.exception) {\r
+ str += "<log4javascript:exception><![CDATA[" +\r
+ getExceptionStringRep(loggingEvent.exception) +\r
+ "]]></log4javascript:exception>" + newLine;\r
+ }\r
+ str += "</log4javascript:event>" + newLine + newLine;\r
+ return str;\r
+ };\r
+\r
+ XmlLayout.prototype.ignoresThrowable = function() {\r
+ return false;\r
+ };\r
+\r
+ XmlLayout.prototype.toString = function() {\r
+ return "XmlLayout";\r
+ };\r
+\r
+ log4javascript.XmlLayout = XmlLayout;\r
+ /* ---------------------------------------------------------------------- */\r
+ // JsonLayout related\r
+\r
+ function escapeNewLines(str) {\r
+ return str.replace(/\r\n|\r|\n/g, "\\r\\n");\r
+ }\r
+\r
+ function JsonLayout(readable, combineMessages) {\r
+ this.readable = extractBooleanFromParam(readable, false);\r
+ this.combineMessages = extractBooleanFromParam(combineMessages, true);\r
+ this.batchHeader = this.readable ? "[" + newLine : "[";\r
+ this.batchFooter = this.readable ? "]" + newLine : "]";\r
+ this.batchSeparator = this.readable ? "," + newLine : ",";\r
+ this.setKeys();\r
+ this.colon = this.readable ? ": " : ":";\r
+ this.tab = this.readable ? "\t" : "";\r
+ this.lineBreak = this.readable ? newLine : "";\r
+ this.customFields = [];\r
+ }\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // JsonLayout\r
+\r
+ JsonLayout.prototype = new Layout();\r
+\r
+ JsonLayout.prototype.isReadable = function() {\r
+ return this.readable;\r
+ };\r
+\r
+ JsonLayout.prototype.isCombinedMessages = function() {\r
+ return this.combineMessages;\r
+ };\r
+\r
+ JsonLayout.prototype.format = function(loggingEvent) {\r
+ var layout = this;\r
+ var dataValues = this.getDataValues(loggingEvent, this.combineMessages);\r
+ var str = "{" + this.lineBreak;\r
+ var i, len;\r
+\r
+ function formatValue(val, prefix, expand) {\r
+ // Check the type of the data value to decide whether quotation marks\r
+ // or expansion are required\r
+ var formattedValue;\r
+ var valType = typeof val;\r
+ if (val instanceof Date) {\r
+ formattedValue = String(val.getTime());\r
+ } else if (expand && (val instanceof Array)) {\r
+ formattedValue = "[" + layout.lineBreak;\r
+ for (var i = 0, len = val.length; i < len; i++) {\r
+ var childPrefix = prefix + layout.tab;\r
+ formattedValue += childPrefix + formatValue(val[i], childPrefix, false);\r
+ if (i < val.length - 1) {\r
+ formattedValue += ",";\r
+ }\r
+ formattedValue += layout.lineBreak;\r
+ }\r
+ formattedValue += prefix + "]";\r
+ } else if (valType !== "number" && valType !== "boolean") {\r
+ formattedValue = "\"" + escapeNewLines(toStr(val).replace(/\"/g, "\\\"")) + "\"";\r
+ } else {\r
+ formattedValue = val;\r
+ }\r
+ return formattedValue;\r
+ }\r
+\r
+ for (i = 0, len = dataValues.length - 1; i <= len; i++) {\r
+ str += this.tab + "\"" + dataValues[i][0] + "\"" + this.colon + formatValue(dataValues[i][1], this.tab, true);\r
+ if (i < len) {\r
+ str += ",";\r
+ }\r
+ str += this.lineBreak;\r
+ }\r
+\r
+ str += "}" + this.lineBreak;\r
+ return str;\r
+ };\r
+\r
+ JsonLayout.prototype.ignoresThrowable = function() {\r
+ return false;\r
+ };\r
+\r
+ JsonLayout.prototype.toString = function() {\r
+ return "JsonLayout";\r
+ };\r
+\r
+ JsonLayout.prototype.getContentType = function() {\r
+ return "application/json";\r
+ };\r
+\r
+ log4javascript.JsonLayout = JsonLayout;\r
+ /* ---------------------------------------------------------------------- */\r
+ // HttpPostDataLayout\r
+\r
+ function HttpPostDataLayout() {\r
+ this.setKeys();\r
+ this.customFields = [];\r
+ this.returnsPostData = true;\r
+ }\r
+\r
+ HttpPostDataLayout.prototype = new Layout();\r
+\r
+ // Disable batching\r
+ HttpPostDataLayout.prototype.allowBatching = function() {\r
+ return false;\r
+ };\r
+\r
+ HttpPostDataLayout.prototype.format = function(loggingEvent) {\r
+ var dataValues = this.getDataValues(loggingEvent);\r
+ var queryBits = [];\r
+ for (var i = 0, len = dataValues.length; i < len; i++) {\r
+ var val = (dataValues[i][1] instanceof Date) ?\r
+ String(dataValues[i][1].getTime()) : dataValues[i][1];\r
+ queryBits.push(urlEncode(dataValues[i][0]) + "=" + urlEncode(val));\r
+ }\r
+ return queryBits.join("&");\r
+ };\r
+\r
+ HttpPostDataLayout.prototype.ignoresThrowable = function(loggingEvent) {\r
+ return false;\r
+ };\r
+\r
+ HttpPostDataLayout.prototype.toString = function() {\r
+ return "HttpPostDataLayout";\r
+ };\r
+\r
+ log4javascript.HttpPostDataLayout = HttpPostDataLayout;\r
+ /* ---------------------------------------------------------------------- */\r
+ // formatObjectExpansion\r
+\r
+ function formatObjectExpansion(obj, depth, indentation) {\r
+ var objectsExpanded = [];\r
+\r
+ function doFormat(obj, depth, indentation) {\r
+ var i, j, len, childDepth, childIndentation, childLines, expansion,\r
+ childExpansion;\r
+\r
+ if (!indentation) {\r
+ indentation = "";\r
+ }\r
+\r
+ function formatString(text) {\r
+ var lines = splitIntoLines(text);\r
+ for (var j = 1, jLen = lines.length; j < jLen; j++) {\r
+ lines[j] = indentation + lines[j];\r
+ }\r
+ return lines.join(newLine);\r
+ }\r
+\r
+ if (obj === null) {\r
+ return "null";\r
+ } else if (typeof obj == "undefined") {\r
+ return "undefined";\r
+ } else if (typeof obj == "string") {\r
+ return formatString(obj);\r
+ } else if (typeof obj == "object" && array_contains(objectsExpanded, obj)) {\r
+ try {\r
+ expansion = toStr(obj);\r
+ } catch (ex) {\r
+ expansion = "Error formatting property. Details: " + getExceptionStringRep(ex);\r
+ }\r
+ return expansion + " [already expanded]";\r
+ } else if ((obj instanceof Array) && depth > 0) {\r
+ objectsExpanded.push(obj);\r
+ expansion = "[" + newLine;\r
+ childDepth = depth - 1;\r
+ childIndentation = indentation + " ";\r
+ childLines = [];\r
+ for (i = 0, len = obj.length; i < len; i++) {\r
+ try {\r
+ childExpansion = doFormat(obj[i], childDepth, childIndentation);\r
+ childLines.push(childIndentation + childExpansion);\r
+ } catch (ex) {\r
+ childLines.push(childIndentation + "Error formatting array member. Details: " +\r
+ getExceptionStringRep(ex) + "");\r
+ }\r
+ }\r
+ expansion += childLines.join("," + newLine) + newLine + indentation + "]";\r
+ return expansion;\r
+ } else if (Object.prototype.toString.call(obj) == "[object Date]") {\r
+ return obj.toString();\r
+ } else if (typeof obj == "object" && depth > 0) {\r
+ objectsExpanded.push(obj);\r
+ expansion = "{" + newLine;\r
+ childDepth = depth - 1;\r
+ childIndentation = indentation + " ";\r
+ childLines = [];\r
+ for (i in obj) {\r
+ try {\r
+ childExpansion = doFormat(obj[i], childDepth, childIndentation);\r
+ childLines.push(childIndentation + i + ": " + childExpansion);\r
+ } catch (ex) {\r
+ childLines.push(childIndentation + i + ": Error formatting property. Details: " +\r
+ getExceptionStringRep(ex));\r
+ }\r
+ }\r
+ expansion += childLines.join("," + newLine) + newLine + indentation + "}";\r
+ return expansion;\r
+ } else {\r
+ return formatString(toStr(obj));\r
+ }\r
+ }\r
+ return doFormat(obj, depth, indentation);\r
+ }\r
+ /* ---------------------------------------------------------------------- */\r
+ // Date-related stuff\r
+\r
+ var SimpleDateFormat;\r
+\r
+ (function() {\r
+ 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']+)/;\r
+ var monthNames = ["January", "February", "March", "April", "May", "June",\r
+ "July", "August", "September", "October", "November", "December"];\r
+ var dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];\r
+ var TEXT2 = 0, TEXT3 = 1, NUMBER = 2, YEAR = 3, MONTH = 4, TIMEZONE = 5;\r
+ var types = {\r
+ G : TEXT2,\r
+ y : YEAR,\r
+ M : MONTH,\r
+ w : NUMBER,\r
+ W : NUMBER,\r
+ D : NUMBER,\r
+ d : NUMBER,\r
+ F : NUMBER,\r
+ E : TEXT3,\r
+ a : TEXT2,\r
+ H : NUMBER,\r
+ k : NUMBER,\r
+ K : NUMBER,\r
+ h : NUMBER,\r
+ m : NUMBER,\r
+ s : NUMBER,\r
+ S : NUMBER,\r
+ Z : TIMEZONE\r
+ };\r
+ var ONE_DAY = 24 * 60 * 60 * 1000;\r
+ var ONE_WEEK = 7 * ONE_DAY;\r
+ var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK = 1;\r
+\r
+ var newDateAtMidnight = function(year, month, day) {\r
+ var d = new Date(year, month, day, 0, 0, 0);\r
+ d.setMilliseconds(0);\r
+ return d;\r
+ };\r
+\r
+ Date.prototype.getDifference = function(date) {\r
+ return this.getTime() - date.getTime();\r
+ };\r
+\r
+ Date.prototype.isBefore = function(d) {\r
+ return this.getTime() < d.getTime();\r
+ };\r
+\r
+ Date.prototype.getUTCTime = function() {\r
+ return Date.UTC(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours(), this.getMinutes(),\r
+ this.getSeconds(), this.getMilliseconds());\r
+ };\r
+\r
+ Date.prototype.getTimeSince = function(d) {\r
+ return this.getUTCTime() - d.getUTCTime();\r
+ };\r
+\r
+ Date.prototype.getPreviousSunday = function() {\r
+ // Using midday avoids any possibility of DST messing things up\r
+ var midday = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 12, 0, 0);\r
+ var previousSunday = new Date(midday.getTime() - this.getDay() * ONE_DAY);\r
+ return newDateAtMidnight(previousSunday.getFullYear(), previousSunday.getMonth(),\r
+ previousSunday.getDate());\r
+ };\r
+\r
+ Date.prototype.getWeekInYear = function(minimalDaysInFirstWeek) {\r
+ if (isUndefined(this.minimalDaysInFirstWeek)) {\r
+ minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;\r
+ }\r
+ var previousSunday = this.getPreviousSunday();\r
+ var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);\r
+ var numberOfSundays = previousSunday.isBefore(startOfYear) ?\r
+ 0 : 1 + Math.floor(previousSunday.getTimeSince(startOfYear) / ONE_WEEK);\r
+ var numberOfDaysInFirstWeek = 7 - startOfYear.getDay();\r
+ var weekInYear = numberOfSundays;\r
+ if (numberOfDaysInFirstWeek < minimalDaysInFirstWeek) {\r
+ weekInYear--;\r
+ }\r
+ return weekInYear;\r
+ };\r
+\r
+ Date.prototype.getWeekInMonth = function(minimalDaysInFirstWeek) {\r
+ if (isUndefined(this.minimalDaysInFirstWeek)) {\r
+ minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;\r
+ }\r
+ var previousSunday = this.getPreviousSunday();\r
+ var startOfMonth = newDateAtMidnight(this.getFullYear(), this.getMonth(), 1);\r
+ var numberOfSundays = previousSunday.isBefore(startOfMonth) ?\r
+ 0 : 1 + Math.floor(previousSunday.getTimeSince(startOfMonth) / ONE_WEEK);\r
+ var numberOfDaysInFirstWeek = 7 - startOfMonth.getDay();\r
+ var weekInMonth = numberOfSundays;\r
+ if (numberOfDaysInFirstWeek >= minimalDaysInFirstWeek) {\r
+ weekInMonth++;\r
+ }\r
+ return weekInMonth;\r
+ };\r
+\r
+ Date.prototype.getDayInYear = function() {\r
+ var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);\r
+ return 1 + Math.floor(this.getTimeSince(startOfYear) / ONE_DAY);\r
+ };\r
+\r
+ /* ------------------------------------------------------------------ */\r
+\r
+ SimpleDateFormat = function(formatString) {\r
+ this.formatString = formatString;\r
+ };\r
+\r
+ /**\r
+ * Sets the minimum number of days in a week in order for that week to\r
+ * be considered as belonging to a particular month or year\r
+ */\r
+ SimpleDateFormat.prototype.setMinimalDaysInFirstWeek = function(days) {\r
+ this.minimalDaysInFirstWeek = days;\r
+ };\r
+\r
+ SimpleDateFormat.prototype.getMinimalDaysInFirstWeek = function() {\r
+ return isUndefined(this.minimalDaysInFirstWeek) ?\r
+ DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK : this.minimalDaysInFirstWeek;\r
+ };\r
+\r
+ var padWithZeroes = function(str, len) {\r
+ while (str.length < len) {\r
+ str = "0" + str;\r
+ }\r
+ return str;\r
+ };\r
+\r
+ var formatText = function(data, numberOfLetters, minLength) {\r
+ return (numberOfLetters >= 4) ? data : data.substr(0, Math.max(minLength, numberOfLetters));\r
+ };\r
+\r
+ var formatNumber = function(data, numberOfLetters) {\r
+ var dataString = "" + data;\r
+ // Pad with 0s as necessary\r
+ return padWithZeroes(dataString, numberOfLetters);\r
+ };\r
+\r
+ SimpleDateFormat.prototype.format = function(date) {\r
+ var formattedString = "";\r
+ var result;\r
+ var searchString = this.formatString;\r
+ while ((result = regex.exec(searchString))) {\r
+ var quotedString = result[1];\r
+ var patternLetters = result[2];\r
+ var otherLetters = result[3];\r
+ var otherCharacters = result[4];\r
+\r
+ // If the pattern matched is quoted string, output the text between the quotes\r
+ if (quotedString) {\r
+ if (quotedString == "''") {\r
+ formattedString += "'";\r
+ } else {\r
+ formattedString += quotedString.substring(1, quotedString.length - 1);\r
+ }\r
+ } else if (otherLetters) {\r
+ // Swallow non-pattern letters by doing nothing here\r
+ } else if (otherCharacters) {\r
+ // Simply output other characters\r
+ formattedString += otherCharacters;\r
+ } else if (patternLetters) {\r
+ // Replace pattern letters\r
+ var patternLetter = patternLetters.charAt(0);\r
+ var numberOfLetters = patternLetters.length;\r
+ var rawData = "";\r
+ switch(patternLetter) {\r
+ case "G":\r
+ rawData = "AD";\r
+ break;\r
+ case "y":\r
+ rawData = date.getFullYear();\r
+ break;\r
+ case "M":\r
+ rawData = date.getMonth();\r
+ break;\r
+ case "w":\r
+ rawData = date.getWeekInYear(this.getMinimalDaysInFirstWeek());\r
+ break;\r
+ case "W":\r
+ rawData = date.getWeekInMonth(this.getMinimalDaysInFirstWeek());\r
+ break;\r
+ case "D":\r
+ rawData = date.getDayInYear();\r
+ break;\r
+ case "d":\r
+ rawData = date.getDate();\r
+ break;\r
+ case "F":\r
+ rawData = 1 + Math.floor((date.getDate() - 1) / 7);\r
+ break;\r
+ case "E":\r
+ rawData = dayNames[date.getDay()];\r
+ break;\r
+ case "a":\r
+ rawData = (date.getHours() >= 12) ? "PM" : "AM";\r
+ break;\r
+ case "H":\r
+ rawData = date.getHours();\r
+ break;\r
+ case "k":\r
+ rawData = date.getHours() || 24;\r
+ break;\r
+ case "K":\r
+ rawData = date.getHours() % 12;\r
+ break;\r
+ case "h":\r
+ rawData = (date.getHours() % 12) || 12;\r
+ break;\r
+ case "m":\r
+ rawData = date.getMinutes();\r
+ break;\r
+ case "s":\r
+ rawData = date.getSeconds();\r
+ break;\r
+ case "S":\r
+ rawData = date.getMilliseconds();\r
+ break;\r
+ case "Z":\r
+ rawData = date.getTimezoneOffset(); // This returns the number of minutes since GMT was this time.\r
+ break;\r
+ }\r
+ // Format the raw data depending on the type\r
+ switch(types[patternLetter]) {\r
+ case TEXT2:\r
+ formattedString += formatText(rawData, numberOfLetters, 2);\r
+ break;\r
+ case TEXT3:\r
+ formattedString += formatText(rawData, numberOfLetters, 3);\r
+ break;\r
+ case NUMBER:\r
+ formattedString += formatNumber(rawData, numberOfLetters);\r
+ break;\r
+ case YEAR:\r
+ if (numberOfLetters <= 3) {\r
+ // Output a 2-digit year\r
+ var dataString = "" + rawData;\r
+ formattedString += dataString.substr(2, 2);\r
+ } else {\r
+ formattedString += formatNumber(rawData, numberOfLetters);\r
+ }\r
+ break;\r
+ case MONTH:\r
+ if (numberOfLetters >= 3) {\r
+ formattedString += formatText(monthNames[rawData], numberOfLetters, numberOfLetters);\r
+ } else {\r
+ // NB. Months returned by getMonth are zero-based\r
+ formattedString += formatNumber(rawData + 1, numberOfLetters);\r
+ }\r
+ break;\r
+ case TIMEZONE:\r
+ var isPositive = (rawData > 0);\r
+ // The following line looks like a mistake but isn't\r
+ // because of the way getTimezoneOffset measures.\r
+ var prefix = isPositive ? "-" : "+";\r
+ var absData = Math.abs(rawData);\r
+\r
+ // Hours\r
+ var hours = "" + Math.floor(absData / 60);\r
+ hours = padWithZeroes(hours, 2);\r
+ // Minutes\r
+ var minutes = "" + (absData % 60);\r
+ minutes = padWithZeroes(minutes, 2);\r
+\r
+ formattedString += prefix + hours + minutes;\r
+ break;\r
+ }\r
+ }\r
+ searchString = searchString.substr(result.index + result[0].length);\r
+ }\r
+ return formattedString;\r
+ };\r
+ })();\r
+\r
+ log4javascript.SimpleDateFormat = SimpleDateFormat;\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // PatternLayout\r
+\r
+ function PatternLayout(pattern) {\r
+ if (pattern) {\r
+ this.pattern = pattern;\r
+ } else {\r
+ this.pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;\r
+ }\r
+ this.customFields = [];\r
+ }\r
+\r
+ PatternLayout.TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n";\r
+ PatternLayout.DEFAULT_CONVERSION_PATTERN = "%m%n";\r
+ PatternLayout.ISO8601_DATEFORMAT = "yyyy-MM-dd HH:mm:ss,SSS";\r
+ PatternLayout.DATETIME_DATEFORMAT = "dd MMM yyyy HH:mm:ss,SSS";\r
+ PatternLayout.ABSOLUTETIME_DATEFORMAT = "HH:mm:ss,SSS";\r
+\r
+ PatternLayout.prototype = new Layout();\r
+\r
+ PatternLayout.prototype.format = function(loggingEvent) {\r
+ var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;\r
+ var formattedString = "";\r
+ var result;\r
+ var searchString = this.pattern;\r
+\r
+ // Cannot use regex global flag since it doesn't work with exec in IE5\r
+ while ((result = regex.exec(searchString))) {\r
+ var matchedString = result[0];\r
+ var padding = result[1];\r
+ var truncation = result[2];\r
+ var conversionCharacter = result[3];\r
+ var specifier = result[5];\r
+ var text = result[6];\r
+\r
+ // Check if the pattern matched was just normal text\r
+ if (text) {\r
+ formattedString += "" + text;\r
+ } else {\r
+ // Create a raw replacement string based on the conversion\r
+ // character and specifier\r
+ var replacement = "";\r
+ switch(conversionCharacter) {\r
+ case "a": // Array of messages\r
+ case "m": // Message\r
+ var depth = 0;\r
+ if (specifier) {\r
+ depth = parseInt(specifier, 10);\r
+ if (isNaN(depth)) {\r
+ handleError("PatternLayout.format: invalid specifier '" +\r
+ specifier + "' for conversion character '" + conversionCharacter +\r
+ "' - should be a number");\r
+ depth = 0;\r
+ }\r
+ }\r
+ var messages = (conversionCharacter === "a") ? loggingEvent.messages[0] : loggingEvent.messages;\r
+ for (var i = 0, len = messages.length; i < len; i++) {\r
+ if (i > 0 && (replacement.charAt(replacement.length - 1) !== " ")) {\r
+ replacement += " ";\r
+ }\r
+ if (depth === 0) {\r
+ replacement += messages[i];\r
+ } else {\r
+ replacement += formatObjectExpansion(messages[i], depth);\r
+ }\r
+ }\r
+ break;\r
+ case "c": // Logger name\r
+ var loggerName = loggingEvent.logger.name;\r
+ if (specifier) {\r
+ var precision = parseInt(specifier, 10);\r
+ var loggerNameBits = loggingEvent.logger.name.split(".");\r
+ if (precision >= loggerNameBits.length) {\r
+ replacement = loggerName;\r
+ } else {\r
+ replacement = loggerNameBits.slice(loggerNameBits.length - precision).join(".");\r
+ }\r
+ } else {\r
+ replacement = loggerName;\r
+ }\r
+ break;\r
+ case "d": // Date\r
+ var dateFormat = PatternLayout.ISO8601_DATEFORMAT;\r
+ if (specifier) {\r
+ dateFormat = specifier;\r
+ // Pick up special cases\r
+ if (dateFormat == "ISO8601") {\r
+ dateFormat = PatternLayout.ISO8601_DATEFORMAT;\r
+ } else if (dateFormat == "ABSOLUTE") {\r
+ dateFormat = PatternLayout.ABSOLUTETIME_DATEFORMAT;\r
+ } else if (dateFormat == "DATE") {\r
+ dateFormat = PatternLayout.DATETIME_DATEFORMAT;\r
+ }\r
+ }\r
+ // Format the date\r
+ replacement = (new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);\r
+ break;\r
+ case "f": // Custom field\r
+ if (this.hasCustomFields()) {\r
+ var fieldIndex = 0;\r
+ if (specifier) {\r
+ fieldIndex = parseInt(specifier, 10);\r
+ if (isNaN(fieldIndex)) {\r
+ handleError("PatternLayout.format: invalid specifier '" +\r
+ specifier + "' for conversion character 'f' - should be a number");\r
+ } else if (fieldIndex === 0) {\r
+ handleError("PatternLayout.format: invalid specifier '" +\r
+ specifier + "' for conversion character 'f' - must be greater than zero");\r
+ } else if (fieldIndex > this.customFields.length) {\r
+ handleError("PatternLayout.format: invalid specifier '" +\r
+ specifier + "' for conversion character 'f' - there aren't that many custom fields");\r
+ } else {\r
+ fieldIndex = fieldIndex - 1;\r
+ }\r
+ }\r
+ var val = this.customFields[fieldIndex].value;\r
+ if (typeof val == "function") {\r
+ val = val(this, loggingEvent);\r
+ }\r
+ replacement = val;\r
+ }\r
+ break;\r
+ case "n": // New line\r
+ replacement = newLine;\r
+ break;\r
+ case "p": // Level\r
+ replacement = loggingEvent.level.name;\r
+ break;\r
+ case "r": // Milliseconds since log4javascript startup\r
+ replacement = "" + loggingEvent.timeStamp.getDifference(applicationStartDate);\r
+ break;\r
+ case "%": // Literal % sign\r
+ replacement = "%";\r
+ break;\r
+ default:\r
+ replacement = matchedString;\r
+ break;\r
+ }\r
+ // Format the replacement according to any padding or\r
+ // truncation specified\r
+ var l;\r
+\r
+ // First, truncation\r
+ if (truncation) {\r
+ l = parseInt(truncation.substr(1), 10);\r
+ var strLen = replacement.length;\r
+ if (l < strLen) {\r
+ replacement = replacement.substring(strLen - l, strLen);\r
+ }\r
+ }\r
+ // Next, padding\r
+ if (padding) {\r
+ if (padding.charAt(0) == "-") {\r
+ l = parseInt(padding.substr(1), 10);\r
+ // Right pad with spaces\r
+ while (replacement.length < l) {\r
+ replacement += " ";\r
+ }\r
+ } else {\r
+ l = parseInt(padding, 10);\r
+ // Left pad with spaces\r
+ while (replacement.length < l) {\r
+ replacement = " " + replacement;\r
+ }\r
+ }\r
+ }\r
+ formattedString += replacement;\r
+ }\r
+ searchString = searchString.substr(result.index + result[0].length);\r
+ }\r
+ return formattedString;\r
+ };\r
+\r
+ PatternLayout.prototype.ignoresThrowable = function() {\r
+ return true;\r
+ };\r
+\r
+ PatternLayout.prototype.toString = function() {\r
+ return "PatternLayout";\r
+ };\r
+\r
+ log4javascript.PatternLayout = PatternLayout;\r
+ /* ---------------------------------------------------------------------- */\r
+ // AlertAppender\r
+\r
+ function AlertAppender() {}\r
+\r
+ AlertAppender.prototype = new Appender();\r
+\r
+ AlertAppender.prototype.layout = new SimpleLayout();\r
+\r
+ AlertAppender.prototype.append = function(loggingEvent) {\r
+ var formattedMessage = this.getLayout().format(loggingEvent);\r
+ if (this.getLayout().ignoresThrowable()) {\r
+ formattedMessage += loggingEvent.getThrowableStrRep();\r
+ }\r
+ alert(formattedMessage);\r
+ };\r
+\r
+ AlertAppender.prototype.toString = function() {\r
+ return "AlertAppender";\r
+ };\r
+\r
+ log4javascript.AlertAppender = AlertAppender;\r
+ /* ---------------------------------------------------------------------- */\r
+ // BrowserConsoleAppender (only works in Opera and Safari and Firefox with\r
+ // Firebug extension)\r
+\r
+ function BrowserConsoleAppender() {}\r
+\r
+ BrowserConsoleAppender.prototype = new log4javascript.Appender();\r
+ BrowserConsoleAppender.prototype.layout = new NullLayout();\r
+ BrowserConsoleAppender.prototype.threshold = Level.DEBUG;\r
+\r
+ BrowserConsoleAppender.prototype.append = function(loggingEvent) {\r
+ var appender = this;\r
+\r
+ var getFormattedMessage = function() {\r
+ var layout = appender.getLayout();\r
+ var formattedMessage = layout.format(loggingEvent);\r
+ if (layout.ignoresThrowable() && loggingEvent.exception) {\r
+ formattedMessage += loggingEvent.getThrowableStrRep();\r
+ }\r
+ return formattedMessage;\r
+ };\r
+\r
+ if ((typeof opera != "undefined") && opera.postError) { // Opera\r
+ opera.postError(getFormattedMessage());\r
+ } else if (window.console && window.console.log) { // Safari and Firebug\r
+ var formattedMesage = getFormattedMessage();\r
+ // Log to Firebug using its logging methods or revert to the console.log\r
+ // method in Safari\r
+ if (window.console.debug && Level.DEBUG.isGreaterOrEqual(loggingEvent.level)) {\r
+ window.console.debug(formattedMesage);\r
+ } else if (window.console.info && Level.INFO.equals(loggingEvent.level)) {\r
+ window.console.info(formattedMesage);\r
+ } else if (window.console.warn && Level.WARN.equals(loggingEvent.level)) {\r
+ window.console.warn(formattedMesage);\r
+ } else if (window.console.error && loggingEvent.level.isGreaterOrEqual(Level.ERROR)) {\r
+ window.console.error(formattedMesage);\r
+ } else {\r
+ window.console.log(formattedMesage);\r
+ }\r
+ }\r
+ };\r
+\r
+ BrowserConsoleAppender.prototype.group = function(name) {\r
+ if (window.console && window.console.group) {\r
+ window.console.group(name);\r
+ }\r
+ };\r
+\r
+ BrowserConsoleAppender.prototype.groupEnd = function() {\r
+ if (window.console && window.console.groupEnd) {\r
+ window.console.groupEnd();\r
+ }\r
+ };\r
+\r
+ BrowserConsoleAppender.prototype.toString = function() {\r
+ return "BrowserConsoleAppender";\r
+ };\r
+\r
+ log4javascript.BrowserConsoleAppender = BrowserConsoleAppender;\r
+ /* ---------------------------------------------------------------------- */\r
+ // AjaxAppender related\r
+\r
+ var xmlHttpFactories = [\r
+ function() { return new XMLHttpRequest(); },\r
+ function() { return new ActiveXObject("Msxml2.XMLHTTP"); },\r
+ function() { return new ActiveXObject("Microsoft.XMLHTTP"); }\r
+ ];\r
+\r
+ var getXmlHttp = function(errorHandler) {\r
+ // This is only run the first time; the value of getXmlHttp gets\r
+ // replaced with the factory that succeeds on the first run\r
+ var xmlHttp = null, factory;\r
+ for (var i = 0, len = xmlHttpFactories.length; i < len; i++) {\r
+ factory = xmlHttpFactories[i];\r
+ try {\r
+ xmlHttp = factory();\r
+ getXmlHttp = factory;\r
+ return xmlHttp;\r
+ } catch (e) {\r
+ }\r
+ }\r
+ // If we're here, all factories have failed, so throw an error\r
+ if (errorHandler) {\r
+ errorHandler();\r
+ } else {\r
+ handleError("getXmlHttp: unable to obtain XMLHttpRequest object");\r
+ }\r
+ };\r
+\r
+ function isHttpRequestSuccessful(xmlHttp) {\r
+ return isUndefined(xmlHttp.status) || xmlHttp.status === 0 ||\r
+ (xmlHttp.status >= 200 && xmlHttp.status < 300) ||\r
+ xmlHttp.status == 1223 /* Fix for IE */;\r
+ }\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // AjaxAppender\r
+\r
+ function AjaxAppender(url) {\r
+ var appender = this;\r
+ var isSupported = true;\r
+ if (!url) {\r
+ handleError("AjaxAppender: URL must be specified in constructor");\r
+ isSupported = false;\r
+ }\r
+\r
+ var timed = this.defaults.timed;\r
+ var waitForResponse = this.defaults.waitForResponse;\r
+ var batchSize = this.defaults.batchSize;\r
+ var timerInterval = this.defaults.timerInterval;\r
+ var requestSuccessCallback = this.defaults.requestSuccessCallback;\r
+ var failCallback = this.defaults.failCallback;\r
+ var postVarName = this.defaults.postVarName;\r
+ var sendAllOnUnload = this.defaults.sendAllOnUnload;\r
+ var contentType = this.defaults.contentType;\r
+ var sessionId = null;\r
+\r
+ var queuedLoggingEvents = [];\r
+ var queuedRequests = [];\r
+ var headers = [];\r
+ var sending = false;\r
+ var initialized = false;\r
+\r
+ // Configuration methods. The function scope is used to prevent\r
+ // direct alteration to the appender configuration properties.\r
+ function checkCanConfigure(configOptionName) {\r
+ if (initialized) {\r
+ handleError("AjaxAppender: configuration option '" +\r
+ configOptionName +\r
+ "' may not be set after the appender has been initialized");\r
+ return false;\r
+ }\r
+ return true;\r
+ }\r
+\r
+ this.getSessionId = function() { return sessionId; };\r
+ this.setSessionId = function(sessionIdParam) {\r
+ sessionId = extractStringFromParam(sessionIdParam, null);\r
+ this.layout.setCustomField("sessionid", sessionId);\r
+ };\r
+\r
+ this.setLayout = function(layoutParam) {\r
+ if (checkCanConfigure("layout")) {\r
+ this.layout = layoutParam;\r
+ // Set the session id as a custom field on the layout, if not already present\r
+ if (sessionId !== null) {\r
+ this.setSessionId(sessionId);\r
+ }\r
+ }\r
+ };\r
+\r
+ this.isTimed = function() { return timed; };\r
+ this.setTimed = function(timedParam) {\r
+ if (checkCanConfigure("timed")) {\r
+ timed = bool(timedParam);\r
+ }\r
+ };\r
+\r
+ this.getTimerInterval = function() { return timerInterval; };\r
+ this.setTimerInterval = function(timerIntervalParam) {\r
+ if (checkCanConfigure("timerInterval")) {\r
+ timerInterval = extractIntFromParam(timerIntervalParam, timerInterval);\r
+ }\r
+ };\r
+\r
+ this.isWaitForResponse = function() { return waitForResponse; };\r
+ this.setWaitForResponse = function(waitForResponseParam) {\r
+ if (checkCanConfigure("waitForResponse")) {\r
+ waitForResponse = bool(waitForResponseParam);\r
+ }\r
+ };\r
+\r
+ this.getBatchSize = function() { return batchSize; };\r
+ this.setBatchSize = function(batchSizeParam) {\r
+ if (checkCanConfigure("batchSize")) {\r
+ batchSize = extractIntFromParam(batchSizeParam, batchSize);\r
+ }\r
+ };\r
+\r
+ this.isSendAllOnUnload = function() { return sendAllOnUnload; };\r
+ this.setSendAllOnUnload = function(sendAllOnUnloadParam) {\r
+ if (checkCanConfigure("sendAllOnUnload")) {\r
+ sendAllOnUnload = extractBooleanFromParam(sendAllOnUnloadParam, sendAllOnUnload);\r
+ }\r
+ };\r
+\r
+ this.setRequestSuccessCallback = function(requestSuccessCallbackParam) {\r
+ requestSuccessCallback = extractFunctionFromParam(requestSuccessCallbackParam, requestSuccessCallback);\r
+ };\r
+\r
+ this.setFailCallback = function(failCallbackParam) {\r
+ failCallback = extractFunctionFromParam(failCallbackParam, failCallback);\r
+ };\r
+\r
+ this.getPostVarName = function() { return postVarName; };\r
+ this.setPostVarName = function(postVarNameParam) {\r
+ if (checkCanConfigure("postVarName")) {\r
+ postVarName = extractStringFromParam(postVarNameParam, postVarName);\r
+ }\r
+ };\r
+\r
+ this.getHeaders = function() { return headers; };\r
+ this.addHeader = function(name, value) {\r
+ if (name.toLowerCase() == "content-type") {\r
+ contentType = value;\r
+ } else {\r
+ headers.push( { name: name, value: value } );\r
+ }\r
+ };\r
+\r
+ // Internal functions\r
+ function sendAll() {\r
+ if (isSupported && enabled) {\r
+ sending = true;\r
+ var currentRequestBatch;\r
+ if (waitForResponse) {\r
+ // Send the first request then use this function as the callback once\r
+ // the response comes back\r
+ if (queuedRequests.length > 0) {\r
+ currentRequestBatch = queuedRequests.shift();\r
+ sendRequest(preparePostData(currentRequestBatch), sendAll);\r
+ } else {\r
+ sending = false;\r
+ if (timed) {\r
+ scheduleSending();\r
+ }\r
+ }\r
+ } else {\r
+ // Rattle off all the requests without waiting to see the response\r
+ while ((currentRequestBatch = queuedRequests.shift())) {\r
+ sendRequest(preparePostData(currentRequestBatch));\r
+ }\r
+ sending = false;\r
+ if (timed) {\r
+ scheduleSending();\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ this.sendAll = sendAll;\r
+\r
+ // Called when the window unloads. At this point we're past caring about\r
+ // waiting for responses or timers or incomplete batches - everything\r
+ // must go, now\r
+ function sendAllRemaining() {\r
+ var sendingAnything = false;\r
+ if (isSupported && enabled) {\r
+ // Create requests for everything left over, batched as normal\r
+ var actualBatchSize = appender.getLayout().allowBatching() ? batchSize : 1;\r
+ var currentLoggingEvent;\r
+ var batchedLoggingEvents = [];\r
+ while ((currentLoggingEvent = queuedLoggingEvents.shift())) {\r
+ batchedLoggingEvents.push(currentLoggingEvent);\r
+ if (queuedLoggingEvents.length >= actualBatchSize) {\r
+ // Queue this batch of log entries\r
+ queuedRequests.push(batchedLoggingEvents);\r
+ batchedLoggingEvents = [];\r
+ }\r
+ }\r
+ // If there's a partially completed batch, add it\r
+ if (batchedLoggingEvents.length > 0) {\r
+ queuedRequests.push(batchedLoggingEvents);\r
+ }\r
+ sendingAnything = (queuedRequests.length > 0);\r
+ waitForResponse = false;\r
+ timed = false;\r
+ sendAll();\r
+ }\r
+ return sendingAnything;\r
+ }\r
+\r
+ this.sendAllRemaining = sendAllRemaining;\r
+\r
+ function preparePostData(batchedLoggingEvents) {\r
+ // Format the logging events\r
+ var formattedMessages = [];\r
+ var currentLoggingEvent;\r
+ var postData = "";\r
+ while ((currentLoggingEvent = batchedLoggingEvents.shift())) {\r
+ var currentFormattedMessage = appender.getLayout().format(currentLoggingEvent);\r
+ if (appender.getLayout().ignoresThrowable()) {\r
+ currentFormattedMessage += currentLoggingEvent.getThrowableStrRep();\r
+ }\r
+ formattedMessages.push(currentFormattedMessage);\r
+ }\r
+ // Create the post data string\r
+ if (batchedLoggingEvents.length == 1) {\r
+ postData = formattedMessages.join("");\r
+ } else {\r
+ postData = appender.getLayout().batchHeader +\r
+ formattedMessages.join(appender.getLayout().batchSeparator) +\r
+ appender.getLayout().batchFooter;\r
+ }\r
+ if (contentType == appender.defaults.contentType) {\r
+ postData = appender.getLayout().returnsPostData ? postData :\r
+ urlEncode(postVarName) + "=" + urlEncode(postData);\r
+ // Add the layout name to the post data\r
+ if (postData.length > 0) {\r
+ postData += "&";\r
+ }\r
+ postData += "layout=" + urlEncode(appender.getLayout().toString());\r
+ }\r
+ return postData;\r
+ }\r
+\r
+ function scheduleSending() {\r
+ window.setTimeout(sendAll, timerInterval);\r
+ }\r
+\r
+ function xmlHttpErrorHandler() {\r
+ var msg = "AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";\r
+ handleError(msg);\r
+ isSupported = false;\r
+ if (failCallback) {\r
+ failCallback(msg);\r
+ }\r
+ }\r
+\r
+ function sendRequest(postData, successCallback) {\r
+ try {\r
+ var xmlHttp = getXmlHttp(xmlHttpErrorHandler);\r
+ if (isSupported) {\r
+ if (xmlHttp.overrideMimeType) {\r
+ xmlHttp.overrideMimeType(appender.getLayout().getContentType());\r
+ }\r
+ xmlHttp.onreadystatechange = function() {\r
+ if (xmlHttp.readyState == 4) {\r
+ if (isHttpRequestSuccessful(xmlHttp)) {\r
+ if (requestSuccessCallback) {\r
+ requestSuccessCallback(xmlHttp);\r
+ }\r
+ if (successCallback) {\r
+ successCallback(xmlHttp);\r
+ }\r
+ } else {\r
+ var msg = "AjaxAppender.append: XMLHttpRequest request to URL " +\r
+ url + " returned status code " + xmlHttp.status;\r
+ handleError(msg);\r
+ if (failCallback) {\r
+ failCallback(msg);\r
+ }\r
+ }\r
+ xmlHttp.onreadystatechange = emptyFunction;\r
+ xmlHttp = null;\r
+ }\r
+ };\r
+ xmlHttp.open("POST", url, true);\r
+ try {\r
+ for (var i = 0, header; header = headers[i++]; ) {\r
+ xmlHttp.setRequestHeader(header.name, header.value);\r
+ }\r
+ xmlHttp.setRequestHeader("Content-Type", contentType);\r
+ } catch (headerEx) {\r
+ var msg = "AjaxAppender.append: your browser's XMLHttpRequest implementation" +\r
+ " does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";\r
+ handleError(msg);\r
+ isSupported = false;\r
+ if (failCallback) {\r
+ failCallback(msg);\r
+ }\r
+ return;\r
+ }\r
+ xmlHttp.send(postData);\r
+ }\r
+ } catch (ex) {\r
+ var errMsg = "AjaxAppender.append: error sending log message to " + url;\r
+ handleError(errMsg, ex);\r
+ isSupported = false;\r
+ if (failCallback) {\r
+ failCallback(errMsg + ". Details: " + getExceptionStringRep(ex));\r
+ }\r
+ }\r
+ }\r
+\r
+ this.append = function(loggingEvent) {\r
+ if (isSupported) {\r
+ if (!initialized) {\r
+ init();\r
+ }\r
+ queuedLoggingEvents.push(loggingEvent);\r
+ var actualBatchSize = this.getLayout().allowBatching() ? batchSize : 1;\r
+\r
+ if (queuedLoggingEvents.length >= actualBatchSize) {\r
+ var currentLoggingEvent;\r
+ var batchedLoggingEvents = [];\r
+ while ((currentLoggingEvent = queuedLoggingEvents.shift())) {\r
+ batchedLoggingEvents.push(currentLoggingEvent);\r
+ }\r
+ // Queue this batch of log entries\r
+ queuedRequests.push(batchedLoggingEvents);\r
+\r
+ // If using a timer, the queue of requests will be processed by the\r
+ // timer function, so nothing needs to be done here.\r
+ if (!timed && (!waitForResponse || (waitForResponse && !sending))) {\r
+ sendAll();\r
+ }\r
+ }\r
+ }\r
+ };\r
+\r
+ function init() {\r
+ initialized = true;\r
+ // Add unload event to send outstanding messages\r
+ if (sendAllOnUnload) {\r
+ var oldBeforeUnload = window.onbeforeunload;\r
+ window.onbeforeunload = function() {\r
+ if (oldBeforeUnload) {\r
+ oldBeforeUnload();\r
+ }\r
+ if (sendAllRemaining()) {\r
+ return "Sending log messages";\r
+ }\r
+ };\r
+ }\r
+ // Start timer\r
+ if (timed) {\r
+ scheduleSending();\r
+ }\r
+ }\r
+ }\r
+\r
+ AjaxAppender.prototype = new Appender();\r
+\r
+ AjaxAppender.prototype.defaults = {\r
+ waitForResponse: false,\r
+ timed: false,\r
+ timerInterval: 1000,\r
+ batchSize: 1,\r
+ sendAllOnUnload: false,\r
+ requestSuccessCallback: null,\r
+ failCallback: null,\r
+ postVarName: "data",\r
+ contentType: "application/x-www-form-urlencoded"\r
+ };\r
+\r
+ AjaxAppender.prototype.layout = new HttpPostDataLayout();\r
+\r
+ AjaxAppender.prototype.toString = function() {\r
+ return "AjaxAppender";\r
+ };\r
+\r
+ log4javascript.AjaxAppender = AjaxAppender;\r
+ /* ---------------------------------------------------------------------- */\r
+ // PopUpAppender and InPageAppender related\r
+\r
+ function setCookie(name, value, days, path) {\r
+ var expires;\r
+ path = path ? "; path=" + path : "";\r
+ if (days) {\r
+ var date = new Date();\r
+ date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));\r
+ expires = "; expires=" + date.toGMTString();\r
+ } else {\r
+ expires = "";\r
+ }\r
+ document.cookie = escape(name) + "=" + escape(value) + expires + path;\r
+ }\r
+\r
+ function getCookie(name) {\r
+ var nameEquals = escape(name) + "=";\r
+ var ca = document.cookie.split(";");\r
+ for (var i = 0, len = ca.length; i < len; i++) {\r
+ var c = ca[i];\r
+ while (c.charAt(0) === " ") {\r
+ c = c.substring(1, c.length);\r
+ }\r
+ if (c.indexOf(nameEquals) === 0) {\r
+ return unescape(c.substring(nameEquals.length, c.length));\r
+ }\r
+ }\r
+ return null;\r
+ }\r
+\r
+ // Gets the base URL of the location of the log4javascript script.\r
+ // This is far from infallible.\r
+ function getBaseUrl() {\r
+ var scripts = document.getElementsByTagName("script");\r
+ for (var i = 0, len = scripts.length; i < len; ++i) {\r
+ if (scripts[i].src.indexOf("log4javascript") != -1) {\r
+ var lastSlash = scripts[i].src.lastIndexOf("/");\r
+ return (lastSlash == -1) ? "" : scripts[i].src.substr(0, lastSlash + 1);\r
+ }\r
+ }\r
+ return null;\r
+ }\r
+\r
+ function isLoaded(win) {\r
+ try {\r
+ return bool(win.loaded);\r
+ } catch (ex) {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // ConsoleAppender (prototype for PopUpAppender and InPageAppender)\r
+\r
+ var ConsoleAppender;\r
+\r
+ // Create an anonymous function to protect base console methods\r
+ (function() {\r
+ var getConsoleHtmlLines = function() {\r
+ return [\r
+'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',\r
+'<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">',\r
+' <head>',\r
+' <title>log4javascript</title>',\r
+' <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',\r
+' <!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->',\r
+' <meta http-equiv="X-UA-Compatible" content="IE=7" />',\r
+' <script type="text/javascript">var isIe = false, isIePre7 = false;</script>',\r
+' <!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->',\r
+' <!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->',\r
+' <script type="text/javascript">',\r
+' //<![CDATA[',\r
+' var loggingEnabled = true;',\r
+' var logQueuedEventsTimer = null;',\r
+' var logEntries = [];',\r
+' var logEntriesAndSeparators = [];',\r
+' var logItems = [];',\r
+' var renderDelay = 100;',\r
+' var unrenderedLogItemsExist = false;',\r
+' var rootGroup, currentGroup = null;',\r
+' var loaded = false;',\r
+' var currentLogItem = null;',\r
+' var logMainContainer;',\r
+'',\r
+' function copyProperties(obj, props) {',\r
+' for (var i in props) {',\r
+' obj[i] = props[i];',\r
+' }',\r
+' }',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function LogItem() {',\r
+' }',\r
+'',\r
+' LogItem.prototype = {',\r
+' mainContainer: null,',\r
+' wrappedContainer: null,',\r
+' unwrappedContainer: null,',\r
+' group: null,',\r
+'',\r
+' appendToLog: function() {',\r
+' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',\r
+' this.elementContainers[i].appendToLog();',\r
+' }',\r
+' this.group.update();',\r
+' },',\r
+'',\r
+' doRemove: function(doUpdate, removeFromGroup) {',\r
+' if (this.rendered) {',\r
+' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',\r
+' this.elementContainers[i].remove();',\r
+' }',\r
+' this.unwrappedElementContainer = null;',\r
+' this.wrappedElementContainer = null;',\r
+' this.mainElementContainer = null;',\r
+' }',\r
+' if (this.group && removeFromGroup) {',\r
+' this.group.removeChild(this, doUpdate);',\r
+' }',\r
+' if (this === currentLogItem) {',\r
+' currentLogItem = null;',\r
+' }',\r
+' },',\r
+'',\r
+' remove: function(doUpdate, removeFromGroup) {',\r
+' this.doRemove(doUpdate, removeFromGroup);',\r
+' },',\r
+'',\r
+' render: function() {},',\r
+'',\r
+' accept: function(visitor) {',\r
+' visitor.visit(this);',\r
+' },',\r
+'',\r
+' getUnwrappedDomContainer: function() {',\r
+' return this.group.unwrappedElementContainer.contentDiv;',\r
+' },',\r
+'',\r
+' getWrappedDomContainer: function() {',\r
+' return this.group.wrappedElementContainer.contentDiv;',\r
+' },',\r
+'',\r
+' getMainDomContainer: function() {',\r
+' return this.group.mainElementContainer.contentDiv;',\r
+' }',\r
+' };',\r
+'',\r
+' LogItem.serializedItemKeys = {LOG_ENTRY: 0, GROUP_START: 1, GROUP_END: 2};',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function LogItemContainerElement() {',\r
+' }',\r
+'',\r
+' LogItemContainerElement.prototype = {',\r
+' appendToLog: function() {',\r
+' var insertBeforeFirst = (newestAtTop && this.containerDomNode.hasChildNodes());',\r
+' if (insertBeforeFirst) {',\r
+' this.containerDomNode.insertBefore(this.mainDiv, this.containerDomNode.firstChild);',\r
+' } else {',\r
+' this.containerDomNode.appendChild(this.mainDiv);',\r
+' }',\r
+' }',\r
+' };',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function SeparatorElementContainer(containerDomNode) {',\r
+' this.containerDomNode = containerDomNode;',\r
+' this.mainDiv = document.createElement("div");',\r
+' this.mainDiv.className = "separator";',\r
+' this.mainDiv.innerHTML = " ";',\r
+' }',\r
+'',\r
+' SeparatorElementContainer.prototype = new LogItemContainerElement();',\r
+'',\r
+' SeparatorElementContainer.prototype.remove = function() {',\r
+' this.mainDiv.parentNode.removeChild(this.mainDiv);',\r
+' this.mainDiv = null;',\r
+' };',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function Separator() {',\r
+' this.rendered = false;',\r
+' }',\r
+'',\r
+' Separator.prototype = new LogItem();',\r
+'',\r
+' copyProperties(Separator.prototype, {',\r
+' render: function() {',\r
+' var containerDomNode = this.group.contentDiv;',\r
+' if (isIe) {',\r
+' this.unwrappedElementContainer = new SeparatorElementContainer(this.getUnwrappedDomContainer());',\r
+' this.wrappedElementContainer = new SeparatorElementContainer(this.getWrappedDomContainer());',\r
+' this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',\r
+' } else {',\r
+' this.mainElementContainer = new SeparatorElementContainer(this.getMainDomContainer());',\r
+' this.elementContainers = [this.mainElementContainer];',\r
+' }',\r
+' this.content = this.formattedMessage;',\r
+' this.rendered = true;',\r
+' }',\r
+' });',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function GroupElementContainer(group, containerDomNode, isRoot, isWrapped) {',\r
+' this.group = group;',\r
+' this.containerDomNode = containerDomNode;',\r
+' this.isRoot = isRoot;',\r
+' this.isWrapped = isWrapped;',\r
+' this.expandable = false;',\r
+'',\r
+' if (this.isRoot) {',\r
+' if (isIe) {',\r
+' this.contentDiv = logMainContainer.appendChild(document.createElement("div"));',\r
+' this.contentDiv.id = this.isWrapped ? "log_wrapped" : "log_unwrapped";',\r
+' } else {',\r
+' this.contentDiv = logMainContainer;',\r
+' }',\r
+' } else {',\r
+' var groupElementContainer = this;',\r
+' ',\r
+' this.mainDiv = document.createElement("div");',\r
+' this.mainDiv.className = "group";',\r
+'',\r
+' this.headingDiv = this.mainDiv.appendChild(document.createElement("div"));',\r
+' this.headingDiv.className = "groupheading";',\r
+'',\r
+' this.expander = this.headingDiv.appendChild(document.createElement("span"));',\r
+' this.expander.className = "expander unselectable greyedout";',\r
+' this.expander.unselectable = true;',\r
+' var expanderText = this.group.expanded ? "-" : "+";',\r
+' this.expanderTextNode = this.expander.appendChild(document.createTextNode(expanderText));',\r
+' ',\r
+' this.headingDiv.appendChild(document.createTextNode(" " + this.group.name));',\r
+'',\r
+' this.contentDiv = this.mainDiv.appendChild(document.createElement("div"));',\r
+' var contentCssClass = this.group.expanded ? "expanded" : "collapsed";',\r
+' this.contentDiv.className = "groupcontent " + contentCssClass;',\r
+'',\r
+' this.expander.onclick = function() {',\r
+' if (groupElementContainer.group.expandable) {',\r
+' groupElementContainer.group.toggleExpanded();',\r
+' }',\r
+' };',\r
+' }',\r
+' }',\r
+'',\r
+' GroupElementContainer.prototype = new LogItemContainerElement();',\r
+'',\r
+' copyProperties(GroupElementContainer.prototype, {',\r
+' toggleExpanded: function() {',\r
+' if (!this.isRoot) {',\r
+' var oldCssClass, newCssClass, expanderText;',\r
+' if (this.group.expanded) {',\r
+' newCssClass = "expanded";',\r
+' oldCssClass = "collapsed";',\r
+' expanderText = "-";',\r
+' } else {',\r
+' newCssClass = "collapsed";',\r
+' oldCssClass = "expanded";',\r
+' expanderText = "+";',\r
+' }',\r
+' replaceClass(this.contentDiv, newCssClass, oldCssClass);',\r
+' this.expanderTextNode.nodeValue = expanderText;',\r
+' }',\r
+' },',\r
+'',\r
+' remove: function() {',\r
+' if (!this.isRoot) {',\r
+' this.headingDiv = null;',\r
+' this.expander.onclick = null;',\r
+' this.expander = null;',\r
+' this.expanderTextNode = null;',\r
+' this.contentDiv = null;',\r
+' this.containerDomNode = null;',\r
+' this.mainDiv.parentNode.removeChild(this.mainDiv);',\r
+' this.mainDiv = null;',\r
+' }',\r
+' },',\r
+'',\r
+' reverseChildren: function() {',\r
+' // Invert the order of the log entries',\r
+' var node = null;',\r
+'',\r
+' // Remove all the log container nodes',\r
+' var childDomNodes = [];',\r
+' while ((node = this.contentDiv.firstChild)) {',\r
+' this.contentDiv.removeChild(node);',\r
+' childDomNodes.push(node);',\r
+' }',\r
+'',\r
+' // Put them all back in reverse order',\r
+' while ((node = childDomNodes.pop())) {',\r
+' this.contentDiv.appendChild(node);',\r
+' }',\r
+' },',\r
+'',\r
+' update: function() {',\r
+' if (!this.isRoot) {',\r
+' if (this.group.expandable) {',\r
+' removeClass(this.expander, "greyedout");',\r
+' } else {',\r
+' addClass(this.expander, "greyedout");',\r
+' }',\r
+' }',\r
+' },',\r
+'',\r
+' clear: function() {',\r
+' if (this.isRoot) {',\r
+' this.contentDiv.innerHTML = "";',\r
+' }',\r
+' }',\r
+' });',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function Group(name, isRoot, initiallyExpanded) {',\r
+' this.name = name;',\r
+' this.group = null;',\r
+' this.isRoot = isRoot;',\r
+' this.initiallyExpanded = initiallyExpanded;',\r
+' this.elementContainers = [];',\r
+' this.children = [];',\r
+' this.expanded = initiallyExpanded;',\r
+' this.rendered = false;',\r
+' this.expandable = false;',\r
+' }',\r
+'',\r
+' Group.prototype = new LogItem();',\r
+'',\r
+' copyProperties(Group.prototype, {',\r
+' addChild: function(logItem) {',\r
+' this.children.push(logItem);',\r
+' logItem.group = this;',\r
+' },',\r
+'',\r
+' render: function() {',\r
+' if (isIe) {',\r
+' var unwrappedDomContainer, wrappedDomContainer;',\r
+' if (this.isRoot) {',\r
+' unwrappedDomContainer = logMainContainer;',\r
+' wrappedDomContainer = logMainContainer;',\r
+' } else {',\r
+' unwrappedDomContainer = this.getUnwrappedDomContainer();',\r
+' wrappedDomContainer = this.getWrappedDomContainer();',\r
+' }',\r
+' this.unwrappedElementContainer = new GroupElementContainer(this, unwrappedDomContainer, this.isRoot, false);',\r
+' this.wrappedElementContainer = new GroupElementContainer(this, wrappedDomContainer, this.isRoot, true);',\r
+' this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',\r
+' } else {',\r
+' var mainDomContainer = this.isRoot ? logMainContainer : this.getMainDomContainer();',\r
+' this.mainElementContainer = new GroupElementContainer(this, mainDomContainer, this.isRoot, false);',\r
+' this.elementContainers = [this.mainElementContainer];',\r
+' }',\r
+' this.rendered = true;',\r
+' },',\r
+'',\r
+' toggleExpanded: function() {',\r
+' this.expanded = !this.expanded;',\r
+' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',\r
+' this.elementContainers[i].toggleExpanded();',\r
+' }',\r
+' },',\r
+'',\r
+' expand: function() {',\r
+' if (!this.expanded) {',\r
+' this.toggleExpanded();',\r
+' }',\r
+' },',\r
+'',\r
+' accept: function(visitor) {',\r
+' visitor.visitGroup(this);',\r
+' },',\r
+'',\r
+' reverseChildren: function() {',\r
+' if (this.rendered) {',\r
+' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',\r
+' this.elementContainers[i].reverseChildren();',\r
+' }',\r
+' }',\r
+' },',\r
+'',\r
+' update: function() {',\r
+' var previouslyExpandable = this.expandable;',\r
+' this.expandable = (this.children.length !== 0);',\r
+' if (this.expandable !== previouslyExpandable) {',\r
+' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',\r
+' this.elementContainers[i].update();',\r
+' }',\r
+' }',\r
+' },',\r
+'',\r
+' flatten: function() {',\r
+' var visitor = new GroupFlattener();',\r
+' this.accept(visitor);',\r
+' return visitor.logEntriesAndSeparators;',\r
+' },',\r
+'',\r
+' removeChild: function(child, doUpdate) {',\r
+' array_remove(this.children, child);',\r
+' child.group = null;',\r
+' if (doUpdate) {',\r
+' this.update();',\r
+' }',\r
+' },',\r
+'',\r
+' remove: function(doUpdate, removeFromGroup) {',\r
+' for (var i = 0, len = this.children.length; i < len; i++) {',\r
+' this.children[i].remove(false, false);',\r
+' }',\r
+' this.children = [];',\r
+' this.update();',\r
+' if (this === currentGroup) {',\r
+' currentGroup = this.group;',\r
+' }',\r
+' this.doRemove(doUpdate, removeFromGroup);',\r
+' },',\r
+'',\r
+' serialize: function(items) {',\r
+' items.push([LogItem.serializedItemKeys.GROUP_START, this.name]);',\r
+' for (var i = 0, len = this.children.length; i < len; i++) {',\r
+' this.children[i].serialize(items);',\r
+' }',\r
+' if (this !== currentGroup) {',\r
+' items.push([LogItem.serializedItemKeys.GROUP_END]);',\r
+' }',\r
+' },',\r
+'',\r
+' clear: function() {',\r
+' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',\r
+' this.elementContainers[i].clear();',\r
+' }',\r
+' }',\r
+' });',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function LogEntryElementContainer() {',\r
+' }',\r
+'',\r
+' LogEntryElementContainer.prototype = new LogItemContainerElement();',\r
+'',\r
+' copyProperties(LogEntryElementContainer.prototype, {',\r
+' remove: function() {',\r
+' this.doRemove();',\r
+' },',\r
+'',\r
+' doRemove: function() {',\r
+' this.mainDiv.parentNode.removeChild(this.mainDiv);',\r
+' this.mainDiv = null;',\r
+' this.contentElement = null;',\r
+' this.containerDomNode = null;',\r
+' },',\r
+'',\r
+' setContent: function(content, wrappedContent) {',\r
+' if (content === this.formattedMessage) {',\r
+' this.contentElement.innerHTML = "";',\r
+' this.contentElement.appendChild(document.createTextNode(this.formattedMessage));',\r
+' } else {',\r
+' this.contentElement.innerHTML = content;',\r
+' }',\r
+' },',\r
+'',\r
+' setSearchMatch: function(isMatch) {',\r
+' var oldCssClass = isMatch ? "searchnonmatch" : "searchmatch";',\r
+' var newCssClass = isMatch ? "searchmatch" : "searchnonmatch";',\r
+' replaceClass(this.mainDiv, newCssClass, oldCssClass);',\r
+' },',\r
+'',\r
+' clearSearch: function() {',\r
+' removeClass(this.mainDiv, "searchmatch");',\r
+' removeClass(this.mainDiv, "searchnonmatch");',\r
+' }',\r
+' });',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function LogEntryWrappedElementContainer(logEntry, containerDomNode) {',\r
+' this.logEntry = logEntry;',\r
+' this.containerDomNode = containerDomNode;',\r
+' this.mainDiv = document.createElement("div");',\r
+' this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));',\r
+' this.mainDiv.className = "logentry wrapped " + this.logEntry.level;',\r
+' this.contentElement = this.mainDiv;',\r
+' }',\r
+'',\r
+' LogEntryWrappedElementContainer.prototype = new LogEntryElementContainer();',\r
+'',\r
+' LogEntryWrappedElementContainer.prototype.setContent = function(content, wrappedContent) {',\r
+' if (content === this.formattedMessage) {',\r
+' this.contentElement.innerHTML = "";',\r
+' this.contentElement.appendChild(document.createTextNode(this.formattedMessage));',\r
+' } else {',\r
+' this.contentElement.innerHTML = wrappedContent;',\r
+' }',\r
+' };',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function LogEntryUnwrappedElementContainer(logEntry, containerDomNode) {',\r
+' this.logEntry = logEntry;',\r
+' this.containerDomNode = containerDomNode;',\r
+' this.mainDiv = document.createElement("div");',\r
+' this.mainDiv.className = "logentry unwrapped " + this.logEntry.level;',\r
+' this.pre = this.mainDiv.appendChild(document.createElement("pre"));',\r
+' this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));',\r
+' this.pre.className = "unwrapped";',\r
+' this.contentElement = this.pre;',\r
+' }',\r
+'',\r
+' LogEntryUnwrappedElementContainer.prototype = new LogEntryElementContainer();',\r
+'',\r
+' LogEntryUnwrappedElementContainer.prototype.remove = function() {',\r
+' this.doRemove();',\r
+' this.pre = null;',\r
+' };',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function LogEntryMainElementContainer(logEntry, containerDomNode) {',\r
+' this.logEntry = logEntry;',\r
+' this.containerDomNode = containerDomNode;',\r
+' this.mainDiv = document.createElement("div");',\r
+' this.mainDiv.className = "logentry nonielogentry " + this.logEntry.level;',\r
+' this.contentElement = this.mainDiv.appendChild(document.createElement("span"));',\r
+' this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));',\r
+' }',\r
+'',\r
+' LogEntryMainElementContainer.prototype = new LogEntryElementContainer();',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function LogEntry(level, formattedMessage) {',\r
+' this.level = level;',\r
+' this.formattedMessage = formattedMessage;',\r
+' this.rendered = false;',\r
+' }',\r
+'',\r
+' LogEntry.prototype = new LogItem();',\r
+'',\r
+' copyProperties(LogEntry.prototype, {',\r
+' render: function() {',\r
+' var logEntry = this;',\r
+' var containerDomNode = this.group.contentDiv;',\r
+'',\r
+' // Support for the CSS attribute white-space in IE for Windows is',\r
+' // non-existent pre version 6 and slightly odd in 6, so instead',\r
+' // use two different HTML elements',\r
+' if (isIe) {',\r
+' this.formattedMessage = this.formattedMessage.replace(/\\r\\n/g, "\\r"); // Workaround for IE\'s treatment of white space',\r
+' this.unwrappedElementContainer = new LogEntryUnwrappedElementContainer(this, this.getUnwrappedDomContainer());',\r
+' this.wrappedElementContainer = new LogEntryWrappedElementContainer(this, this.getWrappedDomContainer());',\r
+' this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',\r
+' } else {',\r
+' this.mainElementContainer = new LogEntryMainElementContainer(this, this.getMainDomContainer());',\r
+' this.elementContainers = [this.mainElementContainer];',\r
+' }',\r
+' this.content = this.formattedMessage;',\r
+' this.rendered = true;',\r
+' },',\r
+'',\r
+' setContent: function(content, wrappedContent) {',\r
+' if (content != this.content) {',\r
+' if (isIe && (content !== this.formattedMessage)) {',\r
+' content = content.replace(/\\r\\n/g, "\\r"); // Workaround for IE\'s treatment of white space',\r
+' }',\r
+' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',\r
+' this.elementContainers[i].setContent(content, wrappedContent);',\r
+' }',\r
+' this.content = content;',\r
+' }',\r
+' },',\r
+'',\r
+' getSearchMatches: function() {',\r
+' var matches = [];',\r
+' var i, len;',\r
+' if (isIe) {',\r
+' var unwrappedEls = getElementsByClass(this.unwrappedElementContainer.mainDiv, "searchterm", "span");',\r
+' var wrappedEls = getElementsByClass(this.wrappedElementContainer.mainDiv, "searchterm", "span");',\r
+' for (i = 0, len = unwrappedEls.length; i < len; i++) {',\r
+' matches[i] = new Match(this.level, null, unwrappedEls[i], wrappedEls[i]);',\r
+' }',\r
+' } else {',\r
+' var els = getElementsByClass(this.mainElementContainer.mainDiv, "searchterm", "span");',\r
+' for (i = 0, len = els.length; i < len; i++) {',\r
+' matches[i] = new Match(this.level, els[i]);',\r
+' }',\r
+' }',\r
+' return matches;',\r
+' },',\r
+'',\r
+' setSearchMatch: function(isMatch) {',\r
+' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',\r
+' this.elementContainers[i].setSearchMatch(isMatch);',\r
+' }',\r
+' },',\r
+'',\r
+' clearSearch: function() {',\r
+' for (var i = 0, len = this.elementContainers.length; i < len; i++) {',\r
+' this.elementContainers[i].clearSearch();',\r
+' }',\r
+' },',\r
+'',\r
+' accept: function(visitor) {',\r
+' visitor.visitLogEntry(this);',\r
+' },',\r
+'',\r
+' serialize: function(items) {',\r
+' items.push([LogItem.serializedItemKeys.LOG_ENTRY, this.level, this.formattedMessage]);',\r
+' }',\r
+' });',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function LogItemVisitor() {',\r
+' }',\r
+'',\r
+' LogItemVisitor.prototype = {',\r
+' visit: function(logItem) {',\r
+' },',\r
+'',\r
+' visitParent: function(logItem) {',\r
+' if (logItem.group) {',\r
+' logItem.group.accept(this);',\r
+' }',\r
+' },',\r
+'',\r
+' visitChildren: function(logItem) {',\r
+' for (var i = 0, len = logItem.children.length; i < len; i++) {',\r
+' logItem.children[i].accept(this);',\r
+' }',\r
+' },',\r
+'',\r
+' visitLogEntry: function(logEntry) {',\r
+' this.visit(logEntry);',\r
+' },',\r
+'',\r
+' visitSeparator: function(separator) {',\r
+' this.visit(separator);',\r
+' },',\r
+'',\r
+' visitGroup: function(group) {',\r
+' this.visit(group);',\r
+' }',\r
+' };',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function GroupFlattener() {',\r
+' this.logEntriesAndSeparators = [];',\r
+' }',\r
+'',\r
+' GroupFlattener.prototype = new LogItemVisitor();',\r
+'',\r
+' GroupFlattener.prototype.visitGroup = function(group) {',\r
+' this.visitChildren(group);',\r
+' };',\r
+'',\r
+' GroupFlattener.prototype.visitLogEntry = function(logEntry) {',\r
+' this.logEntriesAndSeparators.push(logEntry);',\r
+' };',\r
+'',\r
+' GroupFlattener.prototype.visitSeparator = function(separator) {',\r
+' this.logEntriesAndSeparators.push(separator);',\r
+' };',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' window.onload = function() {',\r
+' // Sort out document.domain',\r
+' if (location.search) {',\r
+' var queryBits = unescape(location.search).substr(1).split("&"), nameValueBits;',\r
+' for (var i = 0, len = queryBits.length; i < len; i++) {',\r
+' nameValueBits = queryBits[i].split("=");',\r
+' if (nameValueBits[0] == "log4javascript_domain") {',\r
+' document.domain = nameValueBits[1];',\r
+' break;',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' // Create DOM objects',\r
+' logMainContainer = $("log");',\r
+' if (isIePre7) {',\r
+' addClass(logMainContainer, "oldIe");',\r
+' }',\r
+'',\r
+' rootGroup = new Group("root", true);',\r
+' rootGroup.render();',\r
+' currentGroup = rootGroup;',\r
+' ',\r
+' setCommandInputWidth();',\r
+' setLogContainerHeight();',\r
+' toggleLoggingEnabled();',\r
+' toggleSearchEnabled();',\r
+' toggleSearchFilter();',\r
+' toggleSearchHighlight();',\r
+' applyFilters();',\r
+' checkAllLevels();',\r
+' toggleWrap();',\r
+' toggleNewestAtTop();',\r
+' toggleScrollToLatest();',\r
+' renderQueuedLogItems();',\r
+' loaded = true;',\r
+' $("command").value = "";',\r
+' $("command").autocomplete = "off";',\r
+' $("command").onkeydown = function(evt) {',\r
+' evt = getEvent(evt);',\r
+' if (evt.keyCode == 10 || evt.keyCode == 13) { // Return/Enter',\r
+' evalCommandLine();',\r
+' stopPropagation(evt);',\r
+' } else if (evt.keyCode == 27) { // Escape',\r
+' this.value = "";',\r
+' this.focus();',\r
+' } else if (evt.keyCode == 38 && commandHistory.length > 0) { // Up',\r
+' currentCommandIndex = Math.max(0, currentCommandIndex - 1);',\r
+' this.value = commandHistory[currentCommandIndex];',\r
+' moveCaretToEnd(this);',\r
+' } else if (evt.keyCode == 40 && commandHistory.length > 0) { // Down',\r
+' currentCommandIndex = Math.min(commandHistory.length - 1, currentCommandIndex + 1);',\r
+' this.value = commandHistory[currentCommandIndex];',\r
+' moveCaretToEnd(this);',\r
+' }',\r
+' };',\r
+'',\r
+' // Prevent the keypress moving the caret in Firefox',\r
+' $("command").onkeypress = function(evt) {',\r
+' evt = getEvent(evt);',\r
+' if (evt.keyCode == 38 && commandHistory.length > 0 && evt.preventDefault) { // Up',\r
+' evt.preventDefault();',\r
+' }',\r
+' };',\r
+'',\r
+' // Prevent the keyup event blurring the input in Opera',\r
+' $("command").onkeyup = function(evt) {',\r
+' evt = getEvent(evt);',\r
+' if (evt.keyCode == 27 && evt.preventDefault) { // Up',\r
+' evt.preventDefault();',\r
+' this.focus();',\r
+' }',\r
+' };',\r
+'',\r
+' // Add document keyboard shortcuts',\r
+' document.onkeydown = function keyEventHandler(evt) {',\r
+' evt = getEvent(evt);',\r
+' switch (evt.keyCode) {',\r
+' case 69: // Ctrl + shift + E: re-execute last command',\r
+' if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',\r
+' evalLastCommand();',\r
+' cancelKeyEvent(evt);',\r
+' return false;',\r
+' }',\r
+' break;',\r
+' case 75: // Ctrl + shift + K: focus search',\r
+' if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',\r
+' focusSearch();',\r
+' cancelKeyEvent(evt);',\r
+' return false;',\r
+' }',\r
+' break;',\r
+' case 40: // Ctrl + shift + down arrow: focus command line',\r
+' case 76: // Ctrl + shift + L: focus command line',\r
+' if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',\r
+' focusCommandLine();',\r
+' cancelKeyEvent(evt);',\r
+' return false;',\r
+' }',\r
+' break;',\r
+' }',\r
+' };',\r
+'',\r
+' // Workaround to make sure log div starts at the correct size',\r
+' setTimeout(setLogContainerHeight, 20);',\r
+'',\r
+' setShowCommandLine(showCommandLine);',\r
+' doSearch();',\r
+' };',\r
+'',\r
+' window.onunload = function() {',\r
+' if (mainWindowExists()) {',\r
+' appender.unload();',\r
+' }',\r
+' appender = null;',\r
+' };',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function toggleLoggingEnabled() {',\r
+' setLoggingEnabled($("enableLogging").checked);',\r
+' }',\r
+'',\r
+' function setLoggingEnabled(enable) {',\r
+' loggingEnabled = enable;',\r
+' }',\r
+'',\r
+' var appender = null;',\r
+'',\r
+' function setAppender(appenderParam) {',\r
+' appender = appenderParam;',\r
+' }',\r
+'',\r
+' function setShowCloseButton(showCloseButton) {',\r
+' $("closeButton").style.display = showCloseButton ? "inline" : "none";',\r
+' }',\r
+'',\r
+' function setShowHideButton(showHideButton) {',\r
+' $("hideButton").style.display = showHideButton ? "inline" : "none";',\r
+' }',\r
+'',\r
+' var newestAtTop = false;',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function LogItemContentReverser() {',\r
+' }',\r
+' ',\r
+' LogItemContentReverser.prototype = new LogItemVisitor();',\r
+' ',\r
+' LogItemContentReverser.prototype.visitGroup = function(group) {',\r
+' group.reverseChildren();',\r
+' this.visitChildren(group);',\r
+' };',\r
+'',\r
+' /*----------------------------------------------------------------*/',\r
+'',\r
+' function setNewestAtTop(isNewestAtTop) {',\r
+' var oldNewestAtTop = newestAtTop;',\r
+' var i, iLen, j, jLen;',\r
+' newestAtTop = Boolean(isNewestAtTop);',\r
+' if (oldNewestAtTop != newestAtTop) {',\r
+' var visitor = new LogItemContentReverser();',\r
+' rootGroup.accept(visitor);',\r
+'',\r
+' // Reassemble the matches array',\r
+' if (currentSearch) {',\r
+' var currentMatch = currentSearch.matches[currentMatchIndex];',\r
+' var matchIndex = 0;',\r
+' var matches = [];',\r
+' var actOnLogEntry = function(logEntry) {',\r
+' var logEntryMatches = logEntry.getSearchMatches();',\r
+' for (j = 0, jLen = logEntryMatches.length; j < jLen; j++) {',\r
+' matches[matchIndex] = logEntryMatches[j];',\r
+' if (currentMatch && logEntryMatches[j].equals(currentMatch)) {',\r
+' currentMatchIndex = matchIndex;',\r
+' }',\r
+' matchIndex++;',\r
+' }',\r
+' };',\r
+' if (newestAtTop) {',\r
+' for (i = logEntries.length - 1; i >= 0; i--) {',\r
+' actOnLogEntry(logEntries[i]);',\r
+' }',\r
+' } else {',\r
+' for (i = 0, iLen = logEntries.length; i < iLen; i++) {',\r
+' actOnLogEntry(logEntries[i]);',\r
+' }',\r
+' }',\r
+' currentSearch.matches = matches;',\r
+' if (currentMatch) {',\r
+' currentMatch.setCurrent();',\r
+' }',\r
+' } else if (scrollToLatest) {',\r
+' doScrollToLatest();',\r
+' }',\r
+' }',\r
+' $("newestAtTop").checked = isNewestAtTop;',\r
+' }',\r
+'',\r
+' function toggleNewestAtTop() {',\r
+' var isNewestAtTop = $("newestAtTop").checked;',\r
+' setNewestAtTop(isNewestAtTop);',\r
+' }',\r
+'',\r
+' var scrollToLatest = true;',\r
+'',\r
+' function setScrollToLatest(isScrollToLatest) {',\r
+' scrollToLatest = isScrollToLatest;',\r
+' if (scrollToLatest) {',\r
+' doScrollToLatest();',\r
+' }',\r
+' $("scrollToLatest").checked = isScrollToLatest;',\r
+' }',\r
+'',\r
+' function toggleScrollToLatest() {',\r
+' var isScrollToLatest = $("scrollToLatest").checked;',\r
+' setScrollToLatest(isScrollToLatest);',\r
+' }',\r
+'',\r
+' function doScrollToLatest() {',\r
+' var l = logMainContainer;',\r
+' if (typeof l.scrollTop != "undefined") {',\r
+' if (newestAtTop) {',\r
+' l.scrollTop = 0;',\r
+' } else {',\r
+' var latestLogEntry = l.lastChild;',\r
+' if (latestLogEntry) {',\r
+' l.scrollTop = l.scrollHeight;',\r
+' }',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' var closeIfOpenerCloses = true;',\r
+'',\r
+' function setCloseIfOpenerCloses(isCloseIfOpenerCloses) {',\r
+' closeIfOpenerCloses = isCloseIfOpenerCloses;',\r
+' }',\r
+'',\r
+' var maxMessages = null;',\r
+'',\r
+' function setMaxMessages(max) {',\r
+' maxMessages = max;',\r
+' pruneLogEntries();',\r
+' }',\r
+'',\r
+' var showCommandLine = false;',\r
+'',\r
+' function setShowCommandLine(isShowCommandLine) {',\r
+' showCommandLine = isShowCommandLine;',\r
+' if (loaded) {',\r
+' $("commandLine").style.display = showCommandLine ? "block" : "none";',\r
+' setCommandInputWidth();',\r
+' setLogContainerHeight();',\r
+' }',\r
+' }',\r
+'',\r
+' function focusCommandLine() {',\r
+' if (loaded) {',\r
+' $("command").focus();',\r
+' }',\r
+' }',\r
+'',\r
+' function focusSearch() {',\r
+' if (loaded) {',\r
+' $("searchBox").focus();',\r
+' }',\r
+' }',\r
+'',\r
+' function getLogItems() {',\r
+' var items = [];',\r
+' for (var i = 0, len = logItems.length; i < len; i++) {',\r
+' logItems[i].serialize(items);',\r
+' }',\r
+' return items;',\r
+' }',\r
+'',\r
+' function setLogItems(items) {',\r
+' var loggingReallyEnabled = loggingEnabled;',\r
+' // Temporarily turn logging on',\r
+' loggingEnabled = true;',\r
+' for (var i = 0, len = items.length; i < len; i++) {',\r
+' switch (items[i][0]) {',\r
+' case LogItem.serializedItemKeys.LOG_ENTRY:',\r
+' log(items[i][1], items[i][2]);',\r
+' break;',\r
+' case LogItem.serializedItemKeys.GROUP_START:',\r
+' group(items[i][1]);',\r
+' break;',\r
+' case LogItem.serializedItemKeys.GROUP_END:',\r
+' groupEnd();',\r
+' break;',\r
+' }',\r
+' }',\r
+' loggingEnabled = loggingReallyEnabled;',\r
+' }',\r
+'',\r
+' function log(logLevel, formattedMessage) {',\r
+' if (loggingEnabled) {',\r
+' var logEntry = new LogEntry(logLevel, formattedMessage);',\r
+' logEntries.push(logEntry);',\r
+' logEntriesAndSeparators.push(logEntry);',\r
+' logItems.push(logEntry);',\r
+' currentGroup.addChild(logEntry);',\r
+' if (loaded) {',\r
+' if (logQueuedEventsTimer !== null) {',\r
+' clearTimeout(logQueuedEventsTimer);',\r
+' }',\r
+' logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);',\r
+' unrenderedLogItemsExist = true;',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function renderQueuedLogItems() {',\r
+' logQueuedEventsTimer = null;',\r
+' var pruned = pruneLogEntries();',\r
+'',\r
+' // Render any unrendered log entries and apply the current search to them',\r
+' var initiallyHasMatches = currentSearch ? currentSearch.hasMatches() : false;',\r
+' for (var i = 0, len = logItems.length; i < len; i++) {',\r
+' if (!logItems[i].rendered) {',\r
+' logItems[i].render();',\r
+' logItems[i].appendToLog();',\r
+' if (currentSearch && (logItems[i] instanceof LogEntry)) {',\r
+' currentSearch.applyTo(logItems[i]);',\r
+' }',\r
+' }',\r
+' }',\r
+' if (currentSearch) {',\r
+' if (pruned) {',\r
+' if (currentSearch.hasVisibleMatches()) {',\r
+' if (currentMatchIndex === null) {',\r
+' setCurrentMatchIndex(0);',\r
+' }',\r
+' displayMatches();',\r
+' } else {',\r
+' displayNoMatches();',\r
+' }',\r
+' } else if (!initiallyHasMatches && currentSearch.hasVisibleMatches()) {',\r
+' setCurrentMatchIndex(0);',\r
+' displayMatches();',\r
+' }',\r
+' }',\r
+' if (scrollToLatest) {',\r
+' doScrollToLatest();',\r
+' }',\r
+' unrenderedLogItemsExist = false;',\r
+' }',\r
+'',\r
+' function pruneLogEntries() {',\r
+' if ((maxMessages !== null) && (logEntriesAndSeparators.length > maxMessages)) {',\r
+' var numberToDelete = logEntriesAndSeparators.length - maxMessages;',\r
+' var prunedLogEntries = logEntriesAndSeparators.slice(0, numberToDelete);',\r
+' if (currentSearch) {',\r
+' currentSearch.removeMatches(prunedLogEntries);',\r
+' }',\r
+' var group;',\r
+' for (var i = 0; i < numberToDelete; i++) {',\r
+' group = logEntriesAndSeparators[i].group;',\r
+' array_remove(logItems, logEntriesAndSeparators[i]);',\r
+' array_remove(logEntries, logEntriesAndSeparators[i]);',\r
+' logEntriesAndSeparators[i].remove(true, true);',\r
+' if (group.children.length === 0 && group !== currentGroup && group !== rootGroup) {',\r
+' array_remove(logItems, group);',\r
+' group.remove(true, true);',\r
+' }',\r
+' }',\r
+' logEntriesAndSeparators = array_removeFromStart(logEntriesAndSeparators, numberToDelete);',\r
+' return true;',\r
+' }',\r
+' return false;',\r
+' }',\r
+'',\r
+' function group(name, startExpanded) {',\r
+' if (loggingEnabled) {',\r
+' initiallyExpanded = (typeof startExpanded === "undefined") ? true : Boolean(startExpanded);',\r
+' var newGroup = new Group(name, false, initiallyExpanded);',\r
+' currentGroup.addChild(newGroup);',\r
+' currentGroup = newGroup;',\r
+' logItems.push(newGroup);',\r
+' if (loaded) {',\r
+' if (logQueuedEventsTimer !== null) {',\r
+' clearTimeout(logQueuedEventsTimer);',\r
+' }',\r
+' logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);',\r
+' unrenderedLogItemsExist = true;',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function groupEnd() {',\r
+' currentGroup = (currentGroup === rootGroup) ? rootGroup : currentGroup.group;',\r
+' }',\r
+'',\r
+' function mainPageReloaded() {',\r
+' currentGroup = rootGroup;',\r
+' var separator = new Separator();',\r
+' logEntriesAndSeparators.push(separator);',\r
+' logItems.push(separator);',\r
+' currentGroup.addChild(separator);',\r
+' }',\r
+'',\r
+' function closeWindow() {',\r
+' if (appender && mainWindowExists()) {',\r
+' appender.close(true);',\r
+' } else {',\r
+' window.close();',\r
+' }',\r
+' }',\r
+'',\r
+' function hide() {',\r
+' if (appender && mainWindowExists()) {',\r
+' appender.hide();',\r
+' }',\r
+' }',\r
+'',\r
+' var mainWindow = window;',\r
+' var windowId = "log4javascriptConsoleWindow_" + new Date().getTime() + "_" + ("" + Math.random()).substr(2);',\r
+'',\r
+' function setMainWindow(win) {',\r
+' mainWindow = win;',\r
+' mainWindow[windowId] = window;',\r
+' // If this is a pop-up, poll the opener to see if it\'s closed',\r
+' if (opener && closeIfOpenerCloses) {',\r
+' pollOpener();',\r
+' }',\r
+' }',\r
+'',\r
+' function pollOpener() {',\r
+' if (closeIfOpenerCloses) {',\r
+' if (mainWindowExists()) {',\r
+' setTimeout(pollOpener, 500);',\r
+' } else {',\r
+' closeWindow();',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function mainWindowExists() {',\r
+' try {',\r
+' return (mainWindow && !mainWindow.closed &&',\r
+' mainWindow[windowId] == window);',\r
+' } catch (ex) {}',\r
+' return false;',\r
+' }',\r
+'',\r
+' var logLevels = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"];',\r
+'',\r
+' function getCheckBox(logLevel) {',\r
+' return $("switch_" + logLevel);',\r
+' }',\r
+'',\r
+' function getIeWrappedLogContainer() {',\r
+' return $("log_wrapped");',\r
+' }',\r
+'',\r
+' function getIeUnwrappedLogContainer() {',\r
+' return $("log_unwrapped");',\r
+' }',\r
+'',\r
+' function applyFilters() {',\r
+' for (var i = 0; i < logLevels.length; i++) {',\r
+' if (getCheckBox(logLevels[i]).checked) {',\r
+' addClass(logMainContainer, logLevels[i]);',\r
+' } else {',\r
+' removeClass(logMainContainer, logLevels[i]);',\r
+' }',\r
+' }',\r
+' updateSearchFromFilters();',\r
+' }',\r
+'',\r
+' function toggleAllLevels() {',\r
+' var turnOn = $("switch_ALL").checked;',\r
+' for (var i = 0; i < logLevels.length; i++) {',\r
+' getCheckBox(logLevels[i]).checked = turnOn;',\r
+' if (turnOn) {',\r
+' addClass(logMainContainer, logLevels[i]);',\r
+' } else {',\r
+' removeClass(logMainContainer, logLevels[i]);',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function checkAllLevels() {',\r
+' for (var i = 0; i < logLevels.length; i++) {',\r
+' if (!getCheckBox(logLevels[i]).checked) {',\r
+' getCheckBox("ALL").checked = false;',\r
+' return;',\r
+' }',\r
+' }',\r
+' getCheckBox("ALL").checked = true;',\r
+' }',\r
+'',\r
+' function clearLog() {',\r
+' rootGroup.clear();',\r
+' currentGroup = rootGroup;',\r
+' logEntries = [];',\r
+' logItems = [];',\r
+' logEntriesAndSeparators = [];',\r
+' doSearch();',\r
+' }',\r
+'',\r
+' function toggleWrap() {',\r
+' var enable = $("wrap").checked;',\r
+' if (enable) {',\r
+' addClass(logMainContainer, "wrap");',\r
+' } else {',\r
+' removeClass(logMainContainer, "wrap");',\r
+' }',\r
+' refreshCurrentMatch();',\r
+' }',\r
+'',\r
+' /* ------------------------------------------------------------------- */',\r
+'',\r
+' // Search',\r
+'',\r
+' var searchTimer = null;',\r
+'',\r
+' function scheduleSearch() {',\r
+' try {',\r
+' clearTimeout(searchTimer);',\r
+' } catch (ex) {',\r
+' // Do nothing',\r
+' }',\r
+' searchTimer = setTimeout(doSearch, 500);',\r
+' }',\r
+'',\r
+' function Search(searchTerm, isRegex, searchRegex, isCaseSensitive) {',\r
+' this.searchTerm = searchTerm;',\r
+' this.isRegex = isRegex;',\r
+' this.searchRegex = searchRegex;',\r
+' this.isCaseSensitive = isCaseSensitive;',\r
+' this.matches = [];',\r
+' }',\r
+'',\r
+' Search.prototype = {',\r
+' hasMatches: function() {',\r
+' return this.matches.length > 0;',\r
+' },',\r
+'',\r
+' hasVisibleMatches: function() {',\r
+' if (this.hasMatches()) {',\r
+' for (var i = 0; i < this.matches.length; i++) {',\r
+' if (this.matches[i].isVisible()) {',\r
+' return true;',\r
+' }',\r
+' }',\r
+' }',\r
+' return false;',\r
+' },',\r
+'',\r
+' match: function(logEntry) {',\r
+' var entryText = String(logEntry.formattedMessage);',\r
+' var matchesSearch = false;',\r
+' if (this.isRegex) {',\r
+' matchesSearch = this.searchRegex.test(entryText);',\r
+' } else if (this.isCaseSensitive) {',\r
+' matchesSearch = (entryText.indexOf(this.searchTerm) > -1);',\r
+' } else {',\r
+' matchesSearch = (entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1);',\r
+' }',\r
+' return matchesSearch;',\r
+' },',\r
+'',\r
+' getNextVisibleMatchIndex: function() {',\r
+' for (var i = currentMatchIndex + 1; i < this.matches.length; i++) {',\r
+' if (this.matches[i].isVisible()) {',\r
+' return i;',\r
+' }',\r
+' }',\r
+' // Start again from the first match',\r
+' for (i = 0; i <= currentMatchIndex; i++) {',\r
+' if (this.matches[i].isVisible()) {',\r
+' return i;',\r
+' }',\r
+' }',\r
+' return -1;',\r
+' },',\r
+'',\r
+' getPreviousVisibleMatchIndex: function() {',\r
+' for (var i = currentMatchIndex - 1; i >= 0; i--) {',\r
+' if (this.matches[i].isVisible()) {',\r
+' return i;',\r
+' }',\r
+' }',\r
+' // Start again from the last match',\r
+' for (var i = this.matches.length - 1; i >= currentMatchIndex; i--) {',\r
+' if (this.matches[i].isVisible()) {',\r
+' return i;',\r
+' }',\r
+' }',\r
+' return -1;',\r
+' },',\r
+'',\r
+' applyTo: function(logEntry) {',\r
+' var doesMatch = this.match(logEntry);',\r
+' if (doesMatch) {',\r
+' logEntry.group.expand();',\r
+' logEntry.setSearchMatch(true);',\r
+' var logEntryContent;',\r
+' var wrappedLogEntryContent;',\r
+' var searchTermReplacementStartTag = "<span class=\\\"searchterm\\\">";',\r
+' var searchTermReplacementEndTag = "<" + "/span>";',\r
+' var preTagName = isIe ? "pre" : "span";',\r
+' var preStartTag = "<" + preTagName + " class=\\\"pre\\\">";',\r
+' var preEndTag = "<" + "/" + preTagName + ">";',\r
+' var startIndex = 0;',\r
+' var searchIndex, matchedText, textBeforeMatch;',\r
+' if (this.isRegex) {',\r
+' var flags = this.isCaseSensitive ? "g" : "gi";',\r
+' var capturingRegex = new RegExp("(" + this.searchRegex.source + ")", flags);',\r
+'',\r
+' // Replace the search term with temporary tokens for the start and end tags',\r
+' var rnd = ("" + Math.random()).substr(2);',\r
+' var startToken = "%%s" + rnd + "%%";',\r
+' var endToken = "%%e" + rnd + "%%";',\r
+' logEntryContent = logEntry.formattedMessage.replace(capturingRegex, startToken + "$1" + endToken);',\r
+'',\r
+' // Escape the HTML to get rid of angle brackets',\r
+' logEntryContent = escapeHtml(logEntryContent);',\r
+'',\r
+' // Substitute the proper HTML back in for the search match',\r
+' var result;',\r
+' var searchString = logEntryContent;',\r
+' logEntryContent = "";',\r
+' wrappedLogEntryContent = "";',\r
+' while ((searchIndex = searchString.indexOf(startToken, startIndex)) > -1) {',\r
+' var endTokenIndex = searchString.indexOf(endToken, searchIndex);',\r
+' matchedText = searchString.substring(searchIndex + startToken.length, endTokenIndex);',\r
+' textBeforeMatch = searchString.substring(startIndex, searchIndex);',\r
+' logEntryContent += preStartTag + textBeforeMatch + preEndTag;',\r
+' logEntryContent += searchTermReplacementStartTag + preStartTag + matchedText +',\r
+' preEndTag + searchTermReplacementEndTag;',\r
+' if (isIe) {',\r
+' wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +',\r
+' matchedText + searchTermReplacementEndTag;',\r
+' }',\r
+' startIndex = endTokenIndex + endToken.length;',\r
+' }',\r
+' logEntryContent += preStartTag + searchString.substr(startIndex) + preEndTag;',\r
+' if (isIe) {',\r
+' wrappedLogEntryContent += searchString.substr(startIndex);',\r
+' }',\r
+' } else {',\r
+' logEntryContent = "";',\r
+' wrappedLogEntryContent = "";',\r
+' var searchTermReplacementLength = searchTermReplacementStartTag.length +',\r
+' this.searchTerm.length + searchTermReplacementEndTag.length;',\r
+' var searchTermLength = this.searchTerm.length;',\r
+' var searchTermLowerCase = this.searchTerm.toLowerCase();',\r
+' var logTextLowerCase = logEntry.formattedMessage.toLowerCase();',\r
+' while ((searchIndex = logTextLowerCase.indexOf(searchTermLowerCase, startIndex)) > -1) {',\r
+' matchedText = escapeHtml(logEntry.formattedMessage.substr(searchIndex, this.searchTerm.length));',\r
+' textBeforeMatch = escapeHtml(logEntry.formattedMessage.substring(startIndex, searchIndex));',\r
+' var searchTermReplacement = searchTermReplacementStartTag +',\r
+' preStartTag + matchedText + preEndTag + searchTermReplacementEndTag;',\r
+' logEntryContent += preStartTag + textBeforeMatch + preEndTag + searchTermReplacement;',\r
+' if (isIe) {',\r
+' wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +',\r
+' matchedText + searchTermReplacementEndTag;',\r
+' }',\r
+' startIndex = searchIndex + searchTermLength;',\r
+' }',\r
+' var textAfterLastMatch = escapeHtml(logEntry.formattedMessage.substr(startIndex));',\r
+' logEntryContent += preStartTag + textAfterLastMatch + preEndTag;',\r
+' if (isIe) {',\r
+' wrappedLogEntryContent += textAfterLastMatch;',\r
+' }',\r
+' }',\r
+' logEntry.setContent(logEntryContent, wrappedLogEntryContent);',\r
+' var logEntryMatches = logEntry.getSearchMatches();',\r
+' this.matches = this.matches.concat(logEntryMatches);',\r
+' } else {',\r
+' logEntry.setSearchMatch(false);',\r
+' logEntry.setContent(logEntry.formattedMessage, logEntry.formattedMessage);',\r
+' }',\r
+' return doesMatch;',\r
+' },',\r
+'',\r
+' removeMatches: function(logEntries) {',\r
+' var matchesToRemoveCount = 0;',\r
+' var currentMatchRemoved = false;',\r
+' var matchesToRemove = [];',\r
+' var i, iLen, j, jLen;',\r
+'',\r
+' // Establish the list of matches to be removed',\r
+' for (i = 0, iLen = this.matches.length; i < iLen; i++) {',\r
+' for (j = 0, jLen = logEntries.length; j < jLen; j++) {',\r
+' if (this.matches[i].belongsTo(logEntries[j])) {',\r
+' matchesToRemove.push(this.matches[i]);',\r
+' if (i === currentMatchIndex) {',\r
+' currentMatchRemoved = true;',\r
+' }',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' // Set the new current match index if the current match has been deleted',\r
+' // This will be the first match that appears after the first log entry being',\r
+' // deleted, if one exists; otherwise, it\'s the first match overall',\r
+' var newMatch = currentMatchRemoved ? null : this.matches[currentMatchIndex];',\r
+' if (currentMatchRemoved) {',\r
+' for (i = currentMatchIndex, iLen = this.matches.length; i < iLen; i++) {',\r
+' if (this.matches[i].isVisible() && !array_contains(matchesToRemove, this.matches[i])) {',\r
+' newMatch = this.matches[i];',\r
+' break;',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' // Remove the matches',\r
+' for (i = 0, iLen = matchesToRemove.length; i < iLen; i++) {',\r
+' array_remove(this.matches, matchesToRemove[i]);',\r
+' matchesToRemove[i].remove();',\r
+' }',\r
+'',\r
+' // Set the new match, if one exists',\r
+' if (this.hasVisibleMatches()) {',\r
+' if (newMatch === null) {',\r
+' setCurrentMatchIndex(0);',\r
+' } else {',\r
+' // Get the index of the new match',\r
+' var newMatchIndex = 0;',\r
+' for (i = 0, iLen = this.matches.length; i < iLen; i++) {',\r
+' if (newMatch === this.matches[i]) {',\r
+' newMatchIndex = i;',\r
+' break;',\r
+' }',\r
+' }',\r
+' setCurrentMatchIndex(newMatchIndex);',\r
+' }',\r
+' } else {',\r
+' currentMatchIndex = null;',\r
+' displayNoMatches();',\r
+' }',\r
+' }',\r
+' };',\r
+'',\r
+' function getPageOffsetTop(el, container) {',\r
+' var currentEl = el;',\r
+' var y = 0;',\r
+' while (currentEl && currentEl != container) {',\r
+' y += currentEl.offsetTop;',\r
+' currentEl = currentEl.offsetParent;',\r
+' }',\r
+' return y;',\r
+' }',\r
+'',\r
+' function scrollIntoView(el) {',\r
+' var logContainer = logMainContainer;',\r
+' // Check if the whole width of the element is visible and centre if not',\r
+' if (!$("wrap").checked) {',\r
+' var logContainerLeft = logContainer.scrollLeft;',\r
+' var logContainerRight = logContainerLeft + logContainer.offsetWidth;',\r
+' var elLeft = el.offsetLeft;',\r
+' var elRight = elLeft + el.offsetWidth;',\r
+' if (elLeft < logContainerLeft || elRight > logContainerRight) {',\r
+' logContainer.scrollLeft = elLeft - (logContainer.offsetWidth - el.offsetWidth) / 2;',\r
+' }',\r
+' }',\r
+' // Check if the whole height of the element is visible and centre if not',\r
+' var logContainerTop = logContainer.scrollTop;',\r
+' var logContainerBottom = logContainerTop + logContainer.offsetHeight;',\r
+' var elTop = getPageOffsetTop(el) - getToolBarsHeight();',\r
+' var elBottom = elTop + el.offsetHeight;',\r
+' if (elTop < logContainerTop || elBottom > logContainerBottom) {',\r
+' logContainer.scrollTop = elTop - (logContainer.offsetHeight - el.offsetHeight) / 2;',\r
+' }',\r
+' }',\r
+'',\r
+' function Match(logEntryLevel, spanInMainDiv, spanInUnwrappedPre, spanInWrappedDiv) {',\r
+' this.logEntryLevel = logEntryLevel;',\r
+' this.spanInMainDiv = spanInMainDiv;',\r
+' if (isIe) {',\r
+' this.spanInUnwrappedPre = spanInUnwrappedPre;',\r
+' this.spanInWrappedDiv = spanInWrappedDiv;',\r
+' }',\r
+' this.mainSpan = isIe ? spanInUnwrappedPre : spanInMainDiv;',\r
+' }',\r
+'',\r
+' Match.prototype = {',\r
+' equals: function(match) {',\r
+' return this.mainSpan === match.mainSpan;',\r
+' },',\r
+'',\r
+' setCurrent: function() {',\r
+' if (isIe) {',\r
+' addClass(this.spanInUnwrappedPre, "currentmatch");',\r
+' addClass(this.spanInWrappedDiv, "currentmatch");',\r
+' // Scroll the visible one into view',\r
+' var elementToScroll = $("wrap").checked ? this.spanInWrappedDiv : this.spanInUnwrappedPre;',\r
+' scrollIntoView(elementToScroll);',\r
+' } else {',\r
+' addClass(this.spanInMainDiv, "currentmatch");',\r
+' scrollIntoView(this.spanInMainDiv);',\r
+' }',\r
+' },',\r
+'',\r
+' belongsTo: function(logEntry) {',\r
+' if (isIe) {',\r
+' return isDescendant(this.spanInUnwrappedPre, logEntry.unwrappedPre);',\r
+' } else {',\r
+' return isDescendant(this.spanInMainDiv, logEntry.mainDiv);',\r
+' }',\r
+' },',\r
+'',\r
+' setNotCurrent: function() {',\r
+' if (isIe) {',\r
+' removeClass(this.spanInUnwrappedPre, "currentmatch");',\r
+' removeClass(this.spanInWrappedDiv, "currentmatch");',\r
+' } else {',\r
+' removeClass(this.spanInMainDiv, "currentmatch");',\r
+' }',\r
+' },',\r
+'',\r
+' isOrphan: function() {',\r
+' return isOrphan(this.mainSpan);',\r
+' },',\r
+'',\r
+' isVisible: function() {',\r
+' return getCheckBox(this.logEntryLevel).checked;',\r
+' },',\r
+'',\r
+' remove: function() {',\r
+' if (isIe) {',\r
+' this.spanInUnwrappedPre = null;',\r
+' this.spanInWrappedDiv = null;',\r
+' } else {',\r
+' this.spanInMainDiv = null;',\r
+' }',\r
+' }',\r
+' };',\r
+'',\r
+' var currentSearch = null;',\r
+' var currentMatchIndex = null;',\r
+'',\r
+' function doSearch() {',\r
+' var searchBox = $("searchBox");',\r
+' var searchTerm = searchBox.value;',\r
+' var isRegex = $("searchRegex").checked;',\r
+' var isCaseSensitive = $("searchCaseSensitive").checked;',\r
+' var i;',\r
+'',\r
+' if (searchTerm === "") {',\r
+' $("searchReset").disabled = true;',\r
+' $("searchNav").style.display = "none";',\r
+' removeClass(document.body, "searching");',\r
+' removeClass(searchBox, "hasmatches");',\r
+' removeClass(searchBox, "nomatches");',\r
+' for (i = 0; i < logEntries.length; i++) {',\r
+' logEntries[i].clearSearch();',\r
+' logEntries[i].setContent(logEntries[i].formattedMessage, logEntries[i].formattedMessage);',\r
+' }',\r
+' currentSearch = null;',\r
+' setLogContainerHeight();',\r
+' } else {',\r
+' $("searchReset").disabled = false;',\r
+' $("searchNav").style.display = "block";',\r
+' var searchRegex;',\r
+' var regexValid;',\r
+' if (isRegex) {',\r
+' try {',\r
+' searchRegex = isCaseSensitive ? new RegExp(searchTerm, "g") : new RegExp(searchTerm, "gi");',\r
+' regexValid = true;',\r
+' replaceClass(searchBox, "validregex", "invalidregex");',\r
+' searchBox.title = "Valid regex";',\r
+' } catch (ex) {',\r
+' regexValid = false;',\r
+' replaceClass(searchBox, "invalidregex", "validregex");',\r
+' searchBox.title = "Invalid regex: " + (ex.message ? ex.message : (ex.description ? ex.description : "unknown error"));',\r
+' return;',\r
+' }',\r
+' } else {',\r
+' searchBox.title = "";',\r
+' removeClass(searchBox, "validregex");',\r
+' removeClass(searchBox, "invalidregex");',\r
+' }',\r
+' addClass(document.body, "searching");',\r
+' currentSearch = new Search(searchTerm, isRegex, searchRegex, isCaseSensitive);',\r
+' for (i = 0; i < logEntries.length; i++) {',\r
+' currentSearch.applyTo(logEntries[i]);',\r
+' }',\r
+' setLogContainerHeight();',\r
+'',\r
+' // Highlight the first search match',\r
+' if (currentSearch.hasVisibleMatches()) {',\r
+' setCurrentMatchIndex(0);',\r
+' displayMatches();',\r
+' } else {',\r
+' displayNoMatches();',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function updateSearchFromFilters() {',\r
+' if (currentSearch) {',\r
+' if (currentSearch.hasMatches()) {',\r
+' if (currentMatchIndex === null) {',\r
+' currentMatchIndex = 0;',\r
+' }',\r
+' var currentMatch = currentSearch.matches[currentMatchIndex];',\r
+' if (currentMatch.isVisible()) {',\r
+' displayMatches();',\r
+' setCurrentMatchIndex(currentMatchIndex);',\r
+' } else {',\r
+' currentMatch.setNotCurrent();',\r
+' // Find the next visible match, if one exists',\r
+' var nextVisibleMatchIndex = currentSearch.getNextVisibleMatchIndex();',\r
+' if (nextVisibleMatchIndex > -1) {',\r
+' setCurrentMatchIndex(nextVisibleMatchIndex);',\r
+' displayMatches();',\r
+' } else {',\r
+' displayNoMatches();',\r
+' }',\r
+' }',\r
+' } else {',\r
+' displayNoMatches();',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function refreshCurrentMatch() {',\r
+' if (currentSearch && currentSearch.hasVisibleMatches()) {',\r
+' setCurrentMatchIndex(currentMatchIndex);',\r
+' }',\r
+' }',\r
+'',\r
+' function displayMatches() {',\r
+' replaceClass($("searchBox"), "hasmatches", "nomatches");',\r
+' $("searchBox").title = "" + currentSearch.matches.length + " matches found";',\r
+' $("searchNav").style.display = "block";',\r
+' setLogContainerHeight();',\r
+' }',\r
+'',\r
+' function displayNoMatches() {',\r
+' replaceClass($("searchBox"), "nomatches", "hasmatches");',\r
+' $("searchBox").title = "No matches found";',\r
+' $("searchNav").style.display = "none";',\r
+' setLogContainerHeight();',\r
+' }',\r
+'',\r
+' function toggleSearchEnabled(enable) {',\r
+' enable = (typeof enable == "undefined") ? !$("searchDisable").checked : enable;',\r
+' $("searchBox").disabled = !enable;',\r
+' $("searchReset").disabled = !enable;',\r
+' $("searchRegex").disabled = !enable;',\r
+' $("searchNext").disabled = !enable;',\r
+' $("searchPrevious").disabled = !enable;',\r
+' $("searchCaseSensitive").disabled = !enable;',\r
+' $("searchNav").style.display = (enable && ($("searchBox").value !== "") &&',\r
+' currentSearch && currentSearch.hasVisibleMatches()) ?',\r
+' "block" : "none";',\r
+' if (enable) {',\r
+' removeClass($("search"), "greyedout");',\r
+' addClass(document.body, "searching");',\r
+' if ($("searchHighlight").checked) {',\r
+' addClass(logMainContainer, "searchhighlight");',\r
+' } else {',\r
+' removeClass(logMainContainer, "searchhighlight");',\r
+' }',\r
+' if ($("searchFilter").checked) {',\r
+' addClass(logMainContainer, "searchfilter");',\r
+' } else {',\r
+' removeClass(logMainContainer, "searchfilter");',\r
+' }',\r
+' $("searchDisable").checked = !enable;',\r
+' } else {',\r
+' addClass($("search"), "greyedout");',\r
+' removeClass(document.body, "searching");',\r
+' removeClass(logMainContainer, "searchhighlight");',\r
+' removeClass(logMainContainer, "searchfilter");',\r
+' }',\r
+' setLogContainerHeight();',\r
+' }',\r
+'',\r
+' function toggleSearchFilter() {',\r
+' var enable = $("searchFilter").checked;',\r
+' if (enable) {',\r
+' addClass(logMainContainer, "searchfilter");',\r
+' } else {',\r
+' removeClass(logMainContainer, "searchfilter");',\r
+' }',\r
+' refreshCurrentMatch();',\r
+' }',\r
+'',\r
+' function toggleSearchHighlight() {',\r
+' var enable = $("searchHighlight").checked;',\r
+' if (enable) {',\r
+' addClass(logMainContainer, "searchhighlight");',\r
+' } else {',\r
+' removeClass(logMainContainer, "searchhighlight");',\r
+' }',\r
+' }',\r
+'',\r
+' function clearSearch() {',\r
+' $("searchBox").value = "";',\r
+' doSearch();',\r
+' }',\r
+'',\r
+' function searchNext() {',\r
+' if (currentSearch !== null && currentMatchIndex !== null) {',\r
+' currentSearch.matches[currentMatchIndex].setNotCurrent();',\r
+' var nextMatchIndex = currentSearch.getNextVisibleMatchIndex();',\r
+' if (nextMatchIndex > currentMatchIndex || confirm("Reached the end of the page. Start from the top?")) {',\r
+' setCurrentMatchIndex(nextMatchIndex);',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function searchPrevious() {',\r
+' if (currentSearch !== null && currentMatchIndex !== null) {',\r
+' currentSearch.matches[currentMatchIndex].setNotCurrent();',\r
+' var previousMatchIndex = currentSearch.getPreviousVisibleMatchIndex();',\r
+' if (previousMatchIndex < currentMatchIndex || confirm("Reached the start of the page. Continue from the bottom?")) {',\r
+' setCurrentMatchIndex(previousMatchIndex);',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function setCurrentMatchIndex(index) {',\r
+' currentMatchIndex = index;',\r
+' currentSearch.matches[currentMatchIndex].setCurrent();',\r
+' }',\r
+'',\r
+' /* ------------------------------------------------------------------------- */',\r
+'',\r
+' // CSS Utilities',\r
+'',\r
+' function addClass(el, cssClass) {',\r
+' if (!hasClass(el, cssClass)) {',\r
+' if (el.className) {',\r
+' el.className += " " + cssClass;',\r
+' } else {',\r
+' el.className = cssClass;',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function hasClass(el, cssClass) {',\r
+' if (el.className) {',\r
+' var classNames = el.className.split(" ");',\r
+' return array_contains(classNames, cssClass);',\r
+' }',\r
+' return false;',\r
+' }',\r
+'',\r
+' function removeClass(el, cssClass) {',\r
+' if (hasClass(el, cssClass)) {',\r
+' // Rebuild the className property',\r
+' var existingClasses = el.className.split(" ");',\r
+' var newClasses = [];',\r
+' for (var i = 0, len = existingClasses.length; i < len; i++) {',\r
+' if (existingClasses[i] != cssClass) {',\r
+' newClasses[newClasses.length] = existingClasses[i];',\r
+' }',\r
+' }',\r
+' el.className = newClasses.join(" ");',\r
+' }',\r
+' }',\r
+'',\r
+' function replaceClass(el, newCssClass, oldCssClass) {',\r
+' removeClass(el, oldCssClass);',\r
+' addClass(el, newCssClass);',\r
+' }',\r
+'',\r
+' /* ------------------------------------------------------------------------- */',\r
+'',\r
+' // Other utility functions',\r
+'',\r
+' function getElementsByClass(el, cssClass, tagName) {',\r
+' var elements = el.getElementsByTagName(tagName);',\r
+' var matches = [];',\r
+' for (var i = 0, len = elements.length; i < len; i++) {',\r
+' if (hasClass(elements[i], cssClass)) {',\r
+' matches.push(elements[i]);',\r
+' }',\r
+' }',\r
+' return matches;',\r
+' }',\r
+'',\r
+' // Syntax borrowed from Prototype library',\r
+' function $(id) {',\r
+' return document.getElementById(id);',\r
+' }',\r
+'',\r
+' function isDescendant(node, ancestorNode) {',\r
+' while (node != null) {',\r
+' if (node === ancestorNode) {',\r
+' return true;',\r
+' }',\r
+' node = node.parentNode;',\r
+' }',\r
+' return false;',\r
+' }',\r
+'',\r
+' function isOrphan(node) {',\r
+' var currentNode = node;',\r
+' while (currentNode) {',\r
+' if (currentNode == document.body) {',\r
+' return false;',\r
+' }',\r
+' currentNode = currentNode.parentNode;',\r
+' }',\r
+' return true;',\r
+' }',\r
+'',\r
+' function escapeHtml(str) {',\r
+' return str.replace(/&/g, "&").replace(/[<]/g, "<").replace(/>/g, ">");',\r
+' }',\r
+'',\r
+' function getWindowWidth() {',\r
+' if (window.innerWidth) {',\r
+' return window.innerWidth;',\r
+' } else if (document.documentElement && document.documentElement.clientWidth) {',\r
+' return document.documentElement.clientWidth;',\r
+' } else if (document.body) {',\r
+' return document.body.clientWidth;',\r
+' }',\r
+' return 0;',\r
+' }',\r
+'',\r
+' function getWindowHeight() {',\r
+' if (window.innerHeight) {',\r
+' return window.innerHeight;',\r
+' } else if (document.documentElement && document.documentElement.clientHeight) {',\r
+' return document.documentElement.clientHeight;',\r
+' } else if (document.body) {',\r
+' return document.body.clientHeight;',\r
+' }',\r
+' return 0;',\r
+' }',\r
+'',\r
+' function getToolBarsHeight() {',\r
+' return $("switches").offsetHeight;',\r
+' }',\r
+'',\r
+' function getChromeHeight() {',\r
+' var height = getToolBarsHeight();',\r
+' if (showCommandLine) {',\r
+' height += $("commandLine").offsetHeight;',\r
+' }',\r
+' return height;',\r
+' }',\r
+'',\r
+' function setLogContainerHeight() {',\r
+' if (logMainContainer) {',\r
+' var windowHeight = getWindowHeight();',\r
+' $("body").style.height = getWindowHeight() + "px";',\r
+' logMainContainer.style.height = "" +',\r
+' Math.max(0, windowHeight - getChromeHeight()) + "px";',\r
+' }',\r
+' }',\r
+'',\r
+' function setCommandInputWidth() {',\r
+' if (showCommandLine) {',\r
+' $("command").style.width = "" + Math.max(0, $("commandLineContainer").offsetWidth -',\r
+' ($("evaluateButton").offsetWidth + 13)) + "px";',\r
+' }',\r
+' }',\r
+'',\r
+' window.onresize = function() {',\r
+' setCommandInputWidth();',\r
+' setLogContainerHeight();',\r
+' };',\r
+'',\r
+' if (!Array.prototype.push) {',\r
+' Array.prototype.push = function() {',\r
+' for (var i = 0, len = arguments.length; i < len; i++){',\r
+' this[this.length] = arguments[i];',\r
+' }',\r
+' return this.length;',\r
+' };',\r
+' }',\r
+'',\r
+' if (!Array.prototype.pop) {',\r
+' Array.prototype.pop = function() {',\r
+' if (this.length > 0) {',\r
+' var val = this[this.length - 1];',\r
+' this.length = this.length - 1;',\r
+' return val;',\r
+' }',\r
+' };',\r
+' }',\r
+'',\r
+' if (!Array.prototype.shift) {',\r
+' Array.prototype.shift = function() {',\r
+' if (this.length > 0) {',\r
+' var firstItem = this[0];',\r
+' for (var i = 0, len = this.length - 1; i < len; i++) {',\r
+' this[i] = this[i + 1];',\r
+' }',\r
+' this.length = this.length - 1;',\r
+' return firstItem;',\r
+' }',\r
+' };',\r
+' }',\r
+'',\r
+' if (!Array.prototype.splice) {',\r
+' Array.prototype.splice = function(startIndex, deleteCount) {',\r
+' var itemsAfterDeleted = this.slice(startIndex + deleteCount);',\r
+' var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);',\r
+' this.length = startIndex;',\r
+' // Copy the arguments into a proper Array object',\r
+' var argumentsArray = [];',\r
+' for (var i = 0, len = arguments.length; i < len; i++) {',\r
+' argumentsArray[i] = arguments[i];',\r
+' }',\r
+' var itemsToAppend = (argumentsArray.length > 2) ?',\r
+' itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;',\r
+' for (i = 0, len = itemsToAppend.length; i < len; i++) {',\r
+' this.push(itemsToAppend[i]);',\r
+' }',\r
+' return itemsDeleted;',\r
+' };',\r
+' }',\r
+'',\r
+' function array_remove(arr, val) {',\r
+' var index = -1;',\r
+' for (var i = 0, len = arr.length; i < len; i++) {',\r
+' if (arr[i] === val) {',\r
+' index = i;',\r
+' break;',\r
+' }',\r
+' }',\r
+' if (index >= 0) {',\r
+' arr.splice(index, 1);',\r
+' return index;',\r
+' } else {',\r
+' return false;',\r
+' }',\r
+' }',\r
+'',\r
+' function array_removeFromStart(array, numberToRemove) {',\r
+' if (Array.prototype.splice) {',\r
+' array.splice(0, numberToRemove);',\r
+' } else {',\r
+' for (var i = numberToRemove, len = array.length; i < len; i++) {',\r
+' array[i - numberToRemove] = array[i];',\r
+' }',\r
+' array.length = array.length - numberToRemove;',\r
+' }',\r
+' return array;',\r
+' }',\r
+'',\r
+' function array_contains(arr, val) {',\r
+' for (var i = 0, len = arr.length; i < len; i++) {',\r
+' if (arr[i] == val) {',\r
+' return true;',\r
+' }',\r
+' }',\r
+' return false;',\r
+' }',\r
+'',\r
+' function getErrorMessage(ex) {',\r
+' if (ex.message) {',\r
+' return ex.message;',\r
+' } else if (ex.description) {',\r
+' return ex.description;',\r
+' }',\r
+' return "" + ex;',\r
+' }',\r
+'',\r
+' function moveCaretToEnd(input) {',\r
+' if (input.setSelectionRange) {',\r
+' input.focus();',\r
+' var length = input.value.length;',\r
+' input.setSelectionRange(length, length);',\r
+' } else if (input.createTextRange) {',\r
+' var range = input.createTextRange();',\r
+' range.collapse(false);',\r
+' range.select();',\r
+' }',\r
+' input.focus();',\r
+' }',\r
+'',\r
+' function stopPropagation(evt) {',\r
+' if (evt.stopPropagation) {',\r
+' evt.stopPropagation();',\r
+' } else if (typeof evt.cancelBubble != "undefined") {',\r
+' evt.cancelBubble = true;',\r
+' }',\r
+' }',\r
+'',\r
+' function getEvent(evt) {',\r
+' return evt ? evt : event;',\r
+' }',\r
+'',\r
+' function getTarget(evt) {',\r
+' return evt.target ? evt.target : evt.srcElement;',\r
+' }',\r
+'',\r
+' function getRelatedTarget(evt) {',\r
+' if (evt.relatedTarget) {',\r
+' return evt.relatedTarget;',\r
+' } else if (evt.srcElement) {',\r
+' switch(evt.type) {',\r
+' case "mouseover":',\r
+' return evt.fromElement;',\r
+' case "mouseout":',\r
+' return evt.toElement;',\r
+' default:',\r
+' return evt.srcElement;',\r
+' }',\r
+' }',\r
+' }',\r
+'',\r
+' function cancelKeyEvent(evt) {',\r
+' evt.returnValue = false;',\r
+' stopPropagation(evt);',\r
+' }',\r
+'',\r
+' function evalCommandLine() {',\r
+' var expr = $("command").value;',\r
+' evalCommand(expr);',\r
+' $("command").value = "";',\r
+' }',\r
+'',\r
+' function evalLastCommand() {',\r
+' if (lastCommand != null) {',\r
+' evalCommand(lastCommand);',\r
+' }',\r
+' }',\r
+'',\r
+' var lastCommand = null;',\r
+' var commandHistory = [];',\r
+' var currentCommandIndex = 0;',\r
+'',\r
+' function evalCommand(expr) {',\r
+' if (appender) {',\r
+' appender.evalCommandAndAppend(expr);',\r
+' } else {',\r
+' var prefix = ">>> " + expr + "\\r\\n";',\r
+' try {',\r
+' log("INFO", prefix + eval(expr));',\r
+' } catch (ex) {',\r
+' log("ERROR", prefix + "Error: " + getErrorMessage(ex));',\r
+' }',\r
+' }',\r
+' // Update command history',\r
+' if (expr != commandHistory[commandHistory.length - 1]) {',\r
+' commandHistory.push(expr);',\r
+' // Update the appender',\r
+' if (appender) {',\r
+' appender.storeCommandHistory(commandHistory);',\r
+' }',\r
+' }',\r
+' currentCommandIndex = (expr == commandHistory[currentCommandIndex]) ? currentCommandIndex + 1 : commandHistory.length;',\r
+' lastCommand = expr;',\r
+' }',\r
+' //]]>',\r
+' </script>',\r
+' <style type="text/css">',\r
+' body {',\r
+' background-color: white;',\r
+' color: black;',\r
+' padding: 0;',\r
+' margin: 0;',\r
+' font-family: tahoma, verdana, arial, helvetica, sans-serif;',\r
+' overflow: hidden;',\r
+' }',\r
+'',\r
+' div#switchesContainer input {',\r
+' margin-bottom: 0;',\r
+' }',\r
+'',\r
+' div.toolbar {',\r
+' border-top: solid #ffffff 1px;',\r
+' border-bottom: solid #aca899 1px;',\r
+' background-color: #f1efe7;',\r
+' padding: 3px 5px;',\r
+' font-size: 68.75%;',\r
+' }',\r
+'',\r
+' div.toolbar, div#search input {',\r
+' font-family: tahoma, verdana, arial, helvetica, sans-serif;',\r
+' }',\r
+'',\r
+' div.toolbar input.button {',\r
+' padding: 0 5px;',\r
+' font-size: 100%;',\r
+' }',\r
+'',\r
+' div.toolbar input.hidden {',\r
+' display: none;',\r
+' }',\r
+'',\r
+' div#switches input#clearButton {',\r
+' margin-left: 20px;',\r
+' }',\r
+'',\r
+' div#levels label {',\r
+' font-weight: bold;',\r
+' }',\r
+'',\r
+' div#levels label, div#options label {',\r
+' margin-right: 5px;',\r
+' }',\r
+'',\r
+' div#levels label#wrapLabel {',\r
+' font-weight: normal;',\r
+' }',\r
+'',\r
+' div#search label {',\r
+' margin-right: 10px;',\r
+' }',\r
+'',\r
+' div#search label.searchboxlabel {',\r
+' margin-right: 0;',\r
+' }',\r
+'',\r
+' div#search input {',\r
+' font-size: 100%;',\r
+' }',\r
+'',\r
+' div#search input.validregex {',\r
+' color: green;',\r
+' }',\r
+'',\r
+' div#search input.invalidregex {',\r
+' color: red;',\r
+' }',\r
+'',\r
+' div#search input.nomatches {',\r
+' color: white;',\r
+' background-color: #ff6666;',\r
+' }',\r
+'',\r
+' div#search input.nomatches {',\r
+' color: white;',\r
+' background-color: #ff6666;',\r
+' }',\r
+'',\r
+' div#searchNav {',\r
+' display: none;',\r
+' }',\r
+'',\r
+' div#commandLine {',\r
+' display: none;',\r
+' }',\r
+'',\r
+' div#commandLine input#command {',\r
+' font-size: 100%;',\r
+' font-family: Courier New, Courier;',\r
+' }',\r
+'',\r
+' div#commandLine input#evaluateButton {',\r
+' }',\r
+'',\r
+' *.greyedout {',\r
+' color: gray !important;',\r
+' border-color: gray !important;',\r
+' }',\r
+'',\r
+' *.greyedout *.alwaysenabled { color: black; }',\r
+'',\r
+' *.unselectable {',\r
+' -khtml-user-select: none;',\r
+' -moz-user-select: none;',\r
+' user-select: none;',\r
+' }',\r
+'',\r
+' div#log {',\r
+' font-family: Courier New, Courier;',\r
+' font-size: 75%;',\r
+' width: 100%;',\r
+' overflow: auto;',\r
+' clear: both;',\r
+' position: relative;',\r
+' }',\r
+'',\r
+' div.group {',\r
+' border-color: #cccccc;',\r
+' border-style: solid;',\r
+' border-width: 1px 0 1px 1px;',\r
+' overflow: visible;',\r
+' }',\r
+'',\r
+' div.oldIe div.group, div.oldIe div.group *, div.oldIe *.logentry {',\r
+' height: 1%;',\r
+' }',\r
+'',\r
+' div.group div.groupheading span.expander {',\r
+' border: solid black 1px;',\r
+' font-family: Courier New, Courier;',\r
+' font-size: 0.833em;',\r
+' background-color: #eeeeee;',\r
+' position: relative;',\r
+' top: -1px;',\r
+' color: black;',\r
+' padding: 0 2px;',\r
+' cursor: pointer;',\r
+' cursor: hand;',\r
+' height: 1%;',\r
+' }',\r
+'',\r
+' div.group div.groupcontent {',\r
+' margin-left: 10px;',\r
+' padding-bottom: 2px;',\r
+' overflow: visible;',\r
+' }',\r
+'',\r
+' div.group div.expanded {',\r
+' display: block;',\r
+' }',\r
+'',\r
+' div.group div.collapsed {',\r
+' display: none;',\r
+' }',\r
+'',\r
+' *.logentry {',\r
+' overflow: visible;',\r
+' display: none;',\r
+' white-space: pre;',\r
+' }',\r
+'',\r
+' span.pre {',\r
+' white-space: pre;',\r
+' }',\r
+' ',\r
+' pre.unwrapped {',\r
+' display: inline !important;',\r
+' }',\r
+'',\r
+' pre.unwrapped pre.pre, div.wrapped pre.pre {',\r
+' display: inline;',\r
+' }',\r
+'',\r
+' div.wrapped pre.pre {',\r
+' white-space: normal;',\r
+' }',\r
+'',\r
+' div.wrapped {',\r
+' display: none;',\r
+' }',\r
+'',\r
+' body.searching *.logentry span.currentmatch {',\r
+' color: white !important;',\r
+' background-color: green !important;',\r
+' }',\r
+'',\r
+' body.searching div.searchhighlight *.logentry span.searchterm {',\r
+' color: black;',\r
+' background-color: yellow;',\r
+' }',\r
+'',\r
+' div.wrap *.logentry {',\r
+' white-space: normal !important;',\r
+' border-width: 0 0 1px 0;',\r
+' border-color: #dddddd;',\r
+' border-style: dotted;',\r
+' }',\r
+'',\r
+' div.wrap #log_wrapped, #log_unwrapped {',\r
+' display: block;',\r
+' }',\r
+'',\r
+' div.wrap #log_unwrapped, #log_wrapped {',\r
+' display: none;',\r
+' }',\r
+'',\r
+' div.wrap *.logentry span.pre {',\r
+' overflow: visible;',\r
+' white-space: normal;',\r
+' }',\r
+'',\r
+' div.wrap *.logentry pre.unwrapped {',\r
+' display: none;',\r
+' }',\r
+'',\r
+' div.wrap *.logentry span.wrapped {',\r
+' display: inline;',\r
+' }',\r
+'',\r
+' div.searchfilter *.searchnonmatch {',\r
+' display: none !important;',\r
+' }',\r
+'',\r
+' div#log *.TRACE, label#label_TRACE {',\r
+' color: #666666;',\r
+' }',\r
+'',\r
+' div#log *.DEBUG, label#label_DEBUG {',\r
+' color: green;',\r
+' }',\r
+'',\r
+' div#log *.INFO, label#label_INFO {',\r
+' color: #000099;',\r
+' }',\r
+'',\r
+' div#log *.WARN, label#label_WARN {',\r
+' color: #999900;',\r
+' }',\r
+'',\r
+' div#log *.ERROR, label#label_ERROR {',\r
+' color: red;',\r
+' }',\r
+'',\r
+' div#log *.FATAL, label#label_FATAL {',\r
+' color: #660066;',\r
+' }',\r
+'',\r
+' div.TRACE#log *.TRACE,',\r
+' div.DEBUG#log *.DEBUG,',\r
+' div.INFO#log *.INFO,',\r
+' div.WARN#log *.WARN,',\r
+' div.ERROR#log *.ERROR,',\r
+' div.FATAL#log *.FATAL {',\r
+' display: block;',\r
+' }',\r
+'',\r
+' div#log div.separator {',\r
+' background-color: #cccccc;',\r
+' margin: 5px 0;',\r
+' line-height: 1px;',\r
+' }',\r
+' </style>',\r
+' </head>',\r
+'',\r
+' <body id="body">',\r
+' <div id="switchesContainer">',\r
+' <div id="switches">',\r
+' <div id="levels" class="toolbar">',\r
+' Filters:',\r
+' <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>',\r
+' <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>',\r
+' <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>',\r
+' <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>',\r
+' <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>',\r
+' <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>',\r
+' <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>',\r
+' </div>',\r
+' <div id="search" class="toolbar">',\r
+' <label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />',\r
+' <input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />',\r
+' <input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>',\r
+' <input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>',\r
+' <input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>',\r
+' <div id="searchNav">',\r
+' <input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />',\r
+' <input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />',\r
+' <input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>',\r
+' <input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>',\r
+' </div>',\r
+' </div>',\r
+' <div id="options" class="toolbar">',\r
+' Options:',\r
+' <input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>',\r
+' <input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>',\r
+' <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>',\r
+' <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>',\r
+' <input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages" />',\r
+' <input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />',\r
+' <input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />',\r
+' </div>',\r
+' </div>',\r
+' </div>',\r
+' <div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>',\r
+' <div id="commandLine" class="toolbar">',\r
+' <div id="commandLineContainer">',\r
+' <input type="text" id="command" title="Enter a JavaScript command here and hit return or press \'Evaluate\'" />',\r
+' <input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />',\r
+' </div>',\r
+' </div>',\r
+' </body>',\r
+'</html>',\r
+''\r
+];\r
+ };\r
+\r
+ var defaultCommandLineFunctions = [];\r
+\r
+ ConsoleAppender = function() {};\r
+\r
+ var consoleAppenderIdCounter = 1;\r
+ ConsoleAppender.prototype = new Appender();\r
+\r
+ ConsoleAppender.prototype.create = function(inPage, container,\r
+ lazyInit, initiallyMinimized, useDocumentWrite, width, height, focusConsoleWindow) {\r
+ var appender = this;\r
+\r
+ // Common properties\r
+ var initialized = false;\r
+ var consoleWindowCreated = false;\r
+ var consoleWindowLoaded = false;\r
+ var consoleClosed = false;\r
+\r
+ var queuedLoggingEvents = [];\r
+ var isSupported = true;\r
+ var consoleAppenderId = consoleAppenderIdCounter++;\r
+\r
+ // Local variables\r
+ initiallyMinimized = extractBooleanFromParam(initiallyMinimized, this.defaults.initiallyMinimized);\r
+ lazyInit = extractBooleanFromParam(lazyInit, this.defaults.lazyInit);\r
+ useDocumentWrite = extractBooleanFromParam(useDocumentWrite, this.defaults.useDocumentWrite);\r
+ var newestMessageAtTop = this.defaults.newestMessageAtTop;\r
+ var scrollToLatestMessage = this.defaults.scrollToLatestMessage;\r
+ width = width ? width : this.defaults.width;\r
+ height = height ? height : this.defaults.height;\r
+ var maxMessages = this.defaults.maxMessages;\r
+ var showCommandLine = this.defaults.showCommandLine;\r
+ var commandLineObjectExpansionDepth = this.defaults.commandLineObjectExpansionDepth;\r
+ var showHideButton = this.defaults.showHideButton;\r
+ var showCloseButton = this.defaults.showCloseButton;\r
+ var showLogEntryDeleteButtons = this.defaults.showLogEntryDeleteButtons;\r
+\r
+ this.setLayout(this.defaults.layout);\r
+\r
+ // Functions whose implementations vary between subclasses\r
+ var init, createWindow, safeToAppend, getConsoleWindow, open;\r
+\r
+ // Configuration methods. The function scope is used to prevent\r
+ // direct alteration to the appender configuration properties.\r
+ var appenderName = inPage ? "InPageAppender" : "PopUpAppender";\r
+ var checkCanConfigure = function(configOptionName) {\r
+ if (consoleWindowCreated) {\r
+ handleError(appenderName + ": configuration option '" + configOptionName + "' may not be set after the appender has been initialized");\r
+ return false;\r
+ }\r
+ return true;\r
+ };\r
+\r
+ var consoleWindowExists = function() {\r
+ return (consoleWindowLoaded && isSupported && !consoleClosed);\r
+ };\r
+\r
+ this.isNewestMessageAtTop = function() { return newestMessageAtTop; };\r
+ this.setNewestMessageAtTop = function(newestMessageAtTopParam) {\r
+ newestMessageAtTop = bool(newestMessageAtTopParam);\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().setNewestAtTop(newestMessageAtTop);\r
+ }\r
+ };\r
+\r
+ this.isScrollToLatestMessage = function() { return scrollToLatestMessage; };\r
+ this.setScrollToLatestMessage = function(scrollToLatestMessageParam) {\r
+ scrollToLatestMessage = bool(scrollToLatestMessageParam);\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().setScrollToLatest(scrollToLatestMessage);\r
+ }\r
+ };\r
+\r
+ this.getWidth = function() { return width; };\r
+ this.setWidth = function(widthParam) {\r
+ if (checkCanConfigure("width")) {\r
+ width = extractStringFromParam(widthParam, width);\r
+ }\r
+ };\r
+\r
+ this.getHeight = function() { return height; };\r
+ this.setHeight = function(heightParam) {\r
+ if (checkCanConfigure("height")) {\r
+ height = extractStringFromParam(heightParam, height);\r
+ }\r
+ };\r
+\r
+ this.getMaxMessages = function() { return maxMessages; };\r
+ this.setMaxMessages = function(maxMessagesParam) {\r
+ maxMessages = extractIntFromParam(maxMessagesParam, maxMessages);\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().setMaxMessages(maxMessages);\r
+ }\r
+ };\r
+\r
+ this.isShowCommandLine = function() { return showCommandLine; };\r
+ this.setShowCommandLine = function(showCommandLineParam) {\r
+ showCommandLine = bool(showCommandLineParam);\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().setShowCommandLine(showCommandLine);\r
+ }\r
+ };\r
+\r
+ this.isShowHideButton = function() { return showHideButton; };\r
+ this.setShowHideButton = function(showHideButtonParam) {\r
+ showHideButton = bool(showHideButtonParam);\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().setShowHideButton(showHideButton);\r
+ }\r
+ };\r
+\r
+ this.isShowCloseButton = function() { return showCloseButton; };\r
+ this.setShowCloseButton = function(showCloseButtonParam) {\r
+ showCloseButton = bool(showCloseButtonParam);\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().setShowCloseButton(showCloseButton);\r
+ }\r
+ };\r
+\r
+ this.getCommandLineObjectExpansionDepth = function() { return commandLineObjectExpansionDepth; };\r
+ this.setCommandLineObjectExpansionDepth = function(commandLineObjectExpansionDepthParam) {\r
+ commandLineObjectExpansionDepth = extractIntFromParam(commandLineObjectExpansionDepthParam, commandLineObjectExpansionDepth);\r
+ };\r
+\r
+ var minimized = initiallyMinimized;\r
+ this.isInitiallyMinimized = function() { return initiallyMinimized; };\r
+ this.setInitiallyMinimized = function(initiallyMinimizedParam) {\r
+ if (checkCanConfigure("initiallyMinimized")) {\r
+ initiallyMinimized = bool(initiallyMinimizedParam);\r
+ minimized = initiallyMinimized;\r
+ }\r
+ };\r
+\r
+ this.isUseDocumentWrite = function() { return useDocumentWrite; };\r
+ this.setUseDocumentWrite = function(useDocumentWriteParam) {\r
+ if (checkCanConfigure("useDocumentWrite")) {\r
+ useDocumentWrite = bool(useDocumentWriteParam);\r
+ }\r
+ };\r
+\r
+ // Common methods\r
+ function QueuedLoggingEvent(loggingEvent, formattedMessage) {\r
+ this.loggingEvent = loggingEvent;\r
+ this.levelName = loggingEvent.level.name;\r
+ this.formattedMessage = formattedMessage;\r
+ }\r
+\r
+ QueuedLoggingEvent.prototype.append = function() {\r
+ getConsoleWindow().log(this.levelName, this.formattedMessage);\r
+ };\r
+\r
+ function QueuedGroup(name, initiallyExpanded) {\r
+ this.name = name;\r
+ this.initiallyExpanded = initiallyExpanded;\r
+ }\r
+\r
+ QueuedGroup.prototype.append = function() {\r
+ getConsoleWindow().group(this.name, this.initiallyExpanded);\r
+ };\r
+\r
+ function QueuedGroupEnd() {}\r
+\r
+ QueuedGroupEnd.prototype.append = function() {\r
+ getConsoleWindow().groupEnd();\r
+ };\r
+\r
+ var checkAndAppend = function() {\r
+ // Next line forces a check of whether the window has been closed\r
+ safeToAppend();\r
+ if (!initialized) {\r
+ init();\r
+ } else if (consoleClosed && reopenWhenClosed) {\r
+ createWindow();\r
+ }\r
+ if (safeToAppend()) {\r
+ appendQueuedLoggingEvents();\r
+ }\r
+ };\r
+\r
+ this.append = function(loggingEvent) {\r
+ if (isSupported) {\r
+ // Format the message\r
+ var formattedMessage = appender.getLayout().format(loggingEvent);\r
+ if (this.getLayout().ignoresThrowable()) {\r
+ formattedMessage += loggingEvent.getThrowableStrRep();\r
+ }\r
+ queuedLoggingEvents.push(new QueuedLoggingEvent(loggingEvent, formattedMessage));\r
+ checkAndAppend();\r
+ }\r
+ };\r
+\r
+ this.group = function(name, initiallyExpanded) {\r
+ if (isSupported) {\r
+ queuedLoggingEvents.push(new QueuedGroup(name, initiallyExpanded));\r
+ checkAndAppend();\r
+ }\r
+ };\r
+\r
+ this.groupEnd = function() {\r
+ if (isSupported) {\r
+ queuedLoggingEvents.push(new QueuedGroupEnd());\r
+ checkAndAppend();\r
+ }\r
+ };\r
+\r
+ var appendQueuedLoggingEvents = function() {\r
+ var currentLoggingEvent;\r
+ while (queuedLoggingEvents.length > 0) {\r
+ queuedLoggingEvents.shift().append();\r
+ }\r
+ if (focusConsoleWindow) {\r
+ getConsoleWindow().focus();\r
+ }\r
+ };\r
+\r
+ this.setAddedToLogger = function(logger) {\r
+ this.loggers.push(logger);\r
+ if (enabled && !lazyInit) {\r
+ init();\r
+ }\r
+ };\r
+\r
+ this.clear = function() {\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().clearLog();\r
+ }\r
+ queuedLoggingEvents.length = 0;\r
+ };\r
+\r
+ this.focus = function() {\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().focus();\r
+ }\r
+ };\r
+\r
+ this.focusCommandLine = function() {\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().focusCommandLine();\r
+ }\r
+ };\r
+\r
+ this.focusSearch = function() {\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().focusSearch();\r
+ }\r
+ };\r
+\r
+ var commandWindow = window;\r
+\r
+ this.getCommandWindow = function() { return commandWindow; };\r
+ this.setCommandWindow = function(commandWindowParam) {\r
+ commandWindow = commandWindowParam;\r
+ };\r
+\r
+ this.executeLastCommand = function() {\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().evalLastCommand();\r
+ }\r
+ };\r
+\r
+ var commandLayout = new PatternLayout("%m");\r
+ this.getCommandLayout = function() { return commandLayout; };\r
+ this.setCommandLayout = function(commandLayoutParam) {\r
+ commandLayout = commandLayoutParam;\r
+ };\r
+\r
+ this.evalCommandAndAppend = function(expr) {\r
+ var commandReturnValue = { appendResult: true, isError: false };\r
+ var commandOutput = "";\r
+ // Evaluate the command\r
+ try {\r
+ var result, i;\r
+ // The next three lines constitute a workaround for IE. Bizarrely, iframes seem to have no\r
+ // eval method on the window object initially, but once execScript has been called on\r
+ // it once then the eval method magically appears. See http://www.thismuchiknow.co.uk/?p=25\r
+ if (!commandWindow.eval && commandWindow.execScript) {\r
+ commandWindow.execScript("null");\r
+ }\r
+\r
+ var commandLineFunctionsHash = {};\r
+ for (i = 0, len = commandLineFunctions.length; i < len; i++) {\r
+ commandLineFunctionsHash[commandLineFunctions[i][0]] = commandLineFunctions[i][1];\r
+ }\r
+\r
+ // Keep an array of variables that are being changed in the command window so that they\r
+ // can be restored to their original values afterwards\r
+ var objectsToRestore = [];\r
+ var addObjectToRestore = function(name) {\r
+ objectsToRestore.push([name, commandWindow[name]]);\r
+ };\r
+\r
+ addObjectToRestore("appender");\r
+ commandWindow.appender = appender;\r
+\r
+ addObjectToRestore("commandReturnValue");\r
+ commandWindow.commandReturnValue = commandReturnValue;\r
+\r
+ addObjectToRestore("commandLineFunctionsHash");\r
+ commandWindow.commandLineFunctionsHash = commandLineFunctionsHash;\r
+\r
+ var addFunctionToWindow = function(name) {\r
+ addObjectToRestore(name);\r
+ commandWindow[name] = function() {\r
+ return this.commandLineFunctionsHash[name](appender, arguments, commandReturnValue);\r
+ };\r
+ };\r
+\r
+ for (i = 0, len = commandLineFunctions.length; i < len; i++) {\r
+ addFunctionToWindow(commandLineFunctions[i][0]);\r
+ }\r
+\r
+ // Another bizarre workaround to get IE to eval in the global scope\r
+ if (commandWindow === window && commandWindow.execScript) {\r
+ addObjectToRestore("evalExpr");\r
+ addObjectToRestore("result");\r
+ window.evalExpr = expr;\r
+ commandWindow.execScript("window.result=eval(window.evalExpr);");\r
+ result = window.result;\r
+ } else {\r
+ result = commandWindow.eval(expr);\r
+ }\r
+ commandOutput = isUndefined(result) ? result : formatObjectExpansion(result, commandLineObjectExpansionDepth);\r
+\r
+ // Restore variables in the command window to their original state\r
+ for (i = 0, len = objectsToRestore.length; i < len; i++) {\r
+ commandWindow[objectsToRestore[i][0]] = objectsToRestore[i][1];\r
+ }\r
+ } catch (ex) {\r
+ commandOutput = "Error evaluating command: " + getExceptionStringRep(ex);\r
+ commandReturnValue.isError = true;\r
+ }\r
+ // Append command output\r
+ if (commandReturnValue.appendResult) {\r
+ var message = ">>> " + expr;\r
+ if (!isUndefined(commandOutput)) {\r
+ message += newLine + commandOutput;\r
+ }\r
+ var level = commandReturnValue.isError ? Level.ERROR : Level.INFO;\r
+ var loggingEvent = new LoggingEvent(null, new Date(), level, [message], null);\r
+ var mainLayout = this.getLayout();\r
+ this.setLayout(commandLayout);\r
+ this.append(loggingEvent);\r
+ this.setLayout(mainLayout);\r
+ }\r
+ };\r
+\r
+ var commandLineFunctions = defaultCommandLineFunctions.concat([]);\r
+\r
+ this.addCommandLineFunction = function(functionName, commandLineFunction) {\r
+ commandLineFunctions.push([functionName, commandLineFunction]);\r
+ };\r
+\r
+ var commandHistoryCookieName = "log4javascriptCommandHistory";\r
+ this.storeCommandHistory = function(commandHistory) {\r
+ setCookie(commandHistoryCookieName, commandHistory.join(","));\r
+ };\r
+\r
+ var writeHtml = function(doc) {\r
+ var lines = getConsoleHtmlLines();\r
+ doc.open();\r
+ for (var i = 0, len = lines.length; i < len; i++) {\r
+ doc.writeln(lines[i]);\r
+ }\r
+ doc.close();\r
+ };\r
+\r
+ // Set up event listeners\r
+ this.setEventTypes(["load", "unload"]);\r
+\r
+ var consoleWindowLoadHandler = function() {\r
+ var win = getConsoleWindow();\r
+ win.setAppender(appender);\r
+ win.setNewestAtTop(newestMessageAtTop);\r
+ win.setScrollToLatest(scrollToLatestMessage);\r
+ win.setMaxMessages(maxMessages);\r
+ win.setShowCommandLine(showCommandLine);\r
+ win.setShowHideButton(showHideButton);\r
+ win.setShowCloseButton(showCloseButton);\r
+ win.setMainWindow(window);\r
+\r
+ // Restore command history stored in cookie\r
+ var storedValue = getCookie(commandHistoryCookieName);\r
+ if (storedValue) {\r
+ win.commandHistory = storedValue.split(",");\r
+ win.currentCommandIndex = win.commandHistory.length;\r
+ }\r
+\r
+ appender.dispatchEvent("load", { "win" : win });\r
+ };\r
+\r
+ this.unload = function() {\r
+ logLog.debug("unload " + this + ", caller: " + this.unload.caller);\r
+ if (!consoleClosed) {\r
+ logLog.debug("really doing unload " + this);\r
+ consoleClosed = true;\r
+ consoleWindowLoaded = false;\r
+ consoleWindowCreated = false;\r
+ appender.dispatchEvent("unload", {});\r
+ }\r
+ };\r
+\r
+ var pollConsoleWindow = function(windowTest, interval, successCallback, errorMessage) {\r
+ function doPoll() {\r
+ try {\r
+ // Test if the console has been closed while polling\r
+ if (consoleClosed) {\r
+ clearInterval(poll);\r
+ }\r
+ if (windowTest(getConsoleWindow())) {\r
+ clearInterval(poll);\r
+ successCallback();\r
+ }\r
+ } catch (ex) {\r
+ clearInterval(poll);\r
+ isSupported = false;\r
+ handleError(errorMessage, ex);\r
+ }\r
+ }\r
+\r
+ // Poll the pop-up since the onload event is not reliable\r
+ var poll = setInterval(doPoll, interval);\r
+ };\r
+\r
+ var getConsoleUrl = function() {\r
+ var documentDomainSet = (document.domain != location.hostname);\r
+ return useDocumentWrite ? "" : getBaseUrl() + "console_uncompressed.html" +\r
+ (documentDomainSet ? "?log4javascript_domain=" + escape(document.domain) : "");\r
+ };\r
+\r
+ // Define methods and properties that vary between subclasses\r
+ if (inPage) {\r
+ // InPageAppender\r
+\r
+ var containerElement = null;\r
+\r
+ // Configuration methods. The function scope is used to prevent\r
+ // direct alteration to the appender configuration properties.\r
+ var cssProperties = [];\r
+ this.addCssProperty = function(name, value) {\r
+ if (checkCanConfigure("cssProperties")) {\r
+ cssProperties.push([name, value]);\r
+ }\r
+ };\r
+\r
+ // Define useful variables\r
+ var windowCreationStarted = false;\r
+ var iframeContainerDiv;\r
+ var iframeId = uniqueId + "_InPageAppender_" + consoleAppenderId;\r
+\r
+ this.hide = function() {\r
+ if (initialized && consoleWindowCreated) {\r
+ if (consoleWindowExists()) {\r
+ getConsoleWindow().$("command").blur();\r
+ }\r
+ iframeContainerDiv.style.display = "none";\r
+ minimized = true;\r
+ }\r
+ };\r
+\r
+ this.show = function() {\r
+ if (initialized) {\r
+ if (consoleWindowCreated) {\r
+ iframeContainerDiv.style.display = "block";\r
+ this.setShowCommandLine(showCommandLine); // Force IE to update\r
+ minimized = false;\r
+ } else if (!windowCreationStarted) {\r
+ createWindow(true);\r
+ }\r
+ }\r
+ };\r
+\r
+ this.isVisible = function() {\r
+ return !minimized && !consoleClosed;\r
+ };\r
+\r
+ this.close = function(fromButton) {\r
+ if (!consoleClosed && (!fromButton || confirm("This will permanently remove the console from the page. No more messages will be logged. Do you wish to continue?"))) {\r
+ iframeContainerDiv.parentNode.removeChild(iframeContainerDiv);\r
+ this.unload();\r
+ }\r
+ };\r
+\r
+ // Create open, init, getConsoleWindow and safeToAppend functions\r
+ open = function() {\r
+ var initErrorMessage = "InPageAppender.open: unable to create console iframe";\r
+\r
+ function finalInit() {\r
+ try {\r
+ if (!initiallyMinimized) {\r
+ appender.show();\r
+ }\r
+ consoleWindowLoadHandler();\r
+ consoleWindowLoaded = true;\r
+ appendQueuedLoggingEvents();\r
+ } catch (ex) {\r
+ isSupported = false;\r
+ handleError(initErrorMessage, ex);\r
+ }\r
+ }\r
+\r
+ function writeToDocument() {\r
+ try {\r
+ var windowTest = function(win) { return isLoaded(win); };\r
+ if (useDocumentWrite) {\r
+ writeHtml(getConsoleWindow().document);\r
+ }\r
+ if (windowTest(getConsoleWindow())) {\r
+ finalInit();\r
+ } else {\r
+ pollConsoleWindow(windowTest, 100, finalInit, initErrorMessage);\r
+ }\r
+ } catch (ex) {\r
+ isSupported = false;\r
+ handleError(initErrorMessage, ex);\r
+ }\r
+ }\r
+\r
+ minimized = false;\r
+ iframeContainerDiv = containerElement.appendChild(document.createElement("div"));\r
+\r
+ iframeContainerDiv.style.width = width;\r
+ iframeContainerDiv.style.height = height;\r
+ iframeContainerDiv.style.border = "solid gray 1px";\r
+\r
+ for (var i = 0, len = cssProperties.length; i < len; i++) {\r
+ iframeContainerDiv.style[cssProperties[i][0]] = cssProperties[i][1];\r
+ }\r
+\r
+ var iframeSrc = useDocumentWrite ? "" : " src='" + getConsoleUrl() + "'";\r
+\r
+ // Adding an iframe using the DOM would be preferable, but it doesn't work\r
+ // in IE5 on Windows, or in Konqueror prior to version 3.5 - in Konqueror\r
+ // it creates the iframe fine but I haven't been able to find a way to obtain\r
+ // the iframe's window object\r
+ iframeContainerDiv.innerHTML = "<iframe id='" + iframeId + "' name='" + iframeId +\r
+ "' width='100%' height='100%' frameborder='0'" + iframeSrc +\r
+ " scrolling='no'></iframe>";\r
+ consoleClosed = false;\r
+\r
+ // Write the console HTML to the iframe\r
+ var iframeDocumentExistsTest = function(win) {\r
+ try {\r
+ return bool(win) && bool(win.document);\r
+ } catch (ex) {\r
+ return false;\r
+ }\r
+ };\r
+ if (iframeDocumentExistsTest(getConsoleWindow())) {\r
+ writeToDocument();\r
+ } else {\r
+ pollConsoleWindow(iframeDocumentExistsTest, 100, writeToDocument, initErrorMessage);\r
+ }\r
+ consoleWindowCreated = true;\r
+ };\r
+\r
+ createWindow = function(show) {\r
+ if (show || !initiallyMinimized) {\r
+ var pageLoadHandler = function() {\r
+ if (!container) {\r
+ // Set up default container element\r
+ containerElement = document.createElement("div");\r
+ containerElement.style.position = "fixed";\r
+ containerElement.style.left = "0";\r
+ containerElement.style.right = "0";\r
+ containerElement.style.bottom = "0";\r
+ document.body.appendChild(containerElement);\r
+ appender.addCssProperty("borderWidth", "1px 0 0 0");\r
+ appender.addCssProperty("zIndex", 1000000); // Can't find anything authoritative that says how big z-index can be\r
+ open();\r
+ } else {\r
+ try {\r
+ var el = document.getElementById(container);\r
+ if (el.nodeType == 1) {\r
+ containerElement = el;\r
+ }\r
+ open();\r
+ } catch (ex) {\r
+ handleError("InPageAppender.init: invalid container element '" + container + "' supplied", ex);\r
+ }\r
+ }\r
+ };\r
+\r
+ // Test the type of the container supplied. First, check if it's an element\r
+ if (pageLoaded && container && container.appendChild) {\r
+ containerElement = container;\r
+ open();\r
+ } else if (pageLoaded) {\r
+ pageLoadHandler();\r
+ } else {\r
+ log4javascript.addEventListener("load", pageLoadHandler);\r
+ }\r
+ windowCreationStarted = true;\r
+ }\r
+ };\r
+\r
+ init = function() {\r
+ createWindow();\r
+ initialized = true;\r
+ };\r
+\r
+ getConsoleWindow = function() {\r
+ var iframe = window.frames[iframeId];\r
+ if (iframe) {\r
+ return iframe;\r
+ }\r
+ };\r
+\r
+ safeToAppend = function() {\r
+ if (isSupported && !consoleClosed) {\r
+ if (consoleWindowCreated && !consoleWindowLoaded && getConsoleWindow() && isLoaded(getConsoleWindow())) {\r
+ consoleWindowLoaded = true;\r
+ }\r
+ return consoleWindowLoaded;\r
+ }\r
+ return false;\r
+ };\r
+ } else {\r
+ // PopUpAppender\r
+\r
+ // Extract params\r
+ var useOldPopUp = appender.defaults.useOldPopUp;\r
+ var complainAboutPopUpBlocking = appender.defaults.complainAboutPopUpBlocking;\r
+ var reopenWhenClosed = this.defaults.reopenWhenClosed;\r
+\r
+ // Configuration methods. The function scope is used to prevent\r
+ // direct alteration to the appender configuration properties.\r
+ this.isUseOldPopUp = function() { return useOldPopUp; };\r
+ this.setUseOldPopUp = function(useOldPopUpParam) {\r
+ if (checkCanConfigure("useOldPopUp")) {\r
+ useOldPopUp = bool(useOldPopUpParam);\r
+ }\r
+ };\r
+\r
+ this.isComplainAboutPopUpBlocking = function() { return complainAboutPopUpBlocking; };\r
+ this.setComplainAboutPopUpBlocking = function(complainAboutPopUpBlockingParam) {\r
+ if (checkCanConfigure("complainAboutPopUpBlocking")) {\r
+ complainAboutPopUpBlocking = bool(complainAboutPopUpBlockingParam);\r
+ }\r
+ };\r
+\r
+ this.isFocusPopUp = function() { return focusConsoleWindow; };\r
+ this.setFocusPopUp = function(focusPopUpParam) {\r
+ // This property can be safely altered after logging has started\r
+ focusConsoleWindow = bool(focusPopUpParam);\r
+ };\r
+\r
+ this.isReopenWhenClosed = function() { return reopenWhenClosed; };\r
+ this.setReopenWhenClosed = function(reopenWhenClosedParam) {\r
+ // This property can be safely altered after logging has started\r
+ reopenWhenClosed = bool(reopenWhenClosedParam);\r
+ };\r
+\r
+ this.close = function() {\r
+ logLog.debug("close " + this);\r
+ try {\r
+ popUp.close();\r
+ this.unload();\r
+ } catch (ex) {\r
+ // Do nothing\r
+ }\r
+ };\r
+\r
+ this.hide = function() {\r
+ logLog.debug("hide " + this);\r
+ if (consoleWindowExists()) {\r
+ this.close();\r
+ }\r
+ };\r
+\r
+ this.show = function() {\r
+ logLog.debug("show " + this);\r
+ if (!consoleWindowCreated) {\r
+ open();\r
+ }\r
+ };\r
+\r
+ this.isVisible = function() {\r
+ return safeToAppend();\r
+ };\r
+\r
+ // Define useful variables\r
+ var popUp;\r
+\r
+ // Create open, init, getConsoleWindow and safeToAppend functions\r
+ open = function() {\r
+ var windowProperties = "width=" + width + ",height=" + height + ",status,resizable";\r
+ var frameInfo = "";\r
+ try {\r
+ var frameEl = window.frameElement;\r
+ if (frameEl) {\r
+ frameInfo = "_" + frameEl.tagName + "_" + (frameEl.name || frameEl.id || "");\r
+ }\r
+ } catch (e) {\r
+ frameInfo = "_inaccessibleParentFrame";\r
+ }\r
+ var windowName = "PopUp_" + location.host.replace(/[^a-z0-9]/gi, "_") + "_" + consoleAppenderId + frameInfo;\r
+ if (!useOldPopUp || !useDocumentWrite) {\r
+ // Ensure a previous window isn't used by using a unique name\r
+ windowName = windowName + "_" + uniqueId;\r
+ }\r
+\r
+ var checkPopUpClosed = function(win) {\r
+ if (consoleClosed) {\r
+ return true;\r
+ } else {\r
+ try {\r
+ return bool(win) && win.closed;\r
+ } catch(ex) {}\r
+ }\r
+ return false;\r
+ };\r
+\r
+ var popUpClosedCallback = function() {\r
+ if (!consoleClosed) {\r
+ appender.unload();\r
+ }\r
+ };\r
+\r
+ function finalInit() {\r
+ getConsoleWindow().setCloseIfOpenerCloses(!useOldPopUp || !useDocumentWrite);\r
+ consoleWindowLoadHandler();\r
+ consoleWindowLoaded = true;\r
+ appendQueuedLoggingEvents();\r
+ pollConsoleWindow(checkPopUpClosed, 500, popUpClosedCallback,\r
+ "PopUpAppender.checkPopUpClosed: error checking pop-up window");\r
+ }\r
+\r
+ try {\r
+ popUp = window.open(getConsoleUrl(), windowName, windowProperties);\r
+ consoleClosed = false;\r
+ consoleWindowCreated = true;\r
+ if (popUp && popUp.document) {\r
+ if (useDocumentWrite && useOldPopUp && isLoaded(popUp)) {\r
+ popUp.mainPageReloaded();\r
+ finalInit();\r
+ } else {\r
+ if (useDocumentWrite) {\r
+ writeHtml(popUp.document);\r
+ }\r
+ // Check if the pop-up window object is available\r
+ var popUpLoadedTest = function(win) { return bool(win) && isLoaded(win); };\r
+ if (isLoaded(popUp)) {\r
+ finalInit();\r
+ } else {\r
+ pollConsoleWindow(popUpLoadedTest, 100, finalInit,\r
+ "PopUpAppender.init: unable to create console window");\r
+ }\r
+ }\r
+ } else {\r
+ isSupported = false;\r
+ logLog.warn("PopUpAppender.init: pop-ups blocked, please unblock to use PopUpAppender");\r
+ if (complainAboutPopUpBlocking) {\r
+ handleError("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");\r
+ }\r
+ }\r
+ } catch (ex) {\r
+ handleError("PopUpAppender.init: error creating pop-up", ex);\r
+ }\r
+ };\r
+\r
+ createWindow = function() {\r
+ if (!initiallyMinimized) {\r
+ open();\r
+ }\r
+ };\r
+\r
+ init = function() {\r
+ createWindow();\r
+ initialized = true;\r
+ };\r
+\r
+ getConsoleWindow = function() {\r
+ return popUp;\r
+ };\r
+\r
+ safeToAppend = function() {\r
+ if (isSupported && !isUndefined(popUp) && !consoleClosed) {\r
+ if (popUp.closed ||\r
+ (consoleWindowLoaded && isUndefined(popUp.closed))) { // Extra check for Opera\r
+ appender.unload();\r
+ logLog.debug("PopUpAppender: pop-up closed");\r
+ return false;\r
+ }\r
+ if (!consoleWindowLoaded && isLoaded(popUp)) {\r
+ consoleWindowLoaded = true;\r
+ }\r
+ }\r
+ return isSupported && consoleWindowLoaded && !consoleClosed;\r
+ };\r
+ }\r
+\r
+ // Expose getConsoleWindow so that automated tests can check the DOM\r
+ this.getConsoleWindow = getConsoleWindow;\r
+ };\r
+\r
+ ConsoleAppender.addGlobalCommandLineFunction = function(functionName, commandLineFunction) {\r
+ defaultCommandLineFunctions.push([functionName, commandLineFunction]);\r
+ };\r
+\r
+ /* ------------------------------------------------------------------ */\r
+\r
+ function PopUpAppender(lazyInit, initiallyMinimized, useDocumentWrite,\r
+ width, height) {\r
+ this.create(false, null, lazyInit, initiallyMinimized,\r
+ useDocumentWrite, width, height, this.defaults.focusPopUp);\r
+ }\r
+\r
+ PopUpAppender.prototype = new ConsoleAppender();\r
+\r
+ PopUpAppender.prototype.defaults = {\r
+ layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),\r
+ initiallyMinimized: false,\r
+ focusPopUp: false,\r
+ lazyInit: true,\r
+ useOldPopUp: true,\r
+ complainAboutPopUpBlocking: true,\r
+ newestMessageAtTop: false,\r
+ scrollToLatestMessage: true,\r
+ width: "600",\r
+ height: "400",\r
+ reopenWhenClosed: false,\r
+ maxMessages: null,\r
+ showCommandLine: true,\r
+ commandLineObjectExpansionDepth: 1,\r
+ showHideButton: false,\r
+ showCloseButton: true,\r
+ showLogEntryDeleteButtons: true,\r
+ useDocumentWrite: true\r
+ };\r
+\r
+ PopUpAppender.prototype.toString = function() {\r
+ return "PopUpAppender";\r
+ };\r
+\r
+ log4javascript.PopUpAppender = PopUpAppender;\r
+\r
+ /* ------------------------------------------------------------------ */\r
+\r
+ function InPageAppender(container, lazyInit, initiallyMinimized,\r
+ useDocumentWrite, width, height) {\r
+ this.create(true, container, lazyInit, initiallyMinimized,\r
+ useDocumentWrite, width, height, false);\r
+ }\r
+\r
+ InPageAppender.prototype = new ConsoleAppender();\r
+\r
+ InPageAppender.prototype.defaults = {\r
+ layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),\r
+ initiallyMinimized: false,\r
+ lazyInit: true,\r
+ newestMessageAtTop: false,\r
+ scrollToLatestMessage: true,\r
+ width: "100%",\r
+ height: "220px",\r
+ maxMessages: null,\r
+ showCommandLine: true,\r
+ commandLineObjectExpansionDepth: 1,\r
+ showHideButton: false,\r
+ showCloseButton: false,\r
+ showLogEntryDeleteButtons: true,\r
+ useDocumentWrite: true\r
+ };\r
+\r
+ InPageAppender.prototype.toString = function() {\r
+ return "InPageAppender";\r
+ };\r
+\r
+ log4javascript.InPageAppender = InPageAppender;\r
+\r
+ // Next line for backwards compatibility\r
+ log4javascript.InlineAppender = InPageAppender;\r
+ })();\r
+ /* ---------------------------------------------------------------------- */\r
+ // Console extension functions\r
+\r
+ function padWithSpaces(str, len) {\r
+ if (str.length < len) {\r
+ var spaces = [];\r
+ var numberOfSpaces = Math.max(0, len - str.length);\r
+ for (var i = 0; i < numberOfSpaces; i++) {\r
+ spaces[i] = " ";\r
+ }\r
+ str += spaces.join("");\r
+ }\r
+ return str;\r
+ }\r
+\r
+ (function() {\r
+ function dir(obj) {\r
+ var maxLen = 0;\r
+ // Obtain the length of the longest property name\r
+ for (var p in obj) {\r
+ maxLen = Math.max(toStr(p).length, maxLen);\r
+ }\r
+ // Create the nicely formatted property list\r
+ var propList = [];\r
+ for (p in obj) {\r
+ var propNameStr = " " + padWithSpaces(toStr(p), maxLen + 2);\r
+ var propVal;\r
+ try {\r
+ propVal = splitIntoLines(toStr(obj[p])).join(padWithSpaces(newLine, maxLen + 6));\r
+ } catch (ex) {\r
+ propVal = "[Error obtaining property. Details: " + getExceptionMessage(ex) + "]";\r
+ }\r
+ propList.push(propNameStr + propVal);\r
+ }\r
+ return propList.join(newLine);\r
+ }\r
+\r
+ var nodeTypes = {\r
+ ELEMENT_NODE: 1,\r
+ ATTRIBUTE_NODE: 2,\r
+ TEXT_NODE: 3,\r
+ CDATA_SECTION_NODE: 4,\r
+ ENTITY_REFERENCE_NODE: 5,\r
+ ENTITY_NODE: 6,\r
+ PROCESSING_INSTRUCTION_NODE: 7,\r
+ COMMENT_NODE: 8,\r
+ DOCUMENT_NODE: 9,\r
+ DOCUMENT_TYPE_NODE: 10,\r
+ DOCUMENT_FRAGMENT_NODE: 11,\r
+ NOTATION_NODE: 12\r
+ };\r
+\r
+ var preFormattedElements = ["script", "pre"];\r
+\r
+ // This should be the definitive list, as specified by the XHTML 1.0 Transitional DTD\r
+ var emptyElements = ["br", "img", "hr", "param", "link", "area", "input", "col", "base", "meta"];\r
+ var indentationUnit = " ";\r
+\r
+ // Create and return an XHTML string from the node specified\r
+ function getXhtml(rootNode, includeRootNode, indentation, startNewLine, preformatted) {\r
+ includeRootNode = (typeof includeRootNode == "undefined") ? true : !!includeRootNode;\r
+ if (typeof indentation != "string") {\r
+ indentation = "";\r
+ }\r
+ startNewLine = !!startNewLine;\r
+ preformatted = !!preformatted;\r
+ var xhtml;\r
+\r
+ function isWhitespace(node) {\r
+ return ((node.nodeType == nodeTypes.TEXT_NODE) && /^[ \t\r\n]*$/.test(node.nodeValue));\r
+ }\r
+\r
+ function fixAttributeValue(attrValue) {\r
+ return attrValue.toString().replace(/&/g, "&").replace(/</g, "<").replace(/"/g, """);\r
+ }\r
+\r
+ function getStyleAttributeValue(el) {\r
+ var stylePairs = el.style.cssText.split(";");\r
+ var styleValue = "";\r
+ var isFirst = true;\r
+ for (var j = 0, len = stylePairs.length; j < len; j++) {\r
+ var nameValueBits = stylePairs[j].split(":");\r
+ var props = [];\r
+ if (!/^\s*$/.test(nameValueBits[0])) {\r
+ props.push(trim(nameValueBits[0]).toLowerCase() + ":" + trim(nameValueBits[1]));\r
+ }\r
+ styleValue = props.join(";");\r
+ }\r
+ return styleValue;\r
+ }\r
+\r
+ function getNamespace(el) {\r
+ if (el.prefix) {\r
+ return el.prefix;\r
+ } else if (el.outerHTML) {\r
+ var regex = new RegExp("<([^:]+):" + el.tagName + "[^>]*>", "i");\r
+ if (regex.test(el.outerHTML)) {\r
+ return RegExp.$1.toLowerCase();\r
+ }\r
+ }\r
+ return "";\r
+ }\r
+\r
+ var lt = "<";\r
+ var gt = ">";\r
+\r
+ if (includeRootNode && rootNode.nodeType != nodeTypes.DOCUMENT_FRAGMENT_NODE) {\r
+ switch (rootNode.nodeType) {\r
+ case nodeTypes.ELEMENT_NODE:\r
+ var tagName = rootNode.tagName.toLowerCase();\r
+ xhtml = startNewLine ? newLine + indentation : "";\r
+ xhtml += lt;\r
+ // Allow for namespaces, where present\r
+ var prefix = getNamespace(rootNode);\r
+ var hasPrefix = !!prefix;\r
+ if (hasPrefix) {\r
+ xhtml += prefix + ":";\r
+ }\r
+ xhtml += tagName;\r
+ for (i = 0, len = rootNode.attributes.length; i < len; i++) {\r
+ var currentAttr = rootNode.attributes[i];\r
+ // Check the attribute is valid.\r
+ if (! currentAttr.specified ||\r
+ currentAttr.nodeValue === null ||\r
+ currentAttr.nodeName.toLowerCase() === "style" ||\r
+ typeof currentAttr.nodeValue !== "string" ||\r
+ currentAttr.nodeName.indexOf("_moz") === 0) {\r
+ continue;\r
+ }\r
+ xhtml += " " + currentAttr.nodeName.toLowerCase() + "=\"";\r
+ xhtml += fixAttributeValue(currentAttr.nodeValue);\r
+ xhtml += "\"";\r
+ }\r
+ // Style needs to be done separately as it is not reported as an\r
+ // attribute in IE\r
+ if (rootNode.style.cssText) {\r
+ var styleValue = getStyleAttributeValue(rootNode);\r
+ if (styleValue !== "") {\r
+ xhtml += " style=\"" + getStyleAttributeValue(rootNode) + "\"";\r
+ }\r
+ }\r
+ if (array_contains(emptyElements, tagName) ||\r
+ (hasPrefix && !rootNode.hasChildNodes())) {\r
+ xhtml += "/" + gt;\r
+ } else {\r
+ xhtml += gt;\r
+ // Add output for childNodes collection (which doesn't include attribute nodes)\r
+ var childStartNewLine = !(rootNode.childNodes.length === 1 &&\r
+ rootNode.childNodes[0].nodeType === nodeTypes.TEXT_NODE);\r
+ var childPreformatted = array_contains(preFormattedElements, tagName);\r
+ for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {\r
+ xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit,\r
+ childStartNewLine, childPreformatted);\r
+ }\r
+ // Add the end tag\r
+ var endTag = lt + "/" + tagName + gt;\r
+ xhtml += childStartNewLine ? newLine + indentation + endTag : endTag;\r
+ }\r
+ return xhtml;\r
+ case nodeTypes.TEXT_NODE:\r
+ if (isWhitespace(rootNode)) {\r
+ xhtml = "";\r
+ } else {\r
+ if (preformatted) {\r
+ xhtml = rootNode.nodeValue;\r
+ } else {\r
+ // Trim whitespace from each line of the text node\r
+ var lines = splitIntoLines(trim(rootNode.nodeValue));\r
+ var trimmedLines = [];\r
+ for (var i = 0, len = lines.length; i < len; i++) {\r
+ trimmedLines[i] = trim(lines[i]);\r
+ }\r
+ xhtml = trimmedLines.join(newLine + indentation);\r
+ }\r
+ if (startNewLine) {\r
+ xhtml = newLine + indentation + xhtml;\r
+ }\r
+ }\r
+ return xhtml;\r
+ case nodeTypes.CDATA_SECTION_NODE:\r
+ return "<![CDA" + "TA[" + rootNode.nodeValue + "]" + "]>" + newLine;\r
+ case nodeTypes.DOCUMENT_NODE:\r
+ xhtml = "";\r
+ // Add output for childNodes collection (which doesn't include attribute nodes)\r
+ for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {\r
+ xhtml += getXhtml(rootNode.childNodes[i], true, indentation);\r
+ }\r
+ return xhtml;\r
+ default:\r
+ return "";\r
+ }\r
+ } else {\r
+ xhtml = "";\r
+ // Add output for childNodes collection (which doesn't include attribute nodes)\r
+ for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {\r
+ xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit);\r
+ }\r
+ return xhtml;\r
+ }\r
+ }\r
+\r
+ function createCommandLineFunctions() {\r
+ ConsoleAppender.addGlobalCommandLineFunction("$", function(appender, args, returnValue) {\r
+ return document.getElementById(args[0]);\r
+ });\r
+\r
+ ConsoleAppender.addGlobalCommandLineFunction("dir", function(appender, args, returnValue) {\r
+ var lines = [];\r
+ for (var i = 0, len = args.length; i < len; i++) {\r
+ lines[i] = dir(args[i]);\r
+ }\r
+ return lines.join(newLine + newLine);\r
+ });\r
+\r
+ ConsoleAppender.addGlobalCommandLineFunction("dirxml", function(appender, args, returnValue) {\r
+ var lines = [];\r
+ for (var i = 0, len = args.length; i < len; i++) {\r
+ var win = appender.getCommandWindow();\r
+ lines[i] = getXhtml(args[i]);\r
+ }\r
+ return lines.join(newLine + newLine);\r
+ });\r
+\r
+ ConsoleAppender.addGlobalCommandLineFunction("cd", function(appender, args, returnValue) {\r
+ var win, message;\r
+ if (args.length === 0 || args[0] === "") {\r
+ win = window;\r
+ message = "Command line set to run in main window";\r
+ } else {\r
+ if (args[0].window == args[0]) {\r
+ win = args[0];\r
+ message = "Command line set to run in frame '" + args[0].name + "'";\r
+ } else {\r
+ win = window.frames[args[0]];\r
+ if (win) {\r
+ message = "Command line set to run in frame '" + args[0] + "'";\r
+ } else {\r
+ returnValue.isError = true;\r
+ message = "Frame '" + args[0] + "' does not exist";\r
+ win = appender.getCommandWindow();\r
+ }\r
+ }\r
+ }\r
+ appender.setCommandWindow(win);\r
+ return message;\r
+ });\r
+\r
+ ConsoleAppender.addGlobalCommandLineFunction("clear", function(appender, args, returnValue) {\r
+ returnValue.appendResult = false;\r
+ appender.clear();\r
+ });\r
+\r
+ ConsoleAppender.addGlobalCommandLineFunction("keys", function(appender, args, returnValue) {\r
+ var keys = [];\r
+ for (var k in args[0]) {\r
+ keys.push(k);\r
+ }\r
+ return keys;\r
+ });\r
+\r
+ ConsoleAppender.addGlobalCommandLineFunction("values", function(appender, args, returnValue) {\r
+ var values = [];\r
+ for (var k in args[0]) {\r
+ try {\r
+ values.push(args[0][k]);\r
+ } catch (ex) {\r
+ logLog.warn("values(): Unable to obtain value for key " + k + ". Details: " + getExceptionMessage(ex));\r
+ }\r
+ }\r
+ return values;\r
+ });\r
+\r
+ ConsoleAppender.addGlobalCommandLineFunction("expansionDepth", function(appender, args, returnValue) {\r
+ var expansionDepth = parseInt(args[0], 10);\r
+ if (isNaN(expansionDepth) || expansionDepth < 0) {\r
+ returnValue.isError = true;\r
+ return "" + args[0] + " is not a valid expansion depth";\r
+ } else {\r
+ appender.setCommandLineObjectExpansionDepth(expansionDepth);\r
+ return "Object expansion depth set to " + expansionDepth;\r
+ }\r
+ });\r
+ }\r
+\r
+ function init() {\r
+ // Add command line functions\r
+ createCommandLineFunctions();\r
+ }\r
+\r
+ /* ------------------------------------------------------------------ */\r
+\r
+ init();\r
+ })();\r
+\r
+ /* ---------------------------------------------------------------------- */\r
+ // Main load\r
+\r
+ log4javascript.setDocumentReady = function() {\r
+ pageLoaded = true;\r
+ log4javascript.dispatchEvent("load", {});\r
+ };\r
+\r
+ if (window.addEventListener) {\r
+ window.addEventListener("load", log4javascript.setDocumentReady, false);\r
+ } else if (window.attachEvent) {\r
+ window.attachEvent("onload", log4javascript.setDocumentReady);\r
+ } else {\r
+ var oldOnload = window.onload;\r
+ if (typeof window.onload != "function") {\r
+ window.onload = log4javascript.setDocumentReady;\r
+ } else {\r
+ window.onload = function(evt) {\r
+ if (oldOnload) {\r
+ oldOnload(evt);\r
+ }\r
+ log4javascript.setDocumentReady();\r
+ };\r
+ }\r
+ }\r
+\r
+ // Ensure that the log4javascript object is available in the window. This\r
+ // is necessary for log4javascript to be available in IE if loaded using\r
+ // Dojo's module system\r
+ window.log4javascript = log4javascript;\r
+\r
+ return log4javascript;\r
+})();
\ No newline at end of file
--- /dev/null
+body {\r
+ font-family: Verdana, Arial, Helvetica, Sans-serif;\r
+ font-size: 75%;\r
+ color: black;\r
+ background-color: #eeeeee;\r
+ text-align: center;\r
+ padding: 0px;\r
+ margin: 0px;\r
+}\r
+\r
+div#container {\r
+ width: 770px;\r
+ text-align: left;\r
+ line-height: 150%;\r
+ border-width: 0px 1px 1px 1px;\r
+ border-color: #cccccc;\r
+ border-style: solid;\r
+ background-color: white;\r
+ color: black;\r
+ padding: 10px;\r
+ margin: 0px auto 10px auto;\r
+}\r
+\r
+div#header {\r
+ margin: 0px;\r
+}\r
+\r
+div#header h1 {\r
+ font-family: Courier New, Courier, Monospace, Serif;\r
+ padding: 8px 0 15px 0;\r
+ margin: 0px;\r
+ font-size: 200%;\r
+ font-weight: bold;\r
+ text-align: right;\r
+}\r
+\r
+div#header h1 a {\r
+ color: black;\r
+}\r
+\r
+div#nav {\r
+ font-size: 91.66%;\r
+ font-weight: bold;\r
+ padding-top: 5px;\r
+ padding-bottom: 5px;\r
+ border-bottom: solid #cccccc 1px;\r
+ text-align: right;\r
+ background-color: #f0f0fa;\r
+}\r
+\r
+div#container.nonav div#content {\r
+ float: none;\r
+ width: auto;\r
+}\r
+\r
+*.externallinkinfo {\r
+ float: right;\r
+ font-style: italic;\r
+}\r
+\r
+div#content h1 {\r
+ padding: 10px 3px 5px 3px;\r
+ margin: 5px 0px;\r
+ font-size: 175%;\r
+ font-weight: normal;\r
+}\r
+\r
+div#content h2 {\r
+ background-color: darkgreen;\r
+ color: white;\r
+ padding: 0px 3px;\r
+ font-size: 116.66%;\r
+ font-weight: bold;\r
+}\r
+\r
+div#content h2 a {\r
+ color: white;\r
+}\r
+\r
+div#content h3 {\r
+ padding: 0px 3px;\r
+ font-size: 116.66%;\r
+ font-weight: bold;\r
+ border-style: solid;\r
+ border-color: #003399;\r
+ border-width: 1px 0px;\r
+}\r
+\r
+div#content h4 {\r
+ padding: 0px 3px;\r
+ font-size: 100%;\r
+ font-weight: bold;\r
+ border-top: solid #eeeeee 1px;\r
+}\r
+\r
+div#content h5 {\r
+ padding: 0px;\r
+ margin: 3px 0px;\r
+}\r
+\r
+div#footer {\r
+ margin-top: 20px;\r
+ padding: 2px;\r
+ border-top: solid #cccccc 1px;\r
+ font-size: 91.66%;\r
+}\r
+\r
+a {\r
+ color: #003399;\r
+ text-decoration: none;\r
+}\r
+\r
+a:hover {\r
+ text-decoration: underline;\r
+}\r
+\r
+a.bold {\r
+ font-weight: bold;\r
+}\r
+\r
+a.underlined {\r
+ text-decoration: underline;\r
+}\r
+\r
+a img {\r
+ border-width: 0px;\r
+}\r
+\r
+br.clear {\r
+ clear: both;\r
+}\r
+\r
+table {\r
+ font-size: 100%;\r
+}\r
+\r
+/* Code */\r
+pre, code {\r
+ font-family: Courier New, Courier;\r
+ font-size: 108.33%;\r
+}\r
+\r
+pre.code, pre.console {\r
+ border: solid 1px #cccccc;\r
+ padding: 3px;\r
+}\r
+\r
+pre.code {\r
+ background-color: #eeeeee;\r
+}\r
+\r
+*.trace {\r
+ color: #666666;\r
+}\r
+\r
+*.debug {\r
+ color: green;\r
+}\r
+\r
+*.info {\r
+ color: #000099;\r
+}\r
+\r
+*.warn {\r
+ color: #999900;\r
+}\r
+\r
+*.error {\r
+ color: red;\r
+}\r
+\r
+*.fatal {\r
+ color: #660066;\r
+}\r
+\r
+\r
+div.example, div.panel {\r
+ border: solid 1px #cccccc;\r
+ background-color: #f5f5f5;\r
+ padding: 3px;\r
+ margin-bottom: 10px;\r
+}\r
+\r
+div.panel h2 {\r
+ margin: 5px 0px;\r
+}\r
+\r
+div.padded {\r
+ padding: 10px;\r
+}\r
+\r
+div.hidden {\r
+ display: none;\r
+}\r
+\r
+div.active {\r
+ background-color: #fcfffc;\r
+ border-color: green;\r
+}\r
+\r
+label.rightofinput, input.rightoflabel {\r
+ margin-right: 20px;\r
+}\r
+\r
+/* 'Back to top' link */\r
+p.linktotop {\r
+ text-align: right;\r
+}\r
+\r
+ul.propertieslist li.method, ul.propertieslist li.property {\r
+ margin: 0;\r
+ padding: 0px 0px 15px 0px;\r
+}\r
+\r
+ul.propertieslist li *.name {\r
+ font-size: 116.66%;\r
+ font-weight: bold;\r
+}\r
+\r
+ul.propertieslist li.method div.methodsignature {\r
+ margin: 10px 0px;\r
+ font-size: 116.66%;\r
+ background-color: #eeeeee;\r
+}\r
+\r
+ul.propertieslist li.method *.paramsheading {\r
+ font-weight: bold;\r
+}\r
+\r
+ul.propertieslist li.method *.params {\r
+ padding-top: 5px;\r
+ padding-bottom: 5px;\r
+}\r
+\r
+ul.propertieslist li.method *.params li.param {\r
+ padding-bottom: 10px;\r
+}\r
+\r
+ul.propertieslist li.method *.params li.param *.paramname {\r
+ font-style: italic;\r
+}\r
+\r
+div.serverlog {\r
+ height: 200px;\r
+ /*border: solid 1px #cccccc;*/\r
+}\r
+\r
+div#inPageConsole {\r
+ margin-top: 10px;\r
+}\r
+\r
+div.iframecontainer {\r
+ background-color: white;\r
+ border: solid #cccccc 1px;\r
+ width: 100%;\r
+}\r
+\r
+div.veryprominent {\r
+ background-color: darkgreen;\r
+ color: white;\r
+ font-weight: bold;\r
+ padding: 10px;\r
+ font-size: 133.33%;\r
+ margin-bottom: 10px;\r
+}\r
+\r
+div.veryprominent a {\r
+ color: white;\r
+}\r
+\r
+*.largetext {\r
+ font-size: 116.66%;\r
+}\r
+\r
+div#leftcolumn {\r
+ float: left;\r
+ width: 160px;\r
+}\r
+\r
+div#rightcolumn {\r
+ float: right;\r
+ width: 580px;\r
+}\r
+\r
+td.fullsupport {\r
+ background-color: lightgreen;\r
+}\r
+\r
+td.partialsupport {\r
+ background-color: gold;\r
+}\r
+\r
+td.nosupport {\r
+ background-color: lightcoral;\r
+}\r
+\r
+p.editions {\r
+ text-align: right;\r
+ font-style: italic;\r
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript - Tests</title>\r
+ </head>\r
+ <body>\r
+ <ul>\r
+ <li><a href="log4javascript.html">Standard edition tests</a></li>\r
+ <li><a href="log4javascript_uncompressed.html">Standard edition uncompressed tests</a></li>\r
+ <li><a href="log4javascript_production.html">Production edition tests</a></li>\r
+ <li><a href="log4javascript_production_uncompressed.html">Production edition uncompressed tests</a></li>\r
+ </ul>\r
+ </body>\r
+</html>\r
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript - log4javascript - Tests</title>\r
+ <script type="text/javascript" src="../js/log4javascript.js"></script>\r
+ <script type="text/javascript" src="../js/stubs/log4javascript.js"></script>\r
+ <script type="text/javascript" src="xntest.js"></script>\r
+ <script type="text/javascript" src="../js/tests/log4javascript.js"></script>\r
+ <link rel="stylesheet" type="text/css" href="tests.css"/>\r
+ </head>\r
+ <body>\r
+ <div id="messages"></div>\r
+ <div id="inlineAppenderContainer"></div>\r
+ </body>\r
+</html>\r
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript - log4javascript_lite - Tests</title>\r
+ <script type="text/javascript" src="../js/log4javascript_lite.js"></script>\r
+ <script type="text/javascript" src="../js/stubs/log4javascript_lite.js"></script>\r
+ <script type="text/javascript" src="xntest.js"></script>\r
+ <script type="text/javascript" src="../js/tests/log4javascript_lite.js"></script>\r
+ <link rel="stylesheet" type="text/css" href="tests.css"/>\r
+ </head>\r
+ <body>\r
+ <div id="messages"></div>\r
+ <div id="inlineAppenderContainer"></div>\r
+ </body>\r
+</html>\r
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript - log4javascript_lite_uncompressed - Tests</title>\r
+ <script type="text/javascript" src="../js/log4javascript_lite_uncompressed.js"></script>\r
+ <script type="text/javascript" src="../js/stubs/log4javascript_lite_uncompressed.js"></script>\r
+ <script type="text/javascript" src="xntest.js"></script>\r
+ <script type="text/javascript" src="../js/tests/log4javascript_lite_uncompressed.js"></script>\r
+ <link rel="stylesheet" type="text/css" href="tests.css"/>\r
+ </head>\r
+ <body>\r
+ <div id="messages"></div>\r
+ <div id="inlineAppenderContainer"></div>\r
+ </body>\r
+</html>\r
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript - log4javascript_production - Tests</title>\r
+ <script type="text/javascript" src="../js/log4javascript_production.js"></script>\r
+ <script type="text/javascript" src="../js/stubs/log4javascript_production.js"></script>\r
+ <script type="text/javascript" src="xntest.js"></script>\r
+ <script type="text/javascript" src="../js/tests/log4javascript_production.js"></script>\r
+ <link rel="stylesheet" type="text/css" href="tests.css"/>\r
+ </head>\r
+ <body>\r
+ <div id="messages"></div>\r
+ <div id="inlineAppenderContainer"></div>\r
+ </body>\r
+</html>\r
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript - log4javascript_production_uncompressed - Tests</title>\r
+ <script type="text/javascript" src="../js/log4javascript_production_uncompressed.js"></script>\r
+ <script type="text/javascript" src="../js/stubs/log4javascript_production_uncompressed.js"></script>\r
+ <script type="text/javascript" src="xntest.js"></script>\r
+ <script type="text/javascript" src="../js/tests/log4javascript_production_uncompressed.js"></script>\r
+ <link rel="stylesheet" type="text/css" href="tests.css"/>\r
+ </head>\r
+ <body>\r
+ <div id="messages"></div>\r
+ <div id="inlineAppenderContainer"></div>\r
+ </body>\r
+</html>\r
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript - log4javascript_uncompressed - Tests</title>\r
+ <script type="text/javascript" src="../js/log4javascript_uncompressed.js"></script>\r
+ <script type="text/javascript" src="../js/stubs/log4javascript_uncompressed.js"></script>\r
+ <script type="text/javascript" src="xntest.js"></script>\r
+ <script type="text/javascript" src="../js/tests/log4javascript_uncompressed.js"></script>\r
+ <link rel="stylesheet" type="text/css" href="tests.css"/>\r
+ </head>\r
+ <body>\r
+ <div id="messages"></div>\r
+ <div id="inlineAppenderContainer"></div>\r
+ </body>\r
+</html>\r
--- /dev/null
+<?xml version="1.0"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">\r
+ <head>\r
+ <title>log4javascript - %%build:edition%% - Tests</title>\r
+ <script type="text/javascript" src="../js/%%build:edition%%.js"></script>\r
+ <script type="text/javascript" src="../js/stubs/%%build:edition%%.js"></script>\r
+ <script type="text/javascript" src="xntest.js"></script>\r
+ <script type="text/javascript" src="../js/tests/%%build:edition%%.js"></script>\r
+ <link rel="stylesheet" type="text/css" href="tests.css"/>\r
+ </head>\r
+ <body>\r
+ <div id="messages"></div>\r
+ <div id="inlineAppenderContainer"></div>\r
+ </body>\r
+</html>\r
--- /dev/null
+body {\r
+ font-family: verdana, arial, helvetica, sans-serif;\r
+ font-size: 81.25%;\r
+}\r
+\r
+h2 {\r
+ font-size: 100%;\r
+ padding: 0;\r
+ margin: 0.1em 0 0.1em 0;\r
+}\r
+\r
+div.xn_test_suite_container {\r
+ border: solid #cccccc 1px;\r
+ padding: 2px 5px;\r
+ margin: 2px 0px;\r
+}\r
+\r
+div.xn_test_progressbar_container {\r
+ border: solid black 1px;\r
+}\r
+\r
+div.xn_test_progressbar_container *.success {\r
+ background-color: #00ff00;\r
+}\r
+\r
+div.xn_test_progressbar_container *.failure {\r
+ background-color: red;\r
+}\r
+\r
+div.xn_test_overallprogressbar_container {\r
+ position: relative;\r
+}\r
+\r
+div.xn_test_overallprogressbar_container h1 {\r
+ margin: 0;\r
+ padding: 2px;\r
+ font-size: 125%;\r
+ font-weight: bold;\r
+ white-space: nowrap;\r
+}\r
+\r
+dl *.success {\r
+ color: green;\r
+}\r
+\r
+dl *.failure {\r
+ color: red;\r
+}\r
+\r
+span.xn_test_expander {\r
+ padding: 0;\r
+ border: solid black 1px;\r
+ cursor: pointer;\r
+ cursor: hand;\r
+ line-height: 100%; \r
+ font-weight: bold;\r
+ margin-right: 1em;\r
+ font-size: 11px;\r
+}\r
+\r
+dl.xn_test_expanded {\r
+ display: block;\r
+}\r
+\r
+dl.xn_test_collapsed {\r
+ display: none;\r
+}\r
+\r
+div.xn_test_suite_success {\r
+ border: solid 2px limegreen;\r
+}\r
+\r
+div.xn_test_suite_failure {\r
+ border: solid 2px red;\r
+}\r
+\r
+pre.xn_test_log_report {\r
+ background-color: #f5f5f5;\r
+ padding: 3px;\r
+ border: solid gray 1px;\r
+ font-size: 11px;\r
+ font-family: Courier New, Courier, monospace;\r
+}\r
+\r
+code.xn_test_stacktrace {\r
+ color: red;\r
+ overflow: \r
+}
\ No newline at end of file
--- /dev/null
+// 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 = " ";
+ 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
.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;
+}
{% 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 %}