Merge branch 'master' of ssh://git.planet-lab.org/git/plstackapi
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..be5701d
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,36 @@
+NAME = opencloud
+SPECFILE = $(NAME).spec
+VERSION = $(shell rpm -q --specfile $(SPECFILE) --qf '%{VERSION}\n' | head -n 1)
+RELEASE = $(shell rpm -q --specfile $(SPECFILE) --qf '%{RELEASE}\n' | head -n 1)
+
+PWD = $(shell pwd)
+
+dist rpm: $(NAME)-$(VERSION)-$(RELEASE).rpm
+
+$(NAME)-$(VERSION).tar.gz:
+	mkdir -p $(NAME)-$(VERSION)
+	rsync -av --exclude=.svn --exclude=.git --exclude=*.tar.gz --exclude=$(NAME)-$(VERSION)/ ./ $(NAME)-$(VERSION)
+	tar -czf $@ $(NAME)-$(VERSION)
+	rm -fr $(NAME)-$(VERSION)
+
+$(NAME)-$(VERSION)-$(RELEASE).rpm: $(NAME)-$(VERSION).tar.gz
+	mkdir -p build
+	rpmbuild -bb --define '_sourcedir $(PWD)' \
+                --define '_builddir $(PWD)/build' \
+                --define '_srcrpmdir $(PWD)' \
+                --define '_rpmdir $(PWD)' \
+                --define '_build_name_fmt %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm' \
+                $(SPECFILE)
+
+srpm: $(NAME)-$(VERSION)-$(RELEASE).src.rpm
+$(NAME)-$(VERSION)-$(RELEASE).src.rpm: $(NAME)-$(VERSION).tar.gz
+	rpmbuild -bs --define "_sourcedir $$(pwd)" \
+                --define "_srcrpmdir $$(pwd)" \
+                $(SPECFILE)
+
+clean:
+	rm -f $(NAME)-$(VERSION).tar.gz $(NAME)-$(VERSION)-$(RELEASE).src.rpm $(NAME)-$(VERSION)-$(RELEASE).noarch.rpm
+	rm -rf build
+
+.PHONY: dist
+
diff --git a/opencloud.spec b/opencloud.spec
new file mode 100644
index 0000000..dab5f11
--- /dev/null
+++ b/opencloud.spec
@@ -0,0 +1,73 @@
+Summary: OpenCloud core services
+Name: opencloud
+Version: 1.0
+Release: 1
+License: GPL+
+Group: Development/Tools
+Source0: %{_tmppath}/%{name}-%{version}.tar.gz
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}
+requires: postgresql
+requires: postgresql-server
+requires: python-psycopg2
+requires: graphviz
+requires: graphviz-devel
+requires: graphviz-python
+requires: libxslt-devel
+requires: python-pip
+requires: tar
+requires: gcc
+
+%description
+%{summary}
+
+%prep
+%setup -q
+
+%build
+# Empty section.
+
+%pre
+pip-python install django==1.5
+pip-python install djangorestframework
+pip-python install markdown  # Markdown support for the browseable API.
+pip-python install pyyaml    # YAML content-type support.
+pip-python install django-filter  # Filtering support
+pip-python install lxml  # XML manipulation library
+pip-python install netaddr # IP Addr library
+pip-python install pytz
+pip-python install django-timezones
+pip-python install requests
+pip-python install django-crispy-forms
+pip-python install django-geoposition
+pip-python install django-extensions
+pip-python install django-suit
+pip-python install django-evolution
+
+easy_install django_evolution
+
+%install
+rm -rf %{buildroot}
+mkdir -p  %{buildroot}
+install -d %{buildroot}/opt/planetstack
+
+# in builddir
+cp -rp /opt/plstackapi/planetstack %{buildroot}/opt/.
+
+find %{buildroot}/opt/planetstack -type f -print | sed "s@^$RPM_BUILD_ROOT@@g"  > %{_tmppath}/tmp-filelist
+
+%clean
+rm -rf %{buildroot}
+
+%files -f %{_tmppath}/tmp-filelist
+%defattr(-,root,root,-)
+
+%post
+/opt/planetstack/scripts/opencloud initdb
+
+%preun
+rm -rf /opt/planetstack
+
+%changelog
+* Sat Feb 22 2014  Siobhan Tully  1.0.0
+- First Build
+
diff --git a/planetstack/core/admin.py b/planetstack/core/admin.py
index 853e5ce..996e22d 100644
--- a/planetstack/core/admin.py
+++ b/planetstack/core/admin.py
@@ -345,6 +345,32 @@
     def queryset(self, request):
         return SitePrivilege.select_by_user(request.user)
 
+class SiteDeploymentROInline(ReadOnlyTabularInline):
+    model = SiteDeployments
+    #model = Site.deployments.through
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-sitedeployments'
+    fields = ['deployment','site']
+
+class SiteDeploymentInline(PlStackTabularInline):
+    model = SiteDeployments
+    #model = Site.deployments.through
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-deployments'
+    fields = ['deployment','site']
+
+    def formfield_for_foreignkey(self, db_field, request, **kwargs):
+        if db_field.name == 'site':
+            kwargs['queryset'] = Site.select_by_user(request.user)
+
+        if db_field.name == 'deployment':
+            kwargs['queryset'] = Deployment.select_by_user(request.user)
+        return super(SiteDeploymentInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
+
+    def queryset(self, request):
+        return SiteDeployments.select_by_user(request.user)
+
+
 class SlicePrivilegeROInline(ReadOnlyTabularInline):
     model = SlicePrivilege
     extra = 0
@@ -492,7 +518,7 @@
     fieldList = ['name', 'site_url', 'enabled', 'is_public', 'login_base', 'accountLink','location']
     fieldsets = [
         (None, {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),
-        ('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
+        #('Deployment Networks', {'fields': ['deployments'], 'classes':['suit-tab suit-tab-deployments']}),
     ]
     suit_form_tabs =(('general', 'Site Details'),
         ('users','Users'),
@@ -505,11 +531,11 @@
     readonly_fields = ['accountLink']
 
     user_readonly_fields = ['name', 'deployments','site_url', 'enabled', 'is_public', 'login_base', 'accountLink']
-    user_readonly_inlines = [SliceROInline,UserROInline,TagROInline, NodeROInline, SitePrivilegeROInline]
+    user_readonly_inlines = [SliceROInline,UserROInline,TagROInline, NodeROInline, SitePrivilegeROInline,SiteDeploymentROInline]
 
     list_display = ('name', 'login_base','site_url', 'enabled')
     filter_horizontal = ('deployments',)
-    inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline]
+    inlines = [SliceInline,UserInline,TagInline, NodeInline, SitePrivilegeInline, SiteDeploymentInline]
     search_fields = ['name']
 
     def queryset(self, request):
diff --git a/planetstack/core/fixtures/initial_data.json b/planetstack/core/fixtures/initial_data.json
index 6650547..469bc31 100644
--- a/planetstack/core/fixtures/initial_data.json
+++ b/planetstack/core/fixtures/initial_data.json
@@ -495,8 +495,7 @@
         "timezone": "America/New_York", 
         "is_admin": true, 
         "password": "pbkdf2_sha256$10000$v5qKhIyhSQ2N$V8vh2mkqYdjQib6d2jBkpwV57eMBfhd/9eiXqaDLUWg=", 
-        "email": "padmin@vicci.org", 
-        "enacted": null
+        "email": "padmin@vicci.org"
     }
 },
 {
@@ -520,8 +519,7 @@
         "timezone": "America/New_York", 
         "is_admin": true, 
         "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
-        "email": "tony@onlab.us", 
-        "enacted": null
+        "email": "tony@onlab.us"
     }
 },
 {
@@ -545,8 +543,7 @@
         "timezone": "America/New_York", 
         "is_admin": true, 
         "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
-        "email": "mike@onlab.us", 
-        "enacted": null
+        "email": "mike@onlab.us"
     }
 },
 {
@@ -570,8 +567,7 @@
         "timezone": "America/New_York", 
         "is_admin": true, 
         "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
-        "email": "andy@onlab.us", 
-        "enacted": null
+        "email": "andy@onlab.us"
     }
 },
 {
@@ -595,8 +591,7 @@
         "timezone": "America/New_York", 
         "is_admin": true, 
         "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
-        "email": "sapan@onlab.us", 
-        "enacted": null
+        "email": "sapan@onlab.us" 
     }
 },
 {
@@ -620,8 +615,7 @@
         "timezone": "America/New_York", 
         "is_admin": true, 
         "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
-        "email": "jcnelson@cs.princeton.edu", 
-        "enacted": null
+        "email": "jcnelson@cs.princeton.edu"
     }
 },
 {
@@ -645,8 +639,7 @@
         "timezone": "America/New_York", 
         "is_admin": true, 
         "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
-        "email": "llp@onlab.us", 
-        "enacted": null
+        "email": "llp@onlab.us"
     }
 },
 {
@@ -670,8 +663,7 @@
         "timezone": "America/New_York", 
         "is_admin": true, 
         "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
-        "email": "scott@onlab.us", 
-        "enacted": null
+        "email": "scott@onlab.us"
     }
 },
 {
@@ -695,8 +687,7 @@
         "timezone": "America/New_York", 
         "is_admin": true, 
         "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
-        "email": "ali@onlab.us", 
-        "enacted": null
+        "email": "ali@onlab.us"
     }
 },
 {
@@ -720,8 +711,7 @@
         "timezone": "America/New_York", 
         "is_admin": true, 
         "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
-        "email": "bill@onlab.us", 
-        "enacted": null
+        "email": "bill@onlab.us"
     }
 },
 {
@@ -745,8 +735,7 @@
         "timezone": "America/New_York", 
         "is_admin": true, 
         "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
-        "email": "guru@onlab.us", 
-        "enacted": null
+        "email": "guru@onlab.us"
     }
 },
 {
@@ -770,8 +759,7 @@
         "timezone": "America/New_York", 
         "is_admin": true, 
         "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
-        "email": "marc@onlab.us", 
-        "enacted": null
+        "email": "marc@onlab.us"
     }
 },
 {
@@ -795,8 +783,7 @@
         "timezone": "America/New_York", 
         "is_admin": true, 
         "password": "pbkdf2_sha256$10000$dLKRXWJlkuvm$Ycamy79oT1lN0Q5R3B3nvlr70n2X50mL86yraDwzuWk=", 
-        "email": "siobhan@onlab.us", 
-        "enacted": null
+        "email": "siobhan@onlab.us"
     }
 },
 {
@@ -820,8 +807,7 @@
         "timezone": "America/New_York", 
         "is_admin": true, 
         "password": "pbkdf2_sha256$10000$jaLSTW2ksHEN$HDpjDKieFDjMvtV5wbF/ow3zfq8EqcFtNXLfuo+150s=", 
-        "email": "demo@onlab.us", 
-        "enacted": null
+        "email": "demo@onlab.us"
     }
 },
 {
@@ -845,8 +831,7 @@
         "timezone": "America/New_York", 
         "is_admin": true, 
         "password": "!", 
-        "email": "jhh@cs.arizona.edu", 
-        "enacted": null
+        "email": "jhh@cs.arizona.edu"
     }
 },
 {
diff --git a/planetstack/core/models/__init__.py b/planetstack/core/models/__init__.py
index 6926d90..7c10fc8 100644
--- a/planetstack/core/models/__init__.py
+++ b/planetstack/core/models/__init__.py
@@ -8,10 +8,10 @@
 from .role import Role
 #from .deployment import Deployment
 from .site import Site,Deployment, DeploymentRole, DeploymentPrivilege, SiteDeployments
-from .user import User
+from .user import User, UserDeployments
 from .serviceclass import ServiceClass
-from .slice import Slice
-from .site import SitePrivilege
+from .slice import Slice, SliceDeployments
+from .site import SitePrivilege, SiteDeployments
 from .image import Image
 from .node import Node
 from .serviceresource import ServiceResource
diff --git a/planetstack/core/models/site.py b/planetstack/core/models/site.py
index edd9373..4256e75 100644
--- a/planetstack/core/models/site.py
+++ b/planetstack/core/models/site.py
@@ -21,8 +21,8 @@
     is_public = models.BooleanField(default=True, help_text="Indicates the visibility of this site to other members")
     abbreviated_name = models.CharField(max_length=80)
 
-    deployments = models.ManyToManyField('Deployment', blank=True, related_name='sites')
-    #deployments = models.ManyToManyField('Deployment', through='SiteDeployments', blank=True)
+    #deployments = models.ManyToManyField('Deployment', blank=True, related_name='sites')
+    deployments = models.ManyToManyField('Deployment', through='SiteDeployments', blank=True)
     tags = generic.GenericRelation(Tag)
 
     def __unicode__(self):  return u'%s' % (self.name)
@@ -88,6 +88,9 @@
 
     def __unicode__(self):  return u'%s' % (self.name)
 
+    @staticmethod
+    def select_by_user(user):
+        return Deployment.objects.all()
 
 class DeploymentRole(PlCoreBase):
 
@@ -127,6 +130,11 @@
 class SiteDeployments(PlCoreBase):
     site = models.ForeignKey(Site)
     deployment = models.ForeignKey(Deployment)
+    tenant_id = models.CharField(null=True, blank=True, max_length=200, help_text="Keystone tenant id")    
+
+    @staticmethod
+    def select_by_user(user):
+        return SiteDeployments.objects.all()
 
     #class Meta:
     #    db_table = 'core_site_deployments'
diff --git a/planetstack/core/models/slice.py b/planetstack/core/models/slice.py
index c39d09b..15d317f 100644
--- a/planetstack/core/models/slice.py
+++ b/planetstack/core/models/slice.py
@@ -9,6 +9,7 @@
 from core.models import Tag
 from django.contrib.contenttypes import generic
 from core.models import Service
+from core.models import Deployment
 
 # Create your models here.
 
@@ -87,3 +88,22 @@
             sp_ids = [sp.id for sp in SlicePrivilege.objects.filter(user=user)]
             qs = SlicePrivilege.objects.filter(id__in=sp_ids)
         return qs
+
+class SliceDeployments(PlCoreBase):
+    slice = models.ForeignKey(Slice)
+    deployment = models.ForeignKey(Deployment)
+    tenant_id = models.CharField(max_length=200, help_text="Keystone tenant id")
+    network_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum network")
+    router_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum router id")
+    subnet_id = models.CharField(null=True, blank=True, max_length=256, help_text="Quantum subnet id")
+
+    def __unicode__(self):  return u'%s %s %s' % (self.slice, self.deployment)
+
+    @staticmethod
+    def select_by_user(user):
+        if user.is_admin:
+            qs = SliceDeployments.objects.all()
+        else:
+            slices = Slice.select_by_user(user)
+            qs = SliceDeployments.objects.filter(slice__in=slices)
+        return qs    
diff --git a/planetstack/core/models/sliver.py b/planetstack/core/models/sliver.py
index 29ae0d4..ce46cac 100644
--- a/planetstack/core/models/sliver.py
+++ b/planetstack/core/models/sliver.py
@@ -52,6 +52,6 @@
         if user.is_admin:
             qs = Sliver.objects.all()
         else:
-            slice_ids = [s.id for s in Slice.select_by_user(user)]
-            qs = Sliver.objects.filter(id__in=slice_ids)
+            slices = Slice.select_by_user(user)
+            qs = Sliver.objects.filter(slice__in=slices)
         return qs
diff --git a/planetstack/core/models/user.py b/planetstack/core/models/user.py
index 1afb5fc..9d0c2ec 100644
--- a/planetstack/core/models/user.py
+++ b/planetstack/core/models/user.py
@@ -4,6 +4,7 @@
 from django.db import models
 from django.db.models import F, Q
 from core.models import PlCoreBase,Site
+from core.models.deployment import Deployment
 from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
 from timezones.fields import TimeZoneField
 
@@ -149,4 +150,19 @@
         return qs            
 
              
-     
+    
+class UserDeployments(PlCoreBase):
+    user = models.ForeignKey(User)
+    deployment = models.ForeignKey(Deployment)
+    kuser_id = models.CharField(null=True, blank=True, max_length=200, help_text="Keystone user id")
+
+    def __unicode__(self):  return u'%s %s' % (self.user, self.deployment.name)
+
+    @staticmethod
+    def select_by_user(user):
+        if user.is_admin:
+            qs = UserDeployments.objects.all()
+        else:
+            users = Users.select_by_user(user)
+            qs = Usereployments.objects.filter(user__in=slices)
+        return qs 
diff --git a/planetstack/core/plus/sites.py b/planetstack/core/plus/sites.py
index da86a10..27ae352 100644
--- a/planetstack/core/plus/sites.py
+++ b/planetstack/core/plus/sites.py
@@ -12,13 +12,15 @@
     def get_urls(self):
         """Add our dashboard view to the admin urlconf. Deleted the default index."""
         from django.conf.urls import patterns, url
-        from views import DashboardWelcomeView
+        from views import DashboardWelcomeView, DashboardAjaxView
 
         urls = super(AdminMixin, self).get_urls()
         del urls[0]
         custom_url = patterns('',
                url(r'^$', self.admin_view(DashboardWelcomeView.as_view()), 
-                    name="index")
+                    name="index"),
+               url(r'^hpcdashboard/', self.admin_view(DashboardAjaxView.as_view()), 
+                    name="hpcdashboard")
         )
 
         return custom_url + urls
diff --git a/planetstack/core/plus/views.py b/planetstack/core/plus/views.py
index 386f6b5..653ee95 100644
--- a/planetstack/core/plus/views.py
+++ b/planetstack/core/plus/views.py
@@ -1,34 +1,196 @@
 #views.py
-from django.views.generic import TemplateView
+from django.views.generic import TemplateView, View
+import datetime
 
+import json 
 from core.models import Slice,SliceRole,SlicePrivilege,Site,Reservation
+from django.http import HttpResponse
+
 
 class DashboardWelcomeView(TemplateView):
     template_name = 'admin/dashboard/welcome.html'
 
     def get(self, request, *args, **kwargs):
         context = self.get_context_data(**kwargs)
-        sliceList = Slice.objects.all()
         try:
             site = Site.objects.filter(id=request.user.site.id)
         except:
             site = Site.objects.filter(name="Princeton")
         context['site'] = site[0]
 
-        slicePrivs = SlicePrivilege.objects.filter(user=request.user)
-        userSliceInfo = []
-        for entry in slicePrivs:
-
-            try:
-                reservationList = Reservation.objects.filter(slice=entry.slice)
-                reservations = (True,reservationList)
-
-            except:
-                reservations = None
-
-            userSliceInfo.append({'slice': Slice.objects.get(id=entry.slice.id),
-                               'role': SliceRole.objects.get(id=entry.role.id).role,
-                               'reservations': reservations})
-
-        context['userSliceInfo'] = userSliceInfo
+        context['userSliceInfo'] = getSliceInfo(request, context)
+        context['cdnData'] = getCDNOperatorData();
         return self.render_to_response(context=context)
+
+def getSliceInfo(request, context):
+    sliceList = Slice.objects.all()
+    slicePrivs = SlicePrivilege.objects.filter(user=request.user)
+    userSliceInfo = []
+    for entry in slicePrivs:
+
+        try:
+            reservationList = Reservation.objects.filter(slice=entry.slice)
+            reservations = (True,reservationList)
+
+        except:
+            reservations = None
+
+        userSliceInfo.append({'slice': Slice.objects.get(id=entry.slice.id),
+                           'role': SliceRole.objects.get(id=entry.role.id).role,
+                           'reservations': reservations})
+    return userSliceInfo
+
+
+def getCDNOperatorData(randomizeData = False):
+    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/"
+        },
+    }
+
+    if randomizeData:
+        cdnData["Siobhan"] = { "lat": 43.34203, "long": -70.56351, "health": 10, "numNodes": 5, "numHPCSlivers": 3, "siteUrl": "https:devonrexes"}
+        del cdnData["Princeton"]
+        cdnData["I2 Seattle"]['siteUrl'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+        cdnData["I2 Salt Lake City"]["numHPCSlivers"] = 34
+
+
+    return cdnData
+
+class DashboardAjaxView(View):
+    def get(self, request, **kwargs):
+        return HttpResponse(json.dumps(getCDNOperatorData(True)), mimetype='application/javascript')
+        
diff --git a/planetstack/core/static/js/Leaflet.MakiMarkers.js b/planetstack/core/static/js/Leaflet.MakiMarkers.js
new file mode 100644
index 0000000..910bb31
--- /dev/null
+++ b/planetstack/core/static/js/Leaflet.MakiMarkers.js
@@ -0,0 +1,101 @@
+/*
+ * Leaflet plugin to create map icons using Maki Icons from MapBox.
+ *
+ * References:
+ *   Maki Icons: https://www.mapbox.com/maki/
+ *   MapBox Marker API: https://www.mapbox.com/developers/api/#Stand-alone.markers
+ *
+ * Usage:
+ *   var icon = L.MakiMarkers.icon({icon: "rocket", color: "#b0b", size: "m"});
+ *
+ * License:
+ *   MIT: http://jseppi.mit-license.org/
+ */
+(function () {
+  "use strict";
+  L.MakiMarkers = {
+    // Available Maki Icons
+    icons: ["circle-stroked", "circle", "square-stroked", "square",
+      "triangle-stroked", "triangle", "star-stroked", "star", "cross",
+      "marker-stroked", "marker", "religious-jewish", "religious-christian",
+      "religious-muslim", "cemetery", "rocket", "airport", "heliport", "rail",
+      "rail-metro", "rail-light", "bus", "fuel", "parking", "parking-garage",
+      "airfield", "roadblock", "ferry", "harbor", "bicycle", "park", "park2",
+      "museum", "lodging", "monument", "zoo", "garden", "campsite", "theatre",
+      "art-gallery", "pitch", "soccer", "america-football", "tennis", "basketball",
+      "baseball", "golf", "swimming", "cricket", "skiing", "school", "college",
+      "library", "post", "fire-station", "town-hall", "police", "prison",
+      "embassy", "beer", "restaurant", "cafe", "shop", "fast-food", "bar", "bank",
+      "grocery", "cinema", "pharmacy", "hospital", "danger", "industrial",
+      "warehouse", "commercial", "building", "place-of-worship", "alcohol-shop",
+      "logging", "oil-well", "slaughterhouse", "dam", "water", "wetland",
+      "disability", "telephone", "emergency-telephone", "toilets", "waste-basket",
+      "music", "land-use", "city", "town", "village", "farm", "bakery", "dog-park",
+      "lighthouse", "clothing-store", "polling-place", "playground", "entrance",
+      "heart", "london-underground", "minefield", "rail-underground", "rail-above",
+      "camera", "laundry", "car", "suitcase", "hairdresser", "chemist"],
+    defaultColor: "#0a0",
+    defaultIcon: "circle-stroked",
+    defaultSize: "m",
+    apiUrl: "https://api.tiles.mapbox.com/v3/marker/",
+    smallOptions: {
+      iconSize: [20, 50],
+      popupAnchor: [0,-20]
+    },
+    mediumOptions: {
+      iconSize: [30,70],
+      popupAnchor: [0,-30]
+    },
+    largeOptions: {
+      iconSize: [36,90],
+      popupAnchor: [0,-40]
+    }
+  };
+
+  L.MakiMarkers.Icon = L.Icon.extend({
+    options: {
+      //Maki icon: any from https://www.mapbox.com/maki/ (ref: L.MakiMarkers.icons)
+      icon: L.MakiMarkers.defaultIcon,
+      //Marker color: short or long form hex color code
+      color: L.MakiMarkers.defaultColor,
+      //Marker size: "s" (small), "m" (medium), or "l" (large)
+      size: L.MakiMarkers.defaultSize,
+      shadowAnchor: null,
+      shadowSize: null,
+      shadowUrl: null,
+      className: 'maki-marker'
+    },
+
+    initialize: function(options) {
+      var pin;
+
+      options = L.setOptions(this, options);
+
+      switch (options.size) {
+        case "s":
+          L.extend(options, L.MakiMarkers.smallOptions);
+          break;
+        case "l":
+          L.extend(options, L.MakiMarkers.largeOptions);
+          break;
+        default:
+          options.size = "m";
+          L.extend(options, L.MakiMarkers.mediumOptions);
+          break;
+      }
+
+      if (options.color.charAt(0) === '#') {
+        options.color = options.color.substr(1);
+      }
+
+      pin = "pin-" + options.size + "-" + options.icon + "+" +
+        options.color + ".png";
+
+      options.iconUrl = "" + L.MakiMarkers.apiUrl + pin;
+    }
+  });
+
+  L.MakiMarkers.icon = function(options) {
+    return new L.MakiMarkers.Icon(options);
+  };
+})();
diff --git a/planetstack/core/static/log4javascript-1.4.6/changelog.txt b/planetstack/core/static/log4javascript-1.4.6/changelog.txt
new file mode 100644
index 0000000..fe10b97
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/changelog.txt
@@ -0,0 +1,379 @@
+log4javascript change log

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

+

+1.4.6 (19/3/2013)

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

+

+1.4.5 (20/2/2013)

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

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

+

+- Exposed sendAllRemaining() method of AjaxAppender

+

+1.4.4 (8/2/2013)

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

+

+- Improved uniqueness of PopUpAppender window name

+

+1.4.3 (18/9/2012)

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

+

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

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

+  disabled by default.

+

+- Removed leaked global variable "initialized" 

+

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

+  Tracker

+

+

+1.4.2 (13/10/2011)

+- Fixed JsonLayout trailing comma issue. See

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

+  blob-from-log4javascript-logging

+

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

+

+

+1.4.1 (23/3/2009)

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

+

+- Added isVisible() method to PopUpAppender

+

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

+  InPageAppender

+

+- Included unit tests in the distribution

+

+

+1.4 (30/10/2008)

+

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

+

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

+  expandable groups to InPageAppender and PopUpAppender

+

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

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

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

+

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

+  formatted either as one combined message or multiple messages

+

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

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

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

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

+

+- Added useDocumentWrite parameter to constructors and isUseDocumentWrite()

+  and setUseDocumentWrite() methods for InPageAppender and PopUpAppender and

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

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

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

+  which is impossible with the document.write method

+

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

+  XmlLayout and HttpPostDataLayout to include milliseconds by default

+

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

+

+- Setting configuration properties in appenders via constructor paramaters has

+  been phased out.

+

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

+  Doesn't work in Opera

+

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

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

+  "app", all of whose appenders it inherits

+

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

+

+- Bugfix for inaccessible error details

+

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

+

+- Multiple messages may now be specified in logger methods

+

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

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

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

+

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

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

+  the appender via setShowCommandLine() and setCommandLineObjectExpansionDepth()

+  methods respectively

+

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

+

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

+  keys, values, expansionDepth

+

+- Fixes for several bugs in object expansion

+

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

+

+- Fix to allow searchable HTML in log entries

+

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

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

+

+- Searches in PopUpAppender and InPageAppender now preserve formatting

+

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

+  used by PopUpAppender and InPageAppender

+

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

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

+

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

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

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

+

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

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

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

+

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

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

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

+

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

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

+  the top left

+

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

+  constructor

+

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

+  copies of each log entry

+

+

+1.3.1 (20/11/2006)

+

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

+  PopUpAppender and InPageAppender

+

+

+1.3 (19/10/2006)

+

+- Fully tested and supported in IE 7 Beta 3

+

+- Added support for FireBug logging levels in BrowserConsoleAppender

+

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

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

+  message to be discarded.

+

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

+

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

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

+  in the formatted output

+

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

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

+  log4javascript.setShowStackTraces function

+

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

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

+  replacement for log4javascript.js in production systems

+

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

+  are removed, resulting in a 30% smaller file

+

+- Added custom fields to layouts

+

+- Added setReopenWhenClosed and isReopenWhenClosed methods to PopUpAppender to

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

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

+

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

+  decide whether to display exceptions

+

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

+

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

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

+  FireBug

+

+- Renamed InlineAppender to InPageAppender (though InlineAppender still works

+  for the sake of backwards compatibility)

+

+- Cosmetic changes to InPageAppender and PopUpAppender

+

+- Added equals() method to Level

+

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

+

+- Added extensive test script

+

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

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

+

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

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

+  is closed before it has fully loaded

+

+- Fixed bug in w and W symbols in SimpleDateFormat

+

+- Fixed bug with quotes inside messages in JsonLayout

+

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

+

+- Changed execution order of callbacks in AjaxAppender so that

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

+  sent

+

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

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

+  changes to the layout take effect immediately

+

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

+  from multiple instances of log4javascript running on different servers

+

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

+

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

+  double quotes

+

+

+1.2 (21/6/2006)

+

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

+

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

+  bugs

+

+- Added addErrorListener and removeErrorListener methods to log4javascript

+  object to allow custom error handling

+

+- Added close() method to PopUpAppender and InlineAppender

+

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

+

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

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

+

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

+  property unchanged rather than reverting to the default

+

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

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

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

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

+  displayed and the appender is disabled.

+

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

+  capitalization and title attributes added to inputs

+

+- toString() method added to all appenders

+

+- Correction to errors in XmlLayout's output

+

+- Documentation corrections and additions

+

+

+1.1.1 (17/5/2006)

+

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

+  latest" checkbox to console window in InlineAppender and PopUpAppender

+

+

+1.1 (16/5/2006)

+

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

+  config properties being altered directly. Several configuration options

+  may not be altered after the appender has been initialized

+

+- Added scrollToLatestMessage constructor parameter, isScrollToLatestMessage

+  and setScrollToLatestMessage methods to InlineAppender and PopUpAppender

+

+- Added isVisible method to InlineAppender

+

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

+  in logic

+

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

+  JsonLayout and HttpPostDataLayout

+

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

+  "timeStamp" in JsonLayout and HttpPostDataLayout

+

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

+  appenders

+

+- Removed browser sniffing code

+

+

+1.0.1 (30/4/2006)

+

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

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

+  be toggled via a checkbox in the console window

+

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

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

+  meaning the behaviour in the demo is essentially unchanged

+

+

+1.0 (26/4/2006)

+

+- Tweaks to default values in PopUpAppender and InlineAppender

+

+- Bugfixes and stylistic tweaks resulting from running JSLint on

+  log4javascript.js

+

+

+1.0 beta 2

+

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

+  methods on the InlineAppender object

+

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

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

+

+

+1.0 beta

+

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

+

+- PopUpAppender default settings bugfix

+

+- getLevel method added to Logger

+

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

+  InlineAppender and PopUpAppender

+

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

+  root logger

+

+0.96

+

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

+

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

+

+- Fixed scrolling issue in Opera InlineAppender and PopUpAppender

+

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

+  only appear when required

+

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

+  InlineAppender and PopUpAppender

+

+- Changed Safari font size in InlineAppender and PopUpAppender

+

+0.95

+

+- AjaxAppender enhancements:

+	- waitForResponse added

+	- timer added

+

+- layout parameter added to all appender constructors

+

+0.94

+- First publicly available version

+- IE 5 support added

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

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

+<head>

+<title>log4javascript</title>

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

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

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

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

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

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

+<script type="text/javascript">

+//<![CDATA[

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

+function LogItem(){}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+return items;}

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

+loggingEnabled=loggingReallyEnabled;}

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

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

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

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

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

+if(scrollToLatest){doScrollToLatest();}

+unrenderedLogItemsExist=false;}

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

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

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

+return false;}

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

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

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

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

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

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

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

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

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

+return false;}

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

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

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

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

+updateSearchFromFilters();}

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

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

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

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

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

+refreshCurrentMatch();}

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

+searchTimer=setTimeout(doSearch,500);}

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

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

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

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

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

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

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

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

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

+matchedText+searchTermReplacementEndTag;}

+startIndex=endTokenIndex+endToken.length;}

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

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

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

+matchedText+searchTermReplacementEndTag;}

+startIndex=searchIndex+searchTermLength;}

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

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

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

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

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

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

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

+return y;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+setLogContainerHeight();}

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

+refreshCurrentMatch();}

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

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

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

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

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

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

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

+return false;}

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

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

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

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

+return matches;}

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

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

+node=node.parentNode;}

+return false;}

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

+currentNode=currentNode.parentNode;}

+return true;}

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

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

+return 0;}

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

+return 0;}

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

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

+return height;}

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

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

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

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

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

+return this.length;};}

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

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

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

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

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

+return itemsDeleted;};}

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

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

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

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

+return array;}

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

+return false;}

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

+return""+ex;}

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

+input.focus();}

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

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

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

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

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

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

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

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

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

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

+//]]>

+</script>

+<style type="text/css">

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

+</style>

+</head>

+<body id="body">

+<div id="switchesContainer">

+<div id="switches">

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

+Filters:

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

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

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

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

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

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

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

+</div>

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

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

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

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

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

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

+<div id="searchNav">

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

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

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

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

+</div>

+</div>

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

+Options:

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

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

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

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

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

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

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

+</div>

+</div>

+</div>

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

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

+<div id="commandLineContainer">

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

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

+</div>

+</div>

+</body>

+</html>

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

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

+	<head>

+		<title>log4javascript</title>

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

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

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

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

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

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

+		<script type="text/javascript">

+			//<![CDATA[

+			var loggingEnabled = true;

+			var logQueuedEventsTimer = null;

+			var logEntries = [];

+			var logEntriesAndSeparators = [];

+			var logItems = [];

+			var renderDelay = 100;

+			var unrenderedLogItemsExist = false;

+			var rootGroup, currentGroup = null;

+			var loaded = false;

+			var currentLogItem = null;

+			var logMainContainer;

+

+			function copyProperties(obj, props) {

+				for (var i in props) {

+					obj[i] = props[i];

+				}

+			}

+

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

+

+			function LogItem() {

+			}

+

+			LogItem.prototype = {

+				mainContainer: null,

+				wrappedContainer: null,

+				unwrappedContainer: null,

+				group: null,

+

+				appendToLog: function() {

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

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

+					}

+					this.group.update();

+				},

+

+				doRemove: function(doUpdate, removeFromGroup) {

+					if (this.rendered) {

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

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

+						}

+						this.unwrappedElementContainer = null;

+						this.wrappedElementContainer = null;

+						this.mainElementContainer = null;

+					}

+					if (this.group && removeFromGroup) {

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

+					}

+					if (this === currentLogItem) {

+						currentLogItem = null;

+					}

+				},

+

+				remove: function(doUpdate, removeFromGroup) {

+					this.doRemove(doUpdate, removeFromGroup);

+				},

+

+				render: function() {},

+

+				accept: function(visitor) {

+					visitor.visit(this);

+				},

+

+				getUnwrappedDomContainer: function() {

+					return this.group.unwrappedElementContainer.contentDiv;

+				},

+

+				getWrappedDomContainer: function() {

+					return this.group.wrappedElementContainer.contentDiv;

+				},

+

+				getMainDomContainer: function() {

+					return this.group.mainElementContainer.contentDiv;

+				}

+			};

+

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

+

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

+

+			function LogItemContainerElement() {

+			}

+

+			LogItemContainerElement.prototype = {

+				appendToLog: function() {

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

+					if (insertBeforeFirst) {

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

+					} else {

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

+					}

+				}

+			};

+

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

+

+			function SeparatorElementContainer(containerDomNode) {

+				this.containerDomNode = containerDomNode;

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

+				this.mainDiv.className = "separator";

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

+			}

+

+			SeparatorElementContainer.prototype = new LogItemContainerElement();

+

+			SeparatorElementContainer.prototype.remove = function() {

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

+				this.mainDiv = null;

+			};

+

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

+

+			function Separator() {

+				this.rendered = false;

+			}

+

+			Separator.prototype = new LogItem();

+

+			copyProperties(Separator.prototype, {

+				render: function() {

+					var containerDomNode = this.group.contentDiv;

+					if (isIe) {

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

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

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

+					} else {

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

+						this.elementContainers = [this.mainElementContainer];

+					}

+					this.content = this.formattedMessage;

+					this.rendered = true;

+				}

+			});

+

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

+

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

+				this.group = group;

+				this.containerDomNode = containerDomNode;

+				this.isRoot = isRoot;

+				this.isWrapped = isWrapped;

+				this.expandable = false;

+

+				if (this.isRoot) {

+					if (isIe) {

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

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

+					} else {

+						this.contentDiv = logMainContainer;

+					}

+				} else {

+					var groupElementContainer = this;

+					

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

+					this.mainDiv.className = "group";

+

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

+					this.headingDiv.className = "groupheading";

+

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

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

+					this.expander.unselectable = true;

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

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

+					

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

+

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

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

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

+

+					this.expander.onclick = function() {

+						if (groupElementContainer.group.expandable) {

+							groupElementContainer.group.toggleExpanded();

+						}

+					};

+				}

+			}

+

+			GroupElementContainer.prototype = new LogItemContainerElement();

+

+			copyProperties(GroupElementContainer.prototype, {

+				toggleExpanded: function() {

+					if (!this.isRoot) {

+						var oldCssClass, newCssClass, expanderText;

+						if (this.group.expanded) {

+							newCssClass = "expanded";

+							oldCssClass = "collapsed";

+							expanderText = "-";

+						} else {

+							newCssClass = "collapsed";

+							oldCssClass = "expanded";

+							expanderText = "+";

+						}

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

+						this.expanderTextNode.nodeValue = expanderText;

+					}

+				},

+

+				remove: function() {

+					if (!this.isRoot) {

+						this.headingDiv = null;

+						this.expander.onclick = null;

+						this.expander = null;

+						this.expanderTextNode = null;

+						this.contentDiv = null;

+						this.containerDomNode = null;

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

+						this.mainDiv = null;

+					}

+				},

+

+				reverseChildren: function() {

+					// Invert the order of the log entries

+					var node = null;

+

+					// Remove all the log container nodes

+					var childDomNodes = [];

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

+						this.contentDiv.removeChild(node);

+						childDomNodes.push(node);

+					}

+

+					// Put them all back in reverse order

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

+						this.contentDiv.appendChild(node);

+					}

+				},

+

+				update: function() {

+					if (!this.isRoot) {

+						if (this.group.expandable) {

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

+						} else {

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

+						}

+					}

+				},

+

+				clear: function() {

+					if (this.isRoot) {

+						this.contentDiv.innerHTML = "";

+					}

+				}

+			});

+

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

+

+			function Group(name, isRoot, initiallyExpanded) {

+				this.name = name;

+				this.group = null;

+				this.isRoot = isRoot;

+				this.initiallyExpanded = initiallyExpanded;

+				this.elementContainers = [];

+				this.children = [];

+				this.expanded = initiallyExpanded;

+				this.rendered = false;

+				this.expandable = false;

+			}

+

+			Group.prototype = new LogItem();

+

+			copyProperties(Group.prototype, {

+				addChild: function(logItem) {

+					this.children.push(logItem);

+					logItem.group = this;

+				},

+

+				render: function() {

+					if (isIe) {

+						var unwrappedDomContainer, wrappedDomContainer;

+						if (this.isRoot) {

+							unwrappedDomContainer = logMainContainer;

+							wrappedDomContainer = logMainContainer;

+						} else {

+							unwrappedDomContainer = this.getUnwrappedDomContainer();

+							wrappedDomContainer = this.getWrappedDomContainer();

+						}

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

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

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

+					} else {

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

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

+						this.elementContainers = [this.mainElementContainer];

+					}

+					this.rendered = true;

+				},

+

+				toggleExpanded: function() {

+					this.expanded = !this.expanded;

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

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

+					}

+				},

+

+				expand: function() {

+					if (!this.expanded) {

+						this.toggleExpanded();

+					}

+				},

+

+				accept: function(visitor) {

+					visitor.visitGroup(this);

+				},

+

+				reverseChildren: function() {

+					if (this.rendered) {

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

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

+						}

+					}

+				},

+

+				update: function() {

+					var previouslyExpandable = this.expandable;

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

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

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

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

+						}

+					}

+				},

+

+				flatten: function() {

+					var visitor = new GroupFlattener();

+					this.accept(visitor);

+					return visitor.logEntriesAndSeparators;

+				},

+

+				removeChild: function(child, doUpdate) {

+					array_remove(this.children, child);

+					child.group = null;

+					if (doUpdate) {

+						this.update();

+					}

+				},

+

+				remove: function(doUpdate, removeFromGroup) {

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

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

+					}

+					this.children = [];

+					this.update();

+					if (this === currentGroup) {

+						currentGroup = this.group;

+					}

+					this.doRemove(doUpdate, removeFromGroup);

+				},

+

+				serialize: function(items) {

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

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

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

+					}

+					if (this !== currentGroup) {

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

+					}

+				},

+

+				clear: function() {

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

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

+					}

+				}

+			});

+

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

+

+			function LogEntryElementContainer() {

+			}

+

+			LogEntryElementContainer.prototype = new LogItemContainerElement();

+

+			copyProperties(LogEntryElementContainer.prototype, {

+				remove: function() {

+					this.doRemove();

+				},

+

+				doRemove: function() {

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

+					this.mainDiv = null;

+					this.contentElement = null;

+					this.containerDomNode = null;

+				},

+

+				setContent: function(content, wrappedContent) {

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

+						this.contentElement.innerHTML = "";

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

+					} else {

+						this.contentElement.innerHTML = content;

+					}

+				},

+

+				setSearchMatch: function(isMatch) {

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

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

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

+				},

+

+				clearSearch: function() {

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

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

+				}

+			});

+

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

+

+			function LogEntryWrappedElementContainer(logEntry, containerDomNode) {

+				this.logEntry = logEntry;

+				this.containerDomNode = containerDomNode;

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

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

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

+				this.contentElement = this.mainDiv;

+			}

+

+			LogEntryWrappedElementContainer.prototype = new LogEntryElementContainer();

+

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

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

+					this.contentElement.innerHTML = "";

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

+				} else {

+					this.contentElement.innerHTML = wrappedContent;

+				}

+			};

+

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

+

+			function LogEntryUnwrappedElementContainer(logEntry, containerDomNode) {

+				this.logEntry = logEntry;

+				this.containerDomNode = containerDomNode;

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

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

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

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

+				this.pre.className = "unwrapped";

+				this.contentElement = this.pre;

+			}

+

+			LogEntryUnwrappedElementContainer.prototype = new LogEntryElementContainer();

+

+			LogEntryUnwrappedElementContainer.prototype.remove = function() {

+				this.doRemove();

+				this.pre = null;

+			};

+

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

+

+			function LogEntryMainElementContainer(logEntry, containerDomNode) {

+				this.logEntry = logEntry;

+				this.containerDomNode = containerDomNode;

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

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

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

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

+			}

+

+			LogEntryMainElementContainer.prototype = new LogEntryElementContainer();

+

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

+

+			function LogEntry(level, formattedMessage) {

+				this.level = level;

+				this.formattedMessage = formattedMessage;

+				this.rendered = false;

+			}

+

+			LogEntry.prototype = new LogItem();

+

+			copyProperties(LogEntry.prototype, {

+				render: function() {

+					var logEntry = this;

+					var containerDomNode = this.group.contentDiv;

+

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

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

+					// use two different HTML elements

+					if (isIe) {

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

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

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

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

+					} else {

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

+						this.elementContainers = [this.mainElementContainer];

+					}

+					this.content = this.formattedMessage;

+					this.rendered = true;

+				},

+

+				setContent: function(content, wrappedContent) {

+					if (content != this.content) {

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

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

+						}

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

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

+						}

+						this.content = content;

+					}

+				},

+

+				getSearchMatches: function() {

+					var matches = [];

+					var i, len;

+					if (isIe) {

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

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

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

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

+						}

+					} else {

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

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

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

+						}

+					}

+					return matches;

+				},

+

+				setSearchMatch: function(isMatch) {

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

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

+					}

+				},

+

+				clearSearch: function() {

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

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

+					}

+				},

+

+				accept: function(visitor) {

+					visitor.visitLogEntry(this);

+				},

+

+				serialize: function(items) {

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

+				}

+			});

+

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

+

+			function LogItemVisitor() {

+			}

+

+			LogItemVisitor.prototype = {

+				visit: function(logItem) {

+				},

+

+				visitParent: function(logItem) {

+					if (logItem.group) {

+						logItem.group.accept(this);

+					}

+				},

+

+				visitChildren: function(logItem) {

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

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

+					}

+				},

+

+				visitLogEntry: function(logEntry) {

+					this.visit(logEntry);

+				},

+

+				visitSeparator: function(separator) {

+					this.visit(separator);

+				},

+

+				visitGroup: function(group) {

+					this.visit(group);

+				}

+			};

+

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

+

+			function GroupFlattener() {

+				this.logEntriesAndSeparators = [];

+			}

+

+			GroupFlattener.prototype = new LogItemVisitor();

+

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

+				this.visitChildren(group);

+			};

+

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

+				this.logEntriesAndSeparators.push(logEntry);

+			};

+

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

+				this.logEntriesAndSeparators.push(separator);

+			};

+

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

+

+			window.onload = function() {

+				// Sort out document.domain

+				if (location.search) {

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

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

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

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

+							document.domain = nameValueBits[1];

+							break;

+						}

+					}

+				}

+

+				// Create DOM objects

+				logMainContainer = $("log");

+				if (isIePre7) {

+					addClass(logMainContainer, "oldIe");

+				}

+

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

+				rootGroup.render();

+				currentGroup = rootGroup;

+				

+				setCommandInputWidth();

+				setLogContainerHeight();

+				toggleLoggingEnabled();

+				toggleSearchEnabled();

+				toggleSearchFilter();

+				toggleSearchHighlight();

+				applyFilters();

+				checkAllLevels();

+				toggleWrap();

+				toggleNewestAtTop();

+				toggleScrollToLatest();

+				renderQueuedLogItems();

+				loaded = true;

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

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

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

+					evt = getEvent(evt);

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

+						evalCommandLine();

+						stopPropagation(evt);

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

+						this.value = "";

+						this.focus();

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

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

+						this.value = commandHistory[currentCommandIndex];

+						moveCaretToEnd(this);

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

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

+						this.value = commandHistory[currentCommandIndex];

+						moveCaretToEnd(this);

+					}

+				};

+

+				// Prevent the keypress moving the caret in Firefox

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

+					evt = getEvent(evt);

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

+						evt.preventDefault();

+					}

+				};

+

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

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

+					evt = getEvent(evt);

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

+						evt.preventDefault();

+						this.focus();

+					}

+				};

+

+				// Add document keyboard shortcuts

+				document.onkeydown = function keyEventHandler(evt) {

+					evt = getEvent(evt);

+					switch (evt.keyCode) {

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

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

+								evalLastCommand();

+								cancelKeyEvent(evt);

+								return false;

+							}

+							break;

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

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

+								focusSearch();

+								cancelKeyEvent(evt);

+								return false;

+							}

+							break;

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

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

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

+								focusCommandLine();

+								cancelKeyEvent(evt);

+								return false;

+							}

+							break;

+					}

+				};

+

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

+				setTimeout(setLogContainerHeight, 20);

+

+				setShowCommandLine(showCommandLine);

+				doSearch();

+			};

+

+			window.onunload = function() {

+				if (mainWindowExists()) {

+					appender.unload();

+				}

+				appender = null;

+			};

+

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

+

+			function toggleLoggingEnabled() {

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

+			}

+

+			function setLoggingEnabled(enable) {

+				loggingEnabled = enable;

+			}

+

+			var appender = null;

+

+			function setAppender(appenderParam) {

+				appender = appenderParam;

+			}

+

+			function setShowCloseButton(showCloseButton) {

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

+			}

+

+			function setShowHideButton(showHideButton) {

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

+			}

+

+			var newestAtTop = false;

+

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

+

+			function LogItemContentReverser() {

+			}

+			

+			LogItemContentReverser.prototype = new LogItemVisitor();

+			

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

+				group.reverseChildren();

+				this.visitChildren(group);

+			};

+

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

+

+			function setNewestAtTop(isNewestAtTop) {

+				var oldNewestAtTop = newestAtTop;

+				var i, iLen, j, jLen;

+				newestAtTop = Boolean(isNewestAtTop);

+				if (oldNewestAtTop != newestAtTop) {

+					var visitor = new LogItemContentReverser();

+					rootGroup.accept(visitor);

+

+					// Reassemble the matches array

+					if (currentSearch) {

+						var currentMatch = currentSearch.matches[currentMatchIndex];

+						var matchIndex = 0;

+						var matches = [];

+						var actOnLogEntry = function(logEntry) {

+							var logEntryMatches = logEntry.getSearchMatches();

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

+								matches[matchIndex] = logEntryMatches[j];

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

+									currentMatchIndex = matchIndex;

+								}

+								matchIndex++;

+							}

+						};

+						if (newestAtTop) {

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

+								actOnLogEntry(logEntries[i]);

+							}

+						} else {

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

+								actOnLogEntry(logEntries[i]);

+							}

+						}

+						currentSearch.matches = matches;

+						if (currentMatch) {

+							currentMatch.setCurrent();

+						}

+					} else if (scrollToLatest) {

+						doScrollToLatest();

+					}

+				}

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

+			}

+

+			function toggleNewestAtTop() {

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

+				setNewestAtTop(isNewestAtTop);

+			}

+

+			var scrollToLatest = true;

+

+			function setScrollToLatest(isScrollToLatest) {

+				scrollToLatest = isScrollToLatest;

+				if (scrollToLatest) {

+					doScrollToLatest();

+				}

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

+			}

+

+			function toggleScrollToLatest() {

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

+				setScrollToLatest(isScrollToLatest);

+			}

+

+			function doScrollToLatest() {

+				var l = logMainContainer;

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

+					if (newestAtTop) {

+						l.scrollTop = 0;

+					} else {

+						var latestLogEntry = l.lastChild;

+						if (latestLogEntry) {

+							l.scrollTop = l.scrollHeight;

+						}

+					}

+				}

+			}

+

+			var closeIfOpenerCloses = true;

+

+			function setCloseIfOpenerCloses(isCloseIfOpenerCloses) {

+				closeIfOpenerCloses = isCloseIfOpenerCloses;

+			}

+

+			var maxMessages = null;

+

+			function setMaxMessages(max) {

+				maxMessages = max;

+				pruneLogEntries();

+			}

+

+			var showCommandLine = false;

+

+			function setShowCommandLine(isShowCommandLine) {

+				showCommandLine = isShowCommandLine;

+				if (loaded) {

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

+					setCommandInputWidth();

+					setLogContainerHeight();

+				}

+			}

+

+			function focusCommandLine() {

+				if (loaded) {

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

+				}

+			}

+

+			function focusSearch() {

+				if (loaded) {

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

+				}

+			}

+

+			function getLogItems() {

+				var items = [];

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

+					logItems[i].serialize(items);

+				}

+				return items;

+			}

+

+			function setLogItems(items) {

+				var loggingReallyEnabled = loggingEnabled;

+				// Temporarily turn logging on

+				loggingEnabled = true;

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

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

+						case LogItem.serializedItemKeys.LOG_ENTRY:

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

+							break;

+						case LogItem.serializedItemKeys.GROUP_START:

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

+							break;

+						case LogItem.serializedItemKeys.GROUP_END:

+							groupEnd();

+							break;

+					}

+				}

+				loggingEnabled = loggingReallyEnabled;

+			}

+

+			function log(logLevel, formattedMessage) {

+				if (loggingEnabled) {

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

+					logEntries.push(logEntry);

+					logEntriesAndSeparators.push(logEntry);

+					logItems.push(logEntry);

+					currentGroup.addChild(logEntry);

+					if (loaded) {

+						if (logQueuedEventsTimer !== null) {

+							clearTimeout(logQueuedEventsTimer);

+						}

+						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);

+						unrenderedLogItemsExist = true;

+					}

+				}

+			}

+

+			function renderQueuedLogItems() {

+				logQueuedEventsTimer = null;

+				var pruned = pruneLogEntries();

+

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

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

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

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

+						logItems[i].render();

+						logItems[i].appendToLog();

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

+							currentSearch.applyTo(logItems[i]);

+						}

+					}

+				}

+				if (currentSearch) {

+					if (pruned) {

+						if (currentSearch.hasVisibleMatches()) {

+							if (currentMatchIndex === null) {

+								setCurrentMatchIndex(0);

+							}

+							displayMatches();

+						} else {

+							displayNoMatches();

+						}

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

+						setCurrentMatchIndex(0);

+						displayMatches();

+					}

+				}

+				if (scrollToLatest) {

+					doScrollToLatest();

+				}

+				unrenderedLogItemsExist = false;

+			}

+

+			function pruneLogEntries() {

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

+					var numberToDelete = logEntriesAndSeparators.length - maxMessages;

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

+					if (currentSearch) {

+						currentSearch.removeMatches(prunedLogEntries);

+					}

+					var group;

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

+						group = logEntriesAndSeparators[i].group;

+						array_remove(logItems, logEntriesAndSeparators[i]);

+						array_remove(logEntries, logEntriesAndSeparators[i]);

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

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

+							array_remove(logItems, group);

+							group.remove(true, true);

+						}

+					}

+					logEntriesAndSeparators = array_removeFromStart(logEntriesAndSeparators, numberToDelete);

+					return true;

+				}

+				return false;

+			}

+

+			function group(name, startExpanded) {

+				if (loggingEnabled) {

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

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

+					currentGroup.addChild(newGroup);

+					currentGroup = newGroup;

+					logItems.push(newGroup);

+					if (loaded) {

+						if (logQueuedEventsTimer !== null) {

+							clearTimeout(logQueuedEventsTimer);

+						}

+						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);

+						unrenderedLogItemsExist = true;

+					}

+				}

+			}

+

+			function groupEnd() {

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

+			}

+

+			function mainPageReloaded() {

+				currentGroup = rootGroup;

+				var separator = new Separator();

+				logEntriesAndSeparators.push(separator);

+				logItems.push(separator);

+				currentGroup.addChild(separator);

+			}

+

+			function closeWindow() {

+				if (appender && mainWindowExists()) {

+					appender.close(true);

+				} else {

+					window.close();

+				}

+			}

+

+			function hide() {

+				if (appender && mainWindowExists()) {

+					appender.hide();

+				}

+			}

+

+			var mainWindow = window;

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

+

+			function setMainWindow(win) {

+				mainWindow = win;

+				mainWindow[windowId] = window;

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

+				if (opener && closeIfOpenerCloses) {

+					pollOpener();

+				}

+			}

+

+			function pollOpener() {

+				if (closeIfOpenerCloses) {

+					if (mainWindowExists()) {

+						setTimeout(pollOpener, 500);

+					} else {

+						closeWindow();

+					}

+				}

+			}

+

+			function mainWindowExists() {

+				try {

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

+						mainWindow[windowId] == window);

+				} catch (ex) {}

+				return false;

+			}

+

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

+

+			function getCheckBox(logLevel) {

+				return $("switch_" + logLevel);

+			}

+

+			function getIeWrappedLogContainer() {

+				return $("log_wrapped");

+			}

+

+			function getIeUnwrappedLogContainer() {

+				return $("log_unwrapped");

+			}

+

+			function applyFilters() {

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

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

+						addClass(logMainContainer, logLevels[i]);

+					} else {

+						removeClass(logMainContainer, logLevels[i]);

+					}

+				}

+				updateSearchFromFilters();

+			}

+

+			function toggleAllLevels() {

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

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

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

+					if (turnOn) {

+						addClass(logMainContainer, logLevels[i]);

+					} else {

+						removeClass(logMainContainer, logLevels[i]);

+					}

+				}

+			}

+

+			function checkAllLevels() {

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

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

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

+						return;

+					}

+				}

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

+			}

+

+			function clearLog() {

+				rootGroup.clear();

+				currentGroup = rootGroup;

+				logEntries = [];

+				logItems = [];

+				logEntriesAndSeparators = [];

+ 				doSearch();

+			}

+

+			function toggleWrap() {

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

+				if (enable) {

+					addClass(logMainContainer, "wrap");

+				} else {

+					removeClass(logMainContainer, "wrap");

+				}

+				refreshCurrentMatch();

+			}

+

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

+

+			// Search

+

+			var searchTimer = null;

+

+			function scheduleSearch() {

+				try {

+					clearTimeout(searchTimer);

+				} catch (ex) {

+					// Do nothing

+				}

+				searchTimer = setTimeout(doSearch, 500);

+			}

+

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

+				this.searchTerm = searchTerm;

+				this.isRegex = isRegex;

+				this.searchRegex = searchRegex;

+				this.isCaseSensitive = isCaseSensitive;

+				this.matches = [];

+			}

+

+			Search.prototype = {

+				hasMatches: function() {

+					return this.matches.length > 0;

+				},

+

+				hasVisibleMatches: function() {

+					if (this.hasMatches()) {

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

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

+								return true;

+							}

+						}

+					}

+					return false;

+				},

+

+				match: function(logEntry) {

+					var entryText = String(logEntry.formattedMessage);

+					var matchesSearch = false;

+					if (this.isRegex) {

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

+					} else if (this.isCaseSensitive) {

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

+					} else {

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

+					}

+					return matchesSearch;

+				},

+

+				getNextVisibleMatchIndex: function() {

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

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

+							return i;

+						}

+					}

+					// Start again from the first match

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

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

+							return i;

+						}

+					}

+					return -1;

+				},

+

+				getPreviousVisibleMatchIndex: function() {

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

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

+							return i;

+						}

+					}

+					// Start again from the last match

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

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

+							return i;

+						}

+					}

+					return -1;

+				},

+

+				applyTo: function(logEntry) {

+					var doesMatch = this.match(logEntry);

+					if (doesMatch) {

+						logEntry.group.expand();

+						logEntry.setSearchMatch(true);

+						var logEntryContent;

+						var wrappedLogEntryContent;

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

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

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

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

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

+						var startIndex = 0;

+						var searchIndex, matchedText, textBeforeMatch;

+						if (this.isRegex) {

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

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

+

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

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

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

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

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

+

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

+							logEntryContent = escapeHtml(logEntryContent);

+

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

+							var result;

+							var searchString = logEntryContent;

+							logEntryContent = "";

+							wrappedLogEntryContent = "";

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

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

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

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

+								logEntryContent += preStartTag + textBeforeMatch + preEndTag;

+								logEntryContent += searchTermReplacementStartTag + preStartTag + matchedText +

+									preEndTag + searchTermReplacementEndTag;

+								if (isIe) {

+									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +

+										matchedText + searchTermReplacementEndTag;

+								}

+								startIndex = endTokenIndex + endToken.length;

+							}

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

+							if (isIe) {

+								wrappedLogEntryContent += searchString.substr(startIndex);

+							}

+						} else {

+							logEntryContent = "";

+							wrappedLogEntryContent = "";

+							var searchTermReplacementLength = searchTermReplacementStartTag.length +

+								this.searchTerm.length + searchTermReplacementEndTag.length;

+							var searchTermLength = this.searchTerm.length;

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

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

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

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

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

+								var searchTermReplacement = searchTermReplacementStartTag +

+									preStartTag + matchedText + preEndTag + searchTermReplacementEndTag;

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

+								if (isIe) {

+									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +

+										matchedText + searchTermReplacementEndTag;

+								}

+								startIndex = searchIndex + searchTermLength;

+							}

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

+							logEntryContent += preStartTag + textAfterLastMatch + preEndTag;

+							if (isIe) {

+								wrappedLogEntryContent += textAfterLastMatch;

+							}

+						}

+						logEntry.setContent(logEntryContent, wrappedLogEntryContent);

+						var logEntryMatches = logEntry.getSearchMatches();

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

+					} else {

+						logEntry.setSearchMatch(false);

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

+					}

+					return doesMatch;

+				},

+

+				removeMatches: function(logEntries) {

+					var matchesToRemoveCount = 0;

+					var currentMatchRemoved = false;

+					var matchesToRemove = [];

+					var i, iLen, j, jLen;

+

+					// Establish the list of matches to be removed

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

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

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

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

+								if (i === currentMatchIndex) {

+									currentMatchRemoved = true;

+								}

+							}

+						}

+					}

+

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

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

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

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

+					if (currentMatchRemoved) {

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

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

+								newMatch = this.matches[i];

+								break;

+							}

+						}

+					}

+

+					// Remove the matches

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

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

+						matchesToRemove[i].remove();

+					}

+

+					// Set the new match, if one exists

+					if (this.hasVisibleMatches()) {

+						if (newMatch === null) {

+							setCurrentMatchIndex(0);

+						} else {

+							// Get the index of the new match

+							var newMatchIndex = 0;

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

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

+									newMatchIndex = i;

+									break;

+								}

+							}

+							setCurrentMatchIndex(newMatchIndex);

+						}

+					} else {

+						currentMatchIndex = null;

+						displayNoMatches();

+					}

+				}

+			};

+

+			function getPageOffsetTop(el, container) {

+				var currentEl = el;

+				var y = 0;

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

+					y += currentEl.offsetTop;

+					currentEl = currentEl.offsetParent;

+				}

+				return y;

+			}

+

+			function scrollIntoView(el) {

+				var logContainer = logMainContainer;

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

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

+					var logContainerLeft = logContainer.scrollLeft;

+					var logContainerRight = logContainerLeft  + logContainer.offsetWidth;

+					var elLeft = el.offsetLeft;

+					var elRight = elLeft + el.offsetWidth;

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

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

+					}

+				}

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

+				var logContainerTop = logContainer.scrollTop;

+				var logContainerBottom = logContainerTop  + logContainer.offsetHeight;

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

+				var elBottom = elTop + el.offsetHeight;

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

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

+				}

+			}

+

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

+				this.logEntryLevel = logEntryLevel;

+				this.spanInMainDiv = spanInMainDiv;

+				if (isIe) {

+					this.spanInUnwrappedPre = spanInUnwrappedPre;

+					this.spanInWrappedDiv = spanInWrappedDiv;

+				}

+				this.mainSpan = isIe ? spanInUnwrappedPre : spanInMainDiv;

+			}

+

+			Match.prototype = {

+				equals: function(match) {

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

+				},

+

+				setCurrent: function() {

+					if (isIe) {

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

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

+						// Scroll the visible one into view

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

+						scrollIntoView(elementToScroll);

+					} else {

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

+						scrollIntoView(this.spanInMainDiv);

+					}

+				},

+

+				belongsTo: function(logEntry) {

+					if (isIe) {

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

+					} else {

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

+					}

+				},

+

+				setNotCurrent: function() {

+					if (isIe) {

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

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

+					} else {

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

+					}

+				},

+

+				isOrphan: function() {

+					return isOrphan(this.mainSpan);

+				},

+

+				isVisible: function() {

+					return getCheckBox(this.logEntryLevel).checked;

+				},

+

+				remove: function() {

+					if (isIe) {

+						this.spanInUnwrappedPre = null;

+						this.spanInWrappedDiv = null;

+					} else {

+						this.spanInMainDiv = null;

+					}

+				}

+			};

+

+			var currentSearch = null;

+			var currentMatchIndex = null;

+

+			function doSearch() {

+				var searchBox = $("searchBox");

+				var searchTerm = searchBox.value;

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

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

+				var i;

+

+				if (searchTerm === "") {

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

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

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

+					removeClass(searchBox, "hasmatches");

+					removeClass(searchBox, "nomatches");

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

+						logEntries[i].clearSearch();

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

+					}

+					currentSearch = null;

+					setLogContainerHeight();

+				} else {

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

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

+					var searchRegex;

+					var regexValid;

+					if (isRegex) {

+						try {

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

+							regexValid = true;

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

+							searchBox.title = "Valid regex";

+						} catch (ex) {

+							regexValid = false;

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

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

+							return;

+						}

+					} else {

+						searchBox.title = "";

+						removeClass(searchBox, "validregex");

+						removeClass(searchBox, "invalidregex");

+					}

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

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

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

+						currentSearch.applyTo(logEntries[i]);

+					}

+					setLogContainerHeight();

+

+					// Highlight the first search match

+					if (currentSearch.hasVisibleMatches()) {

+						setCurrentMatchIndex(0);

+						displayMatches();

+					} else {

+						displayNoMatches();

+					}

+				}

+			}

+

+			function updateSearchFromFilters() {

+				if (currentSearch) {

+					if (currentSearch.hasMatches()) {

+						if (currentMatchIndex === null) {

+							currentMatchIndex = 0;

+						}

+						var currentMatch = currentSearch.matches[currentMatchIndex];

+						if (currentMatch.isVisible()) {

+							displayMatches();

+							setCurrentMatchIndex(currentMatchIndex);

+						} else {

+							currentMatch.setNotCurrent();

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

+							var nextVisibleMatchIndex = currentSearch.getNextVisibleMatchIndex();

+							if (nextVisibleMatchIndex > -1) {

+								setCurrentMatchIndex(nextVisibleMatchIndex);

+								displayMatches();

+							} else {

+								displayNoMatches();

+							}

+						}

+					} else {

+						displayNoMatches();

+					}

+				}

+			}

+

+			function refreshCurrentMatch() {

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

+					setCurrentMatchIndex(currentMatchIndex);

+				}

+			}

+

+			function displayMatches() {

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

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

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

+				setLogContainerHeight();

+			}

+

+			function displayNoMatches() {

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

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

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

+				setLogContainerHeight();

+			}

+

+			function toggleSearchEnabled(enable) {

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

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

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

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

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

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

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

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

+						currentSearch && currentSearch.hasVisibleMatches()) ?

+					"block" : "none";

+				if (enable) {

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

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

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

+						addClass(logMainContainer, "searchhighlight");

+					} else {

+						removeClass(logMainContainer, "searchhighlight");

+					}

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

+						addClass(logMainContainer, "searchfilter");

+					} else {

+						removeClass(logMainContainer, "searchfilter");

+					}

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

+				} else {

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

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

+					removeClass(logMainContainer, "searchhighlight");

+					removeClass(logMainContainer, "searchfilter");

+				}

+				setLogContainerHeight();

+			}

+

+			function toggleSearchFilter() {

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

+				if (enable) {

+					addClass(logMainContainer, "searchfilter");

+				} else {

+					removeClass(logMainContainer, "searchfilter");

+				}

+				refreshCurrentMatch();

+			}

+

+			function toggleSearchHighlight() {

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

+				if (enable) {

+					addClass(logMainContainer, "searchhighlight");

+				} else {

+					removeClass(logMainContainer, "searchhighlight");

+				}

+			}

+

+			function clearSearch() {

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

+				doSearch();

+			}

+

+			function searchNext() {

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

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

+					var nextMatchIndex = currentSearch.getNextVisibleMatchIndex();

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

+						setCurrentMatchIndex(nextMatchIndex);

+					}

+				}

+			}

+

+			function searchPrevious() {

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

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

+					var previousMatchIndex = currentSearch.getPreviousVisibleMatchIndex();

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

+						setCurrentMatchIndex(previousMatchIndex);

+					}

+				}

+			}

+

+			function setCurrentMatchIndex(index) {

+				currentMatchIndex = index;

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

+			}

+

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

+

+			// CSS Utilities

+

+			function addClass(el, cssClass) {

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

+					if (el.className) {

+						el.className += " " + cssClass;

+					} else {

+						el.className = cssClass;

+					}

+				}

+			}

+

+			function hasClass(el, cssClass) {

+				if (el.className) {

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

+					return array_contains(classNames, cssClass);

+				}

+				return false;

+			}

+

+			function removeClass(el, cssClass) {

+				if (hasClass(el, cssClass)) {

+					// Rebuild the className property

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

+					var newClasses = [];

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

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

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

+						}

+					}

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

+				}

+			}

+

+			function replaceClass(el, newCssClass, oldCssClass) {

+				removeClass(el, oldCssClass);

+				addClass(el, newCssClass);

+			}

+

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

+

+			// Other utility functions

+

+			function getElementsByClass(el, cssClass, tagName) {

+				var elements = el.getElementsByTagName(tagName);

+				var matches = [];

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

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

+						matches.push(elements[i]);

+					}

+				}

+				return matches;

+			}

+

+			// Syntax borrowed from Prototype library

+			function $(id) {

+				return document.getElementById(id);

+			}

+

+			function isDescendant(node, ancestorNode) {

+				while (node != null) {

+					if (node === ancestorNode) {

+						return true;

+					}

+					node = node.parentNode;

+				}

+				return false;

+			}

+

+			function isOrphan(node) {

+				var currentNode = node;

+				while (currentNode) {

+					if (currentNode == document.body) {

+						return false;

+					}

+					currentNode = currentNode.parentNode;

+				}

+				return true;

+			}

+

+			function escapeHtml(str) {

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

+			}

+

+			function getWindowWidth() {

+				if (window.innerWidth) {

+					return window.innerWidth;

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

+					return document.documentElement.clientWidth;

+				} else if (document.body) {

+					return document.body.clientWidth;

+				}

+				return 0;

+			}

+

+			function getWindowHeight() {

+				if (window.innerHeight) {

+					return window.innerHeight;

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

+					return document.documentElement.clientHeight;

+				} else if (document.body) {

+					return document.body.clientHeight;

+				}

+				return 0;

+			}

+

+			function getToolBarsHeight() {

+				return $("switches").offsetHeight;

+			}

+

+			function getChromeHeight() {

+				var height = getToolBarsHeight();

+				if (showCommandLine) {

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

+				}

+				return height;

+			}

+

+			function setLogContainerHeight() {

+				if (logMainContainer) {

+					var windowHeight = getWindowHeight();

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

+					logMainContainer.style.height = "" +

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

+				}

+			}

+

+			function setCommandInputWidth() {

+				if (showCommandLine) {

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

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

+				}

+			}

+

+			window.onresize = function() {

+				setCommandInputWidth();

+				setLogContainerHeight();

+			};

+

+			if (!Array.prototype.push) {

+				Array.prototype.push = function() {

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

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

+			        }

+			        return this.length;

+				};

+			}

+

+			if (!Array.prototype.pop) {

+				Array.prototype.pop = function() {

+					if (this.length > 0) {

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

+						this.length = this.length - 1;

+						return val;

+					}

+				};

+			}

+

+			if (!Array.prototype.shift) {

+				Array.prototype.shift = function() {

+					if (this.length > 0) {

+						var firstItem = this[0];

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

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

+						}

+						this.length = this.length - 1;

+						return firstItem;

+					}

+				};

+			}

+

+			if (!Array.prototype.splice) {

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

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

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

+					this.length = startIndex;

+					// Copy the arguments into a proper Array object

+					var argumentsArray = [];

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

+						argumentsArray[i] = arguments[i];

+					}

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

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

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

+						this.push(itemsToAppend[i]);

+					}

+					return itemsDeleted;

+				};

+			}

+

+			function array_remove(arr, val) {

+				var index = -1;

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

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

+						index = i;

+						break;

+					}

+				}

+				if (index >= 0) {

+					arr.splice(index, 1);

+					return index;

+				} else {

+					return false;

+				}

+			}

+

+			function array_removeFromStart(array, numberToRemove) {

+				if (Array.prototype.splice) {

+					array.splice(0, numberToRemove);

+				} else {

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

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

+					}

+					array.length = array.length - numberToRemove;

+				}

+				return array;

+			}

+

+			function array_contains(arr, val) {

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

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

+						return true;

+					}

+				}

+				return false;

+			}

+

+			function getErrorMessage(ex) {

+				if (ex.message) {

+					return ex.message;

+				} else if (ex.description) {

+					return ex.description;

+				}

+				return "" + ex;

+			}

+

+			function moveCaretToEnd(input) {

+				if (input.setSelectionRange) {

+					input.focus();

+					var length = input.value.length;

+					input.setSelectionRange(length, length);

+				} else if (input.createTextRange) {

+					var range = input.createTextRange();

+					range.collapse(false);

+					range.select();

+				}

+				input.focus();

+			}

+

+			function stopPropagation(evt) {

+				if (evt.stopPropagation) {

+					evt.stopPropagation();

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

+					evt.cancelBubble = true;

+				}

+			}

+

+			function getEvent(evt) {

+				return evt ? evt : event;

+			}

+

+			function getTarget(evt) {

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

+			}

+

+			function getRelatedTarget(evt) {

+				if (evt.relatedTarget) {

+					return evt.relatedTarget;

+				} else if (evt.srcElement) {

+					switch(evt.type) {

+						case "mouseover":

+							return evt.fromElement;

+						case "mouseout":

+							return evt.toElement;

+						default:

+							return evt.srcElement;

+					}

+				}

+			}

+

+			function cancelKeyEvent(evt) {

+				evt.returnValue = false;

+				stopPropagation(evt);

+			}

+

+			function evalCommandLine() {

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

+				evalCommand(expr);

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

+			}

+

+			function evalLastCommand() {

+				if (lastCommand != null) {

+					evalCommand(lastCommand);

+				}

+			}

+

+			var lastCommand = null;

+			var commandHistory = [];

+			var currentCommandIndex = 0;

+

+			function evalCommand(expr) {

+				if (appender) {

+					appender.evalCommandAndAppend(expr);

+				} else {

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

+					try {

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

+					} catch (ex) {

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

+					}

+				}

+				// Update command history

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

+					commandHistory.push(expr);

+					// Update the appender

+					if (appender) {

+						appender.storeCommandHistory(commandHistory);

+					}

+				}

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

+				lastCommand = expr;

+			}

+			//]]>

+		</script>

+		<style type="text/css">

+			body {

+				background-color: white;

+				color: black;

+				padding: 0;

+				margin: 0;

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

+				overflow: hidden;

+			}

+

+			div#switchesContainer input {

+				margin-bottom: 0;

+			}

+

+			div.toolbar {

+				border-top: solid #ffffff 1px;

+				border-bottom: solid #aca899 1px;

+				background-color: #f1efe7;

+				padding: 3px 5px;

+				font-size: 68.75%;

+			}

+

+			div.toolbar, div#search input {

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

+			}

+

+			div.toolbar input.button {

+				padding: 0 5px;

+				font-size: 100%;

+			}

+

+			div.toolbar input.hidden {

+				display: none;

+			}

+

+			div#switches input#clearButton {

+				margin-left: 20px;

+			}

+

+			div#levels label {

+				font-weight: bold;

+			}

+

+			div#levels label, div#options label {

+				margin-right: 5px;

+			}

+

+			div#levels label#wrapLabel {

+				font-weight: normal;

+			}

+

+			div#search label {

+				margin-right: 10px;

+			}

+

+			div#search label.searchboxlabel {

+				margin-right: 0;

+			}

+

+			div#search input {

+				font-size: 100%;

+			}

+

+			div#search input.validregex {

+				color: green;

+			}

+

+			div#search input.invalidregex {

+				color: red;

+			}

+

+			div#search input.nomatches {

+				color: white;

+				background-color: #ff6666;

+			}

+

+			div#search input.nomatches {

+				color: white;

+				background-color: #ff6666;

+			}

+

+			div#searchNav {

+				display: none;

+			}

+

+			div#commandLine {

+				display: none;

+			}

+

+			div#commandLine input#command {

+				font-size: 100%;

+				font-family: Courier New, Courier;

+			}

+

+			div#commandLine input#evaluateButton {

+			}

+

+			*.greyedout {

+				color: gray !important;

+				border-color: gray !important;

+			}

+

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

+

+			*.unselectable {

+				-khtml-user-select: none;

+				-moz-user-select: none;

+				user-select: none;

+			}

+

+			div#log {

+				font-family: Courier New, Courier;

+				font-size: 75%;

+				width: 100%;

+				overflow: auto;

+				clear: both;

+				position: relative;

+			}

+

+			div.group {

+				border-color: #cccccc;

+				border-style: solid;

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

+				overflow: visible;

+			}

+

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

+				height: 1%;

+			}

+

+			div.group div.groupheading span.expander {

+				border: solid black 1px;

+				font-family: Courier New, Courier;

+				font-size: 0.833em;

+				background-color: #eeeeee;

+				position: relative;

+				top: -1px;

+				color: black;

+				padding: 0 2px;

+				cursor: pointer;

+				cursor: hand;

+				height: 1%;

+			}

+

+			div.group div.groupcontent {

+				margin-left: 10px;

+				padding-bottom: 2px;

+				overflow: visible;

+			}

+

+			div.group div.expanded {

+				display: block;

+			}

+

+			div.group div.collapsed {

+				display: none;

+			}

+

+			*.logentry {

+				overflow: visible;

+				display: none;

+				white-space: pre;

+			}

+

+			span.pre {

+				white-space: pre;

+			}

+			

+			pre.unwrapped {

+				display: inline !important;

+			}

+

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

+				display: inline;

+			}

+

+			div.wrapped pre.pre {

+				white-space: normal;

+			}

+

+			div.wrapped {

+				display: none;

+			}

+

+			body.searching *.logentry span.currentmatch {

+				color: white !important;

+				background-color: green !important;

+			}

+

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

+				color: black;

+				background-color: yellow;

+			}

+

+			div.wrap *.logentry {

+				white-space: normal !important;

+				border-width: 0 0 1px 0;

+				border-color: #dddddd;

+				border-style: dotted;

+			}

+

+			div.wrap #log_wrapped, #log_unwrapped {

+				display: block;

+			}

+

+			div.wrap #log_unwrapped, #log_wrapped {

+				display: none;

+			}

+

+			div.wrap *.logentry span.pre {

+				overflow: visible;

+				white-space: normal;

+			}

+

+			div.wrap *.logentry pre.unwrapped {

+				display: none;

+			}

+

+			div.wrap *.logentry span.wrapped {

+				display: inline;

+			}

+

+			div.searchfilter *.searchnonmatch {

+				display: none !important;

+			}

+

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

+				color: #666666;

+			}

+

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

+				color: green;

+			}

+

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

+				color: #000099;

+			}

+

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

+				color: #999900;

+			}

+

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

+				color: red;

+			}

+

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

+				color: #660066;

+			}

+

+			div.TRACE#log *.TRACE,

+			div.DEBUG#log *.DEBUG,

+			div.INFO#log *.INFO,

+			div.WARN#log *.WARN,

+			div.ERROR#log *.ERROR,

+			div.FATAL#log *.FATAL {

+				display: block;

+			}

+

+			div#log div.separator {

+				background-color: #cccccc;

+				margin: 5px 0;

+				line-height: 1px;

+			}

+		</style>

+	</head>

+

+	<body id="body">

+		<div id="switchesContainer">

+			<div id="switches">

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

+					Filters:

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

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

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

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

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

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

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

+				</div>

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

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

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

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

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

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

+					<div id="searchNav">

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

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

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

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

+					</div>

+				</div>

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

+					Options:

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

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

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

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

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

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

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

+				</div>

+			</div>

+		</div>

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

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

+			<div id="commandLineContainer">

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

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

+			</div>

+		</div>

+	</body>

+</html>

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

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

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

+	<head>

+		<title>log4javascript basic demo</title>

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

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

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

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

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

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

+		<script type="text/javascript">

+			// <![CDATA[

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

+			var appender = new log4javascript.PopUpAppender();

+			log.addAppender(appender);

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

+

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

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

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

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

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

+			];

+

+			var loaded = false;

+

+			function generateRandom() {

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

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

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

+					var entryWords = [];

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

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

+					}

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

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

+					switch (levelNum) {

+						case 0:

+							log.trace(entryMessage);

+							break;

+						case 1:

+							log.debug(entryMessage);

+							break;

+						case 2:

+							log.info(entryMessage);

+							break;

+						case 3:

+							log.warn(entryMessage);

+							break;

+						case 4:

+							log.error(entryMessage);

+							break;

+						case 5:

+							log.fatal(entryMessage);

+							break;

+					}

+				}

+			}

+

+			function generateObjectExpansion() {

+				var debugObj = {

+					a: {

+						b: "stuff",

+						c: 3,

+						d: {

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

+						}

+					},

+					f: "Things",

+					g: 5

+				};

+				log.debug(debugObj);

+			}

+

+			function generateError() {

+				try {

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

+				} catch (ex) {

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

+				}

+			}

+			// ]]>

+		</script>

+	</head>

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

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

+			<div id="header">

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

+			</div>

+			<div id="content">

+				<div id="nav">

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

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

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

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

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

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

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

+				</div>

+				<h1>log4javascript basic demo</h1>

+				<p>

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

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

+				</p>

+				<p>

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

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

+				</p>

+				<p>

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

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

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

+					expression searches on the log entries.

+				</p>

+				<div class="example">

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

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

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

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

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

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

+					<br />

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

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

+					<br />

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

+					<input type="button" value="go" onclick="generateRandom()" />

+					<br />

+					<input type="button" value="Log exception" onclick="generateError()" />

+					<input type="button" value="Log example object" onclick="generateObjectExpansion()" />

+					<br />

+					<input type="checkbox" id="enabled" onclick="log4javascript.setEnabled(this.checked)" checked="checked" /> <label for="enabled">logging enabled</label>

+					<br />

+					<input type="text" id="groupName" value="Group name" />

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

+					<input type="button" value="end group" onclick="log.groupEnd()" />

+					<br />

+					<input type="text" id="timerName" value="Example timer name" />

+					<input type="button" value="start timer" onclick="log.time(document.getElementById('timerName').value)" />

+					<input type="button" value="end timer" onclick="log.timeEnd(document.getElementById('timerName').value)" />

+				</div>

+			</div>

+			<br class="clear" />

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/demos/blank.html b/planetstack/core/static/log4javascript-1.4.6/demos/blank.html
new file mode 100644
index 0000000..7e8ac56
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/demos/blank.html
@@ -0,0 +1,4 @@
+<html>

+<head><title>Blank page</title></head>

+<body></body>

+</html>
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/demos/index.html b/planetstack/core/static/log4javascript-1.4.6/demos/index.html
new file mode 100644
index 0000000..00e84ac
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/demos/index.html
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript demos</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="/docs/index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="../docs/index.html">docs</a>

+					| <a class="navitem" href="../docs/quickstart.html">quick start</a>

+					| <span class="navitem">demos</span>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript demos</h1>

+				<ul>

+					<li><a href="basic.html">Basic demo</a></li>

+					<li><a href="inpage.html">In-page console demo</a></li>

+					<li><a href="lite.html">log4javascript Lite demo</a></li>

+				</ul>

+			</div>

+			<br class="clear" />

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/demos/inpage.html b/planetstack/core/static/log4javascript-1.4.6/demos/inpage.html
new file mode 100644
index 0000000..8e47d72
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/demos/inpage.html
@@ -0,0 +1,174 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript in-page console demo</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+		<script type="text/javascript" src="../js/log4javascript_uncompressed.js"></script>

+		<script type="text/javascript">

+			// <![CDATA[

+			var log = log4javascript.getLogger("main");

+			var appender = new log4javascript.InPageAppender();

+			log.addAppender(appender);

+			log.debug("This is a debugging message from the log4javascript in-page page");

+

+			var words = ["Watford", "eased", "their", "relegation", "fears", "with", "a", "win",

+				"against", "a", "Charlton", "side", "who", "slipped", "further", "towards", "the",

+				"drop", "Don", "Cowie", "drilled", "in", "a", "shot", "to", "put", "the", "Hornets",

+				"ahead", "before", "Tresor", "Kandol", "ended", "a", "powerful", "run", "by",

+				"rounding", "keeper", "Scott", "Loach", "and", "slotting", "in", "to", "level"

+			];

+

+			var loaded = false;

+

+			function generateRandom() {

+				var numberOfEntries = parseInt(document.getElementById("numberOfLogEntries").value);

+				for (var i = 0; i < numberOfEntries; i++) {

+					var numberOfWords = 1 + Math.floor(10 * Math.random());

+					var entryWords = [];

+					for (var j = 0; j < numberOfWords; j++) {

+						entryWords.push(words[Math.floor(Math.random() * words.length)]);

+					}

+					var entryMessage = entryWords.join(" ");

+					var levelNum = Math.floor(Math.random() * 6);

+					switch (levelNum) {

+						case 0:

+							log.trace(entryMessage);

+							break;

+						case 1:

+							log.debug(entryMessage);

+							break;

+						case 2:

+							log.info(entryMessage);

+							break;

+						case 3:

+							log.warn(entryMessage);

+							break;

+						case 4:

+							log.error(entryMessage);

+							break;

+						case 5:

+							log.fatal(entryMessage);

+							break;

+					}

+				}

+			}

+			

+			var consoleVisible = true;

+			

+			function toggleConsole(button) {

+				if (consoleVisible) {

+					appender.hide();

+					button.value = "Show console";

+					consoleVisible = false;

+				} else {

+					appender.show();

+					button.value = "Hide console";

+					consoleVisible = true;

+				}

+			}

+

+			function generateObjectExpansion() {

+				var debugObj = {

+					a: {

+						b: "stuff",

+						c: 3,

+						d: {

+							e: ["a", "b", "c"]

+						}

+					},

+					f: "Things",

+					g: 5

+				};

+				log.debug(debugObj);

+			}

+

+			function generateError() {

+				try {

+					throw new Error("Made up error");

+				} catch (ex) {

+					log.error("Logging an error!", ex);

+				}

+			}

+			// ]]>

+		</script>

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="/docs/index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="../docs/index.html">docs</a>

+					| <a class="navitem" href="../docs/quickstart.html">quick start</a>

+					| <a class="navitem" href="index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript in-page console demo</h1>

+				<p>

+					This demo demonstrates an in-page logger. The example uses the default behaviour, which

+					is to place the log console in a fixed area at the bottom of the page. However, the

+					console may be placed inside any element in the page. To do this, you may specify the ID

+					of the element (even if the page has not yet loaded) or a reference to the element itself.

+				</p>

+				<p>

+					Enter a log message below and click on one of the buttons to log

+					your message at your desired level. You can then filter by

+					log level, toggle word-wrapping and perform text and regular

+					expression searches on the log entries.

+				</p>

+				<div class="example">

+					<input type="button" value="Hide console" onclick="toggleConsole(this)" />

+					<br />

+					<input type="text" id="logText" value="Put log message here" />

+					<input type="button" value="debug" onclick="log.debug(document.getElementById('logText').value)" />

+					<input type="button" value="info" onclick="log.info(document.getElementById('logText').value)" />

+					<input type="button" value="warn" onclick="log.warn(document.getElementById('logText').value)" />

+					<input type="button" value="error" onclick="log.error(document.getElementById('logText').value)" />

+					<input type="button" value="fatal" onclick="log.fatal(document.getElementById('logText').value)" />

+					<br />

+					<input type="button" value="assert 1 equals 1" onclick="log.assert(1 === 1)" />

+					<input type="button" value="assert 1 equals 2" onclick="log.assert(1 === 2)" />

+					<br />

+					Generate <input type="text" size="5" id="numberOfLogEntries" value="50" /> random log entries

+					<input type="button" value="go" onclick="generateRandom()" />

+					<br />

+					<input type="button" value="Log exception" onclick="generateError()" />

+					<input type="button" value="Log example object" onclick="generateObjectExpansion()" />

+					<br />

+					<input type="checkbox" id="enabled" onclick="log4javascript.setEnabled(this.checked)" checked="checked" /> <label for="enabled">logging enabled</label>

+					<br />

+					<input type="text" id="groupName" value="Group name" />

+					<input type="button" value="group" onclick="log.group(document.getElementById('groupName').value)" />

+					<input type="button" value="end group" onclick="log.groupEnd()" />

+					<br />

+					<input type="text" id="timerName" value="Example timer name" />

+					<input type="button" value="start timer" onclick="log.time(document.getElementById('timerName').value)" />

+					<input type="button" value="end timer" onclick="log.timeEnd(document.getElementById('timerName').value)" />

+				</div>

+			</div>

+			<br class="clear" />

+			<div id="log"></div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/demos/lite.html b/planetstack/core/static/log4javascript-1.4.6/demos/lite.html
new file mode 100644
index 0000000..a1d2dd3
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/demos/lite.html
@@ -0,0 +1,148 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript lite demo</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+		<script type="text/javascript" src="../js/log4javascript_lite.js"></script>

+		<script type="text/javascript">

+			// <![CDATA[

+			var	log = log4javascript.getDefaultLogger();

+			log.debug("This is debugging message from the log4javascript lite demo page");

+

+			var words = ["Boothroyd", "who", "took", "over", "two", "years",

+					"ago", "and", "continues", "to", "maintain", "that", "the",

+					"club", "are", "building", "for", "the", "future", "made",

+					"six", "changes", "and", "gave", "a", "first", "Premiership",

+					"start", "to", "on-loan", "Brazilian", "midfielder",

+					"Douglas", "Rinaldi", "Darius", "Henderson", "and", "Steve",

+					"Kabba", "were", "two", "of", "the", "players", "restored",

+					"to", "the", "home", "side", "and", "were", "responsible",

+					"for", "giving", "Chelsea", "an", "uncomfortable", "start",

+					"which", "set", "the", "pattern", "for", "the", "match"

+					];

+

+			var loaded = false;

+

+			function generateRandom() {

+				var numberOfEntries = parseInt(document.getElementById("numberOfLogEntries").value);

+				for (var i = 0; i < numberOfEntries; i++) {

+					var numberOfWords = 1 + Math.floor(10 * Math.random());

+					var entryWords = [];

+					for (var j = 0; j < numberOfWords; j++) {

+						entryWords.push(words[Math.floor(Math.random() * words.length)]);

+					}

+					var entryMessage = entryWords.join(" ");

+					var levelNum = Math.floor(Math.random() * 6);

+					switch (levelNum) {

+						case 0:

+							log.trace(entryMessage);

+							break;

+						case 1:

+							log.debug(entryMessage);

+							break;

+						case 2:

+							log.info(entryMessage);

+							break;

+						case 3:

+							log.warn(entryMessage);

+							break;

+						case 4:

+							log.error(entryMessage);

+							break;

+						case 5:

+							log.fatal(entryMessage);

+							break;

+					}

+				}

+			}

+

+			function generateObjectExpansion() {

+				var debugObj = {

+					a: {

+						b: "stuff",

+						c: 3,

+						d: {

+							e: ["a", "b", "c"]

+						}

+					},

+					f: "Things",

+					g: 5

+				};

+				log.debug(debugObj);

+			}

+

+			function generateError() {

+				try {

+					throw new Error("Made up error");

+				} catch (ex) {

+					log.error("Logging an error!", ex);

+				}

+			}

+			// ]]>

+		</script>

+	</head>

+	<body onload="loaded = true; document.getElementById('enabled').checked = true;">

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="/docs/index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="../docs/index.html">docs</a>

+					| <a class="navitem" href="../docs/quickstart.html">quick start</a>

+					| <a class="navitem" href="../docs/manual.html">manual</a>

+					| <a class="navitem" href="index.html">demos</a>

+					| <a class="navitem" href="http://www.timdown.co.uk/log4javascript" target="_blank">website</a>

+				</div>

+				<h1>log4javascript lite demo</h1>

+				<p>

+					<em><strong>NB.</strong> Since the demo below uses pop-up windows, you will

+					need to disable any pop-up blockers you may have for it to work.</em>

+				</p>

+				<p>

+					This demo demonstrates the lite edition of log4javascript.

+				</p>

+				<p>

+					Enter a log message below and click on one of the buttons to log

+					your message at your desired level.

+				</p>

+				<div class="example">

+					<input type="text" id="logText" value="Put log message here" />

+					<input type="button" value="trace" onclick="log.trace(document.getElementById('logText').value)" />

+					<input type="button" value="debug" onclick="log.debug(document.getElementById('logText').value)" />

+					<input type="button" value="info" onclick="log.info(document.getElementById('logText').value)" />

+					<input type="button" value="warn" onclick="log.warn(document.getElementById('logText').value)" />

+					<input type="button" value="error" onclick="log.error(document.getElementById('logText').value)" />

+					<input type="button" value="fatal" onclick="log.fatal(document.getElementById('logText').value)" />

+					<br />

+					Generate <input type="text" size="5" id="numberOfLogEntries" value="50" /> random log entries

+					<input type="button" value="go" onclick="generateRandom()" />

+					<br />

+					<input type="button" value="Log exception" onclick="generateError()" />

+					<input type="button" value="Log example object" onclick="generateObjectExpansion()" />

+					<br />

+					<input type="checkbox" id="enabled" onclick="log4javascript.setEnabled(this.checked)" checked="checked" /> <label for="enabled">logging enabled</label>

+					<br />

+				</div>

+			</div>

+			<br class="clear" />

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/backwardsincompatibilities.html b/planetstack/core/static/log4javascript-1.4.6/docs/backwardsincompatibilities.html
new file mode 100644
index 0000000..f212fd4
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/docs/backwardsincompatibilities.html
@@ -0,0 +1,90 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - backwards incompatibilities in version 1.4</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="/index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="index.html">docs</a>

+					| <a class="navitem" href="quickstart.html">quick start</a>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>Backwards incompatibilities in log4javascript 1.4</h1>

+				<ul>

+					<li>

+						Loggers are now hierarchical. This means logger names containing full stops have

+						special meaning. For example, from version 1.4 the logger named <code>myapp.ajax</code>

+						by default inherits all the appenders of the logger named <code>myapp</code>, while

+						prior to version 1.4 these loggers would be entirely independent;

+					</li>

+					<li>

+						The signature of the <code>log</code> method of <code>Logger</code> has changed.

+						However, you should not use this method directly; instead, use one of the level-specific

+						wrapper functions (<code>debug</code>, <code>info</code>, <code>error</code> etc.);

+					</li>

+					<li>

+						Appenders can no longer be configured via constructor parameters. Instead you must use

+						setter methods;

+					</li>

+					<li>

+						The format of requests sent via <code><a href="manual.html#ajaxappender">AjaxAppender</a></code>

+						has changed when using <code><a href="manual.html#jsonlayout">JsonLayout</a></code> or

+						<code><a href="manual.html#xmllayout">XmlLayout</a></code>: the formatted log messages are sent

+						as a name-value pair (with default name <code>data</code>) rather than a single unencoded string;

+					</li>

+					<li>

+						All timestamps returned by <code><a href="manual.html#xmllayout">XmlLayout</a></code>,

+						<code><a href="manual.html#jsonlayout">JsonLayout</a></code> and

+						<code><a href="manual.html#httppostdatlayout">HttpPostDataLayout</a></code> are

+						now measured in milliseconds since January 1st 1970 (previously they were returned

+						as seconds since January 1st 1970);

+					</li>

+					<li>

+						The constructors for <a href="manual.html#jsonlayout">JsonLayout</a> and

+						<a href="manual.html#httppostdatlayout">HttpPostDataLayout</a> have changed; the property names

+						used for the properties of the logging event are now set via <code>setKeys</code> rather than

+						in the constructor;

+					</li>

+					<li>

+						<code>setReadable</code> has been removed from <a href="manual.html#jsonlayout">JsonLayout</a>.

+						The <code>readable</code> property should now be set via the constructor;

+					</li>

+					<li>

+						<code>addErrorListener</code> and <code>removeErrorListener</code> removed from

+						the <code>log4javascript</code> object and replaced with the more generic

+						<code><a href="manual.html#log4javascriptaddeventlistener">addEventListener</a></code>

+						and <code>removeEventListener</code> methods. The listener functions are passed

+						different parameters.

+					</li>

+				</ul>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/distribution.html b/planetstack/core/static/log4javascript-1.4.6/docs/distribution.html
new file mode 100644
index 0000000..8f6cdfd
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/docs/distribution.html
@@ -0,0 +1,87 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en" >

+	<head>

+		<title>log4javascript 1.4 distribution</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="../index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="index.html">docs</a>

+					| <a class="navitem" href="quickstart.html">quick start</a>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript 1.4 distribution</h1>

+				<p>

+					From version 1.4 the distribution includes three different editions of log4javascript:

+				</p>

+				<ul>

+					<li>

+						<div><strong>Standard Edition</strong></div>

+						<p>

+							Equivalent to log4javascript from earlier versions and suitable for general JavaScript

+							debugging and logging (including via Ajax).

+						</p>

+					</li>

+					<li>

+						<div><strong>Production Edition</strong></div>

+						<p>

+							Designed for use in production systems where the focus is solely on logging JavaScript

+							messages back to the server. Consequently this edition omits all appenders except

+							<a href="manual.html#ajaxappender">AjaxAppender</a>, resulting in a drastically reduced

+							file size compared to the standard edition.

+						</p>

+					</li>

+					<li>

+						<div><strong>Lite Edition</strong></div>

+						<p>

+							A lightweight version of log4javascript for quick page debugging. Included is a single logger

+							using a basic pop-up window appender with a fixed layout.

+						</p>

+					</li>

+				</ul>

+				<p>

+					Each edition comes in compressed and uncompressed versions. The compressed version is

+					functionally identical to the uncompressed version but has had whitespace and comments removed

+					and therefore downloads more quickly.

+				</p>

+				<p>

+					Each edition also comes with a stub version. This contains dummy implementations of all

+					log4javacript objects and methods in the public API, making it ideal for production environments

+					where logging is not required. Replacing the main log4javascript script file with this file

+					means that log calls may be left in production code. Compressed and uncompressed versions of

+					each stub are included.

+				</p>

+				<p>

+					Finally, each edition comes with a suite of unit tests, available as HTML pages in the

+					<code>test/</code> directory. Note that these tests crash old versions (pre-3.1) of Safari. Sorry.

+				</p>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/index.html b/planetstack/core/static/log4javascript-1.4.6/docs/index.html
new file mode 100644
index 0000000..d3b3ac2
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/docs/index.html
@@ -0,0 +1,190 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript documentation</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="../index.html">log4javascript</a></h1>

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <span class="navitem">docs</span>

+					| <a class="navitem" href="quickstart.html">quick start</a>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+			</div>

+			<div id="content">

+				<h1>log4javascript 1.4 documentation</h1>

+				<div id="links">

+					<h2>Links</h2>

+					<ul>

+						<li><a href="quickstart.html">Quick start</a></li>

+						<li><a href="distribution.html">Details of the log4javascript distribution</a></li>

+						<li><a href="backwardsincompatibilities.html">Backwards incompatibilities</a></li>

+						<li><a href="whatsnew.html">What's new in this release</a></li>

+						<li><a href="../changelog.txt">Change log</a></li>

+						<li><a href="manual.html">log4javascript manual</a></li>

+						<li><a href="lite.html">log4javascript Lite</a></li>

+						<li><a href="manual_lite.html">log4javascript Lite manual</a></li>

+						<li><a href="../demos/basic.html">Basic demo</a></li>

+						<li><a href="../demos/ajax.html">Ajax demo</a></li>

+					</ul>

+				</div>

+				<div id="contents">

+					<h2>Contents</h2>

+					<ul>

+						<li><a href="#whatitis">What it is</a></li>

+						<li><a href="#whofor">Who it's for</a></li>

+						<li><a href="#previousversions">Note on previous versions</a></li>

+						<li><a href="#features">Features</a></li>

+						<li><a href="#browsers">Browser support</a></li>

+						<li><a href="#licence">Licence</a></li>

+						<li><a href="#furtherreading">Further reading</a></li>

+					</ul>

+				</div>

+				<div id="whatitis">

+					<h2>What it is</h2>

+					<p>

+						log4javascript is a JavaScript logging framework based on the Java

+						logging framework <a href="http://logging.apache.org/log4j/docs/index.html"

+						title="log4j home page (opens in new window)" target="_blank">log4j</a>.

+					</p>

+					<p>

+						log4javascript implements a subset of log4j (primarily loggers, appenders

+						and layouts) and has a few convenience methods of its own for

+						quick JavaScript development. It can be used to debug JavaScript

+						applications of all sizes, including Ajax applications.

+					</p>

+					<p>

+						If you just want to start using it, try the <a href="quickstart.html">quickstart

+						tutorial</a>.

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="whofor">

+					<h2>Who it's for</h2>

+					<p>

+						log4javascript is aimed at JavaScript developers.

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="previousversions">

+					<h2>Note on previous versions</h2>

+					<p>

+						Documentation for previous versions of log4javascript are not available here.

+						However, documentation is bundled with every previous version, all of which

+						are <a href="http://sourceforge.net/projects/log4javascript"

+							target="_blank" title="Download (opens in new window)">available to download</a>.

+					</p>

+				</div>

+				<div id="features">

+					<h2>Features</h2>

+					<ul>

+						<li>can be initialized with one JavaScript include and one line of code;</li>

+						<li>

+							by default logs to a pop-up console window with powerful search (including

+							regular expression) and filtering features. This console window can also

+							be used inline as an iframe in the main page;

+						</li>

+						<li>

+							can send log messages to the server via HTTP (Ajax, if you like);

+						</li>

+						<li>

+							highly configurable using familiar methods from log4j, including the

+							powerful <code><a href="manual.html#patternlayout">PatternLayout</a></code>

+							which gives the developer complete control over the format of the log messages.

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="browsers">

+					<h2>Browser support</h2>

+					<h3>Fully supported browsers:</h3>

+					<ul>

+						<li>All versions Firefox back to 0.6</li>

+						<li>Other Mozilla-based browsers, as far back as Netscape 7</li>

+						<li>Internet Explorer 5 and higher for Windows</li>

+						<li>Safari 1.3 and higher (untested on earlier versions)</li>

+						<li>Opera 8.01 and higher (pre- version 9 browsers have a rendering

+							bug related to scrolling that affects searching in PopUpAppender and InPageAppender)</li>

+						<li>Konqueror 3.4.3 and higher (untested on earlier versions)</li>

+						<li>Google Chrome</li>

+					</ul>

+					<h3>Partially supported browsers:</h3>

+					<ul>

+						<li>Older Mozilla-based browsers, e.g. Netscape 6.2 (generally OK except for

+							display problems searching and filtering PopUpAppender and InPageAppender)</li>

+						<li>Opera 7.0 - 8.0 (InPageAppender not supported until version 7.5, plus some display

+							problems searching PopUpAppender and InPageAppender. AjaxAppender not supported at all)</li>

+					</ul>

+					<h3>Unsupported browsers:</h3>

+					<ul>

+						<li>

+							Internet Explorer for Mac. There are no plans to make log4javascript work

+							in this browser.

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="licence">

+					<h2>Licence</h2>

+					<p>

+						log4javascript is licenced under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+							title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+						Version 2.0</a>. The Apache website has <a href="http://www.apache.org/foundation/licence-FAQ.html#WhatDoesItMEAN"

+							title="View licence (opens in new window)" target="_blank">more details</a>.

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="furtherreading">

+					<h2>Further reading</h2>

+					<p>

+						In order to gain an understanding of the ideas behind log4j and therefore log4javascript,

+						I highly recommend reading the <a href="http://logging.apache.org/log4j/docs/manual.html">short

+						introduction to log4j</a> from the log4j website. log4javascript borrows heavily from

+						log4j but does not carry over all its concepts - for example, Filters and Renderers are not

+						implemented.

+					</p>

+					<p>

+						<a href="manual.html">The full log4javascript manual</a>

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/lite.html b/planetstack/core/static/log4javascript-1.4.6/docs/lite.html
new file mode 100644
index 0000000..11b4684
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/docs/lite.html
@@ -0,0 +1,182 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en" >

+	<head>

+		<title>log4javascript 1.4 Lite</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+		<style type="text/css">

+			.visibleifabletocopy {

+				display: none;

+			}

+			

+			body.abletocopy .visibleifabletocopy {

+				display: block;

+			}

+		</style>

+		<script type="text/javascript">

+			function copyCode() {

+				if (window.clipboardData && clipboardData.setData) {

+					clipboardData.setData("Text", code);

+					alert("Code copied to clipboard.")

+				}

+			}

+			

+			var code;

+			

+			window.onload = function() {

+				var textArea = document.getElementById("codetextarea");

+				code = textArea.value;

+				textArea.select(); 

+				if (window.clipboardData && clipboardData.setData) {

+					document.body.className = "abletocopy";

+				}

+			};

+		</script>

+		<link rel="stylesheet" type="text/css" media="screen,print" href="lite.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="../index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="index.html">docs</a>

+					| <a class="navitem" href="quickstart.html">quick start</a>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript 1.4 Lite</h1>

+				<h2>Contents</h2>

+				<ul>

+					<li><a href="#intro">Introduction</a></li>

+					<li><a href="#code">Code</a></li>

+					<li><a href="#api">API</a></li>

+				</ul>

+				<div id="intro">

+					<h2>Introduction</h2>

+					<p>

+						log4javascript Lite is designed to be a basic, lightweight, cross-browser logging tool. It

+						provides functions to log messages of different severity to a pop-up window using the exactly

+						the same syntax as log4javascript.

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="code">

+					<h2>Code</h2>

+					<p>

+						You can copy the code for log4javascript Lite below:

+					</p>

+					<textarea id="codetextarea" cols="80" rows="10">

+if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}

+this.length--;return firstItem;}};}

+var log4javascript;(function(){var newLine="\r\n";function Log4JavaScript(){}

+log4javascript=new Log4JavaScript();log4javascript.version="1.4.6";log4javascript.edition="log4javascript_lite";function getExceptionMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}else{return String(ex);}}

+function getUrlFileName(url){var lastSlashIndex=Math.max(url.lastIndexOf("/"),url.lastIndexOf("\\"));return url.substr(lastSlashIndex+1);}

+function getExceptionStringRep(ex){if(ex){var exStr="Exception: "+getExceptionMessage(ex);try{if(ex.lineNumber){exStr+=" on line number "+ex.lineNumber;}

+if(ex.fileName){exStr+=" in file "+getUrlFileName(ex.fileName);}}catch(localEx){}

+if(showStackTraces&&ex.stack){exStr+=newLine+"Stack trace:"+newLine+ex.stack;}

+return exStr;}

+return null;}

+function isError(err){return(err instanceof Error);}

+function bool(obj){return Boolean(obj);}

+var enabled=(typeof log4javascript_disabled!="undefined")&&log4javascript_disabled?false:true;log4javascript.setEnabled=function(enable){enabled=bool(enable);};log4javascript.isEnabled=function(){return enabled;};var showStackTraces=false;log4javascript.setShowStackTraces=function(show){showStackTraces=bool(show);};var Level=function(level,name){this.level=level;this.name=name;};Level.prototype={toString:function(){return this.name;},equals:function(level){return this.level==level.level;},isGreaterOrEqual:function(level){return this.level>=level.level;}};Level.ALL=new Level(Number.MIN_VALUE,"ALL");Level.TRACE=new Level(10000,"TRACE");Level.DEBUG=new Level(20000,"DEBUG");Level.INFO=new Level(30000,"INFO");Level.WARN=new Level(40000,"WARN");Level.ERROR=new Level(50000,"ERROR");Level.FATAL=new Level(60000,"FATAL");Level.OFF=new Level(Number.MAX_VALUE,"OFF");log4javascript.Level=Level;function Appender(){var getConsoleHtmlLines=function(){return['<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">','<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">','<head>','<title>log4javascript</title>','<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />','<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->','<meta http-equiv="X-UA-Compatible" content="IE=7" />','<script type="text/javascript">','//<![CDATA[','var loggingEnabled=true;var messagesBeforeDocLoaded=[];function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}','function setLoggingEnabled(enable){loggingEnabled=enable;}','function scrollToLatestEntry(){var l=getLogContainer();if(typeof l.scrollTop!="undefined"){var latestLogEntry=l.lastChild;if(latestLogEntry){l.scrollTop=l.scrollHeight;}}}','function log(logLevel,formattedMessage){if(loggingEnabled){if(loaded){doLog(logLevel,formattedMessage);}else{messagesBeforeDocLoaded.push([logLevel,formattedMessage]);}}}','function doLog(logLevel,formattedMessage){var logEntry=document.createElement("div");logEntry.appendChild(document.createTextNode(formattedMessage));logEntry.className="logentry "+logLevel.name;getLogContainer().appendChild(logEntry);scrollToLatestEntry();}','function mainPageReloaded(){var separator=document.createElement("div");separator.className="separator";separator.innerHTML="&nbsp;";getLogContainer().appendChild(separator);}','var loaded=false;var logLevels=["DEBUG","INFO","WARN","ERROR","FATAL"];window.onload=function(){setLogContainerHeight();toggleLoggingEnabled();for(var i=0;i<messagesBeforeDocLoaded.length;i++){doLog(messagesBeforeDocLoaded[i][0],messagesBeforeDocLoaded[i][1]);}','messagesBeforeDocLoaded=[];loaded=true;setTimeout(setLogContainerHeight,20);};function getLogContainer(){return $("log");}','function clearLog(){getLogContainer().innerHTML="";}','function $(id){return document.getElementById(id);}','function getWindowHeight(){if(window.innerHeight){return window.innerHeight;}else if(document.documentElement&&document.documentElement.clientHeight){return document.documentElement.clientHeight;}else if(document.body){return document.body.clientHeight;}','return 0;}','function getChromeHeight(){return $("toolbar").offsetHeight;}','function setLogContainerHeight(){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";getLogContainer().style.height=""+','Math.max(0,windowHeight-getChromeHeight())+"px";}','window.onresize=function(){setLogContainerHeight();};','//]]>','</scr' + 'ipt>','<style type="text/css">','body{background-color:white;color:black;padding:0;margin:0;font-family:tahoma,verdana,arial,helvetica,sans-serif;overflow:hidden}div#toolbar{border-top:solid #ffffff 1px;border-bottom:solid #aca899 1px;background-color:#f1efe7;padding:3px 5px;font-size:68.75%}div#toolbar input.button{padding:0 5px;font-size:100%}div#log{font-family:Courier New,Courier;font-size:75%;width:100%;overflow:auto;clear:both}*.logentry{overflow:visible;white-space:pre}*.TRACE{color:#666666}*.DEBUG{color:green}*.INFO{color:#000099}*.WARN{color:#999900}*.ERROR{color:red}*.FATAL{color:#660066}div#log div.separator{background-color:#cccccc;margin:5px 0;line-height:1px}','</style>','</head>','<body id="body">','<div id="toolbar">','Options:','<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" class="stateful" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Enable logging</label>','<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="stateful button" title="Clear all log messages"  />','<input type="button" id="closeButton" value="Close" onclick="window.close()" class="stateful button" title="Close the window" />','</div>','<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>','</body>','</html>'];};var popUp=null;var popUpsBlocked=false;var popUpClosed=false;var popUpLoaded=false;var complainAboutPopUpBlocking=true;var initialized=false;var isSupported=true;var width=600;var height=400;var focusPopUp=false;var queuedLoggingEvents=new Array();function isLoaded(win){try{return bool(win.loaded);}catch(ex){return false;}}

+function finalInit(){popUpLoaded=true;appendQueuedLoggingEvents();}

+function writeHtml(doc){var lines=getConsoleHtmlLines();doc.open();for(var i=0,len=lines.length;i<len;i++){doc.writeln(lines[i]);}

+doc.close();}

+function pollConsoleWindow(){function pollConsoleWindowLoaded(){if(popUpLoaded){clearInterval(poll);}else if(bool(popUp)&&isLoaded(popUp)){clearInterval(poll);finalInit();}}

+var poll=setInterval(pollConsoleWindowLoaded,100);}

+function init(){var windowProperties="width="+width+",height="+height+",status,resizable";var windowName="log4javascriptLitePopUp"+location.host.replace(/[^a-z0-9]/gi,"_");popUp=window.open("",windowName,windowProperties);popUpClosed=false;if(popUp){if(isLoaded(popUp)){popUp.mainPageReloaded();finalInit();}else{writeHtml(popUp.document);if(isLoaded(popUp)){finalInit();}else{pollConsoleWindow();}}}else{isSupported=false;if(complainAboutPopUpBlocking){alert("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");}}

+initialized=true;}

+function safeToAppend(){if(!popUpsBlocked&&!popUpClosed){if(popUp.closed){popUpClosed=true;return false;}

+if(!popUpLoaded&&popUp.loaded){popUpLoaded=true;}}

+return!popUpsBlocked&&popUpLoaded&&!popUpClosed;}

+function padWithZeroes(num,len){var str=""+num;while(str.length<len){str="0"+str;}

+return str;}

+function padWithSpaces(str,len){while(str.length<len){str+=" ";}

+return str;}

+this.append=function(loggingEvent){if(!initialized){init();}

+queuedLoggingEvents.push(loggingEvent);if(safeToAppend()){appendQueuedLoggingEvents();}};function appendQueuedLoggingEvents(){if(safeToAppend()){while(queuedLoggingEvents.length>0){var currentLoggingEvent=queuedLoggingEvents.shift();var date=currentLoggingEvent.timeStamp;var formattedDate=padWithZeroes(date.getHours(),2)+":"+

+padWithZeroes(date.getMinutes(),2)+":"+padWithZeroes(date.getSeconds(),2);var formattedMessage=formattedDate+" "+padWithSpaces(currentLoggingEvent.level.name,5)+" - "+currentLoggingEvent.getCombinedMessages();var throwableStringRep=currentLoggingEvent.getThrowableStrRep();if(throwableStringRep){formattedMessage+=newLine+throwableStringRep;}

+popUp.log(currentLoggingEvent.level,formattedMessage);}

+if(focusPopUp){popUp.focus();}}}}

+log4javascript.Appender=Appender;function Logger(){var appender=new Appender();var loggerLevel=Level.ALL;this.log=function(level,params){if(enabled&&level.isGreaterOrEqual(this.getLevel())){var exception;var finalParamIndex=params.length-1;var lastParam=params[params.length-1];if(params.length>1&&isError(lastParam)){exception=lastParam;finalParamIndex--;}

+var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];}

+var loggingEvent=new LoggingEvent(this,new Date(),level,messages,exception);appender.append(loggingEvent);}};this.setLevel=function(level){loggerLevel=level;};this.getLevel=function(){return loggerLevel;};}

+Logger.prototype={trace:function(){this.log(Level.TRACE,arguments);},debug:function(){this.log(Level.DEBUG,arguments);},info:function(){this.log(Level.INFO,arguments);},warn:function(){this.log(Level.WARN,arguments);},error:function(){this.log(Level.ERROR,arguments);},fatal:function(){this.log(Level.FATAL,arguments);},isEnabledFor:function(level){return level.isGreaterOrEqual(this.getLevel());},isTraceEnabled:function(){return this.isEnabledFor(Level.TRACE);},isDebugEnabled:function(){return this.isEnabledFor(Level.DEBUG);},isInfoEnabled:function(){return this.isEnabledFor(Level.INFO);},isWarnEnabled:function(){return this.isEnabledFor(Level.WARN);},isErrorEnabled:function(){return this.isEnabledFor(Level.ERROR);},isFatalEnabled:function(){return this.isEnabledFor(Level.FATAL);}};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=new Logger();}

+return defaultLogger;};log4javascript.getLogger=log4javascript.getDefaultLogger;var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger();nullLogger.setLevel(Level.OFF);}

+return nullLogger;};var LoggingEvent=function(logger,timeStamp,level,messages,exception){this.logger=logger;this.timeStamp=timeStamp;this.level=level;this.messages=messages;this.exception=exception;};LoggingEvent.prototype={getThrowableStrRep:function(){return this.exception?getExceptionStringRep(this.exception):"";},getCombinedMessages:function(){return(this.messages.length===1)?this.messages[0]:this.messages.join(newLine);}};log4javascript.LoggingEvent=LoggingEvent;window.log4javascript=log4javascript;})();

+</textarea>

+					<p class="visibleifabletocopy">

+						Press this button to copy the code to the clipboard:

+						<input type="button" value="Copy" onclick="copyCode()" />

+					</p>

+					<p>

+						You can either paste the above code inside a script tag:

+					</p>

+					<pre class="code">

+&lt;script type="text/javascript"&gt;

+	... [Code here]...

+&lt;/script&gt;

+</pre>

+					<p>

+						 ... or include the <code>log4javascript_lite.js</code> included in the distribution:

+					</p>

+					<pre class="code">

+&lt;script type="text/javascript" src="log4javascript_lite.js"&gt;&lt;/script&gt;

+</pre>

+					<pre class="code">

+&lt;script type="text/javascript"&gt;

+	var log = log4javascript.getDefaultLogger();

+&lt;/script&gt;

+</pre>

+					<p>

+						Using log4javascript Lite is identical to using log4javascript with its default logger:

+					</p>

+					<pre class="code">

+&lt;script type="text/javascript"&gt;

+	var log = log4javascript.getDefaultLogger();

+	log.debug("What's going on here then?");

+&lt;/script&gt;

+</pre>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="api">

+					<h2>API</h2>

+					<p>

+						The functions available in log4javascript Lite make up a small subset of those provided

+						by log4javascript proper. Each function is <strong>named and called identically to the equivalent

+						function in log4javascript</strong>. Full details can be found in the

+						<a href="manual_lite.html">log4javascript Lite manual</a>.

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/manual.html b/planetstack/core/static/log4javascript-1.4.6/docs/manual.html
new file mode 100644
index 0000000..defac9c
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/docs/manual.html
@@ -0,0 +1,3198 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript 1.4 manual</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="index.html">docs</a>

+					| <a class="navitem" href="quickstart.html">quick start</a>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript 1.4 manual</h1>

+				<h2>Contents</h2>

+				<ul>

+					<li><a href="#intro">Introduction</a></li>

+					<li><a href="#noteaboutlog4javascript">Note about the log4javascript object</a></li>

+					<li>

+						<a href="#loggersappenderslayoutslevels">Loggers, appenders, layouts and levels</a>

+						<ul>

+							<li><a href="#configuration">Configuring appenders</a></li>

+							<li><a href="#loggersappenderslayoutslevelsexample">Example</a></li>

+						</ul>

+					</li>

+					<li><a href="#log4javascript">log4javascript static properties/methods</a></li>

+					<li><a href="#levels">Levels</a></li>

+					<li><a href="#loggers">Loggers</a></li>

+					<li>

+						<a href="#appenders">Appenders</a>

+						<ul>

+							<li><a href="#appender">Appender</a></li>

+							<li><a href="#alertappender">AlertAppender</a></li>

+							<li><a href="#ajaxappender">AjaxAppender</a></li>

+							<li><a href="#popupappender">PopUpAppender</a></li>

+							<li><a href="#inpageappender">InPageAppender</a></li>

+							<li><a href="#browserconsoleappender">BrowserConsoleAppender</a></li>

+						</ul>

+					</li>

+					<li>

+						<a href="#layouts">Layouts</a>

+						<ul>

+							<li><a href="#layout">Layout</a></li>

+							<li><a href="#nulllayout">NullLayout</a></li>

+							<li><a href="#simplelayout">SimpleLayout</a></li>

+							<li><a href="#patternlayout">PatternLayout</a></li>

+							<li><a href="#xmllayout">XmlLayout</a></li>

+							<li><a href="#jsonlayout">JsonLayout</a></li>

+							<li><a href="#httppostdatalayout">HttpPostDataLayout</a></li>

+						</ul>

+					</li>

+					<li><a href="#enabling">Enabling / disabling log4javascript</a></li>

+					<li>

+						<a href="#errorhandling">log4javascript error handling</a>

+						<ul>

+							<li><a href="#loglog">LogLog</a></li>

+						</ul>

+					</li>

+					<li><a href="#differences">Differences between log4javascript and log4j</a></li>

+				</ul>

+				<div id="intro">

+					<h2>Introduction</h2>

+					<p>

+						Anyone who has done a reasonable amount of JavaScript development will be

+						familiar with <code>alert</code> as a means of debugging. For

+						a small script, it works fine. But for anything of greater complexity than,

+						say, a rollover script its shortcomings become apparent. The most obvious problem

+						is the endless clicking of 'OK'. Another problem is that for a page

+						heavily reliant on events generated from user actions, alerts

+						can actually alter the way the page behaves. One final problem is infinite loops:

+						without alerts, the browser will notice that the script has messed

+						up and will offer the user the chance to stop the script running. With an

+						alert inside an infinite loop, you're forced to kill the browser.

+					</p>

+					<p>

+						At the other end of the scale there is

+						<a href="http://www.mozilla.org/projects/venkman/" target="_blank">Venkman</a>,

+						a full-on JavaScript debugger for Mozilla-based browsers such as Firefox. Here

+						I have to confess that I simply have not put in the time to learn how to make

+						it work well for me and I suspect I am not alone.

+					</p>

+					<p>

+						Nowadays, easily the best option for day-to-day JavaScript development is the brilliant

+						<a href="http://www.getfirebug.com" title="Firebug home page (opens in new window)"

+						   target="_blank">Firebug</a>, a Firefox plugin with built-in debugger, console, logging,

+						and profiler. It's a seriously impressive tool but by its very nature as a Firefox

+						plugin can only be used in one of the typical target browsers for mainstream web

+						development.

+					</p>

+					<p>

+						log4javascript was originally written as a cross-browser tool to ease the pain of JavaScript

+						debugging without the time investment required to use a debugger effectively. It requires

+						only a JavaScript include and one line of code to initialize with default settings.

+						Having for several years used log4j and its .NET port log4net, it was natural for me to

+						base it on log4j.

+					</p>

+					<p>

+						log4javascript is by no means the only JavaScript logging framework out there.

+						It is not even the only JavaScript implementation of log4j. It turns out the name

+						log4javascript is used by another JavaScript logging framework, and that the name log4js is

+						used by at least two other pieces of software; this version of log4javascript is unrelated

+						to any of those.

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="noteaboutlog4javascript">

+					<h2>Note about the log4javascript object</h2>

+					<p>

+						All of log4javascript's instantiable classes are accessible via the log4javascript object, which

+						acts as a namespace. Therefore references to all class names must be preceded with "log4javascript.".

+						For example:

+					</p>

+					<p>

+						<code>var popUpAppender = new log4javascript.PopUpAppender();</code>

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="loggersappenderslayoutslevels">

+					<h2>Loggers, Appenders, Layouts and Levels</h2>

+					<p>

+						A <em>logger</em> in log4javascript is the object on which log calls are

+						made. A logger may be assigned zero or more <em>appenders</em>.

+						An appender is an object that actually does the logging: for example,

+						a <code><a href="#popupappender">PopUpAppender</a></code> logs messages to

+						a pop-up console window while an <code><a href="#ajaxappender">AjaxAppender</a></code>

+						uses HTTP to send log messages back to the server. Each appender is assigned

+						a <em>layout</em>, which is responsible for formatting log messages that

+						are passed to an appender.

+					</p>

+					<p>

+						Every log message has a <em>level</em>. This is the severity of the message.

+						Available levels are <code>TRACE</code>, <code>DEBUG</code>, <code>INFO</code>,

+						<code>WARN</code>, <code>ERROR</code> and <code>FATAL</code> - these correspond to

+						the logging methods <code>trace</code>, <code>debug</code>, <code>info</code>,

+						<code>warn</code>, <code>error</code> and <code>fatal</code> of <code>Logger</code>.

+						Levels are ordered as follows: <code>TRACE</code> &lt; <code>DEBUG</code> &lt;

+						<code>INFO</code> &lt; <code>WARN</code> &lt; <code>ERROR</code> &lt;

+						<code>FATAL</code>. This means the <code>FATAL</code> is the most severe and

+						<code>TRACE</code> the least. Also included are levels called <code>ALL</code>

+						and <code>OFF</code> intended to enable or disable all logging respectively.

+					</p>

+					<p>

+						Both loggers and appenders also have threshold levels (by default, <code>DEBUG</code>

+						for loggers and <code>ALL</code> for appenders).

+						Setting a level to either a logger or an appender disables log messages of severity

+						lower than that level. For instance, if a level of <code>INFO</code> is set on a

+						logger then only log messages of severity <code>INFO</code> or greater will be logged,

+						meaning <code>DEBUG</code> and <code>TRACE</code> messages will not be logged. If the

+						same logger had two appenders, one of level <code>DEBUG</code> and one of level

+						<code>WARN</code> then the first appender will still only log messages of

+						<code>INFO</code> or greater while the second appender will only log messages of level

+						<code>WARN</code> or greater.

+					</p>

+					<p>

+						This allows the developer fine control over which messages get logged where.

+					</p>

+					<div id="configuration">

+						<h3>Configuring appenders</h3>

+						<p>

+							From version 1.4, <strong>configuring appenders is only possible via configuration

+							methods</strong>. As the number of configuration options increases it becomes increasingly

+							undesirable to use constructor parameters, so support for it has been dropped.

+						</p>

+					</div>

+					<div id="loggersappenderslayoutslevelsexample">

+						<h3>Example</h3>

+						<p>

+							<strong>NB.</strong> The Ajax side of this example relies on having

+							server-side processing in place.

+						</p>

+						<p>

+							First, log4javascript is initialized, and a logger (actually the

+							anonymous logger) is assigned to a variable called <code>log</code>:

+						</p>

+						<pre class="code">

+&lt;script type="text/javascript" src="log4javascript.js"&gt;&lt;/script&gt;

+&lt;script type="text/javascript"&gt;

+	//&lt;![CDATA[

+	var log = log4javascript.getLogger();

+</pre>

+						<p>

+							<code>log</code> does not yet have any appenders, so a call to <code>log.debug()</code>

+							will do nothing as yet. For this example we will use a

+							<code><a href="#popupappender">PopUpAppender</a></code> for debugging purposes.

+							Since the lifespan of the messages displayed in the pop-up is only going to be the

+							same as that of the window, a <code><a href="#patternlayout">PatternLayout</a></code>

+							is used that displays the time of the message and not the date (note that this is

+							also true of PopUpAppender's default layout). The format of the string passed into

+							PatternLayout is explained <a href="#patternlayout">below</a>.

+						</p>

+						<pre class="code">

+	var popUpAppender = new log4javascript.PopUpAppender();

+	var popUpLayout = new log4javascript.PatternLayout("%d{HH:mm:ss} %-5p - %m%n");

+	popUpAppender.setLayout(popUpLayout);

+	log.addAppender(popUpAppender);

+</pre>

+						<p>

+							Suppose that we also want to send log messages to the server, but limited to

+							error messages only. To achieve this we use an

+							<code><a href="#ajaxappender">AjaxAppender</a></code>. Note that if no layout is

+							specified then for convenience a default layout is used; in the case of

+							AjaxAppender, that is <code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>,

+							which formats log messages as a standard HTTP POST string from which a simple

+							server-side script (not provided with log4javascript) will be able to extract

+							posted parameters. This is fine for our purposes:

+						</p>

+						<pre class="code">

+	var ajaxAppender = new log4javascript.AjaxAppender("myloggingservlet.do");

+	ajaxAppender.setThreshold(log4javascript.Level.<code>ERROR</code>);

+	log.addAppender(ajaxAppender);

+</pre>

+						<p>

+							Finally, some test log messages and the closing script tag:

+						</p>

+						<pre class="code">

+	log.debug("Debugging message (appears in pop-up)");

+	log.error("Error message (appears in pop-up and in server log)");

+	//]]&gt;

+&lt;/script&gt;

+</pre>

+						<p>

+							The full script:

+						</p>

+						<pre class="code">

+&lt;script type="text/javascript" src="log4javascript.js"&gt;&lt;/script&gt;

+&lt;script type="text/javascript"&gt;

+	//&lt;![CDATA[

+	var log = log4javascript.getLogger();

+	var popUpAppender = new log4javascript.PopUpAppender();

+	var popUpLayout = new log4javascript.PatternLayout("%d{HH:mm:ss} %-5p - %m%n");

+	popUpAppender.setLayout(popUpLayout);

+	log.addAppender(popUpAppender);

+	var ajaxAppender = new log4javascript.AjaxAppender("myloggingservlet.do");

+	ajaxAppender.setThreshold(log4javascript.Level.ERROR);

+	log.addAppender(ajaxAppender);

+	log.debug("Debugging message (appears in pop-up)");

+	log.error("Error message (appears in pop-up and in server log)");

+	//]]&gt;

+&lt;/script&gt;

+</pre>

+						<p>

+							<a href="../examples/example_manual.html" title="View example (opens in new window)"

+								target="_blank">See this example in action</a> (opens in new window)

+						</p>

+					</div>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="log4javascript">

+					<h2>log4javascript static properties/methods</h2>

+					<h4>Properties</h4>

+					<ul class="propertieslist">

+						<li class="property">

+							<div class="name">version</div>

+							<div class="summary">

+								The version number of your copy of log4javascript.

+							</div>

+						</li>

+						<li class="property">

+							<div class="name">edition</div>

+							<div class="summary">

+								The edition of your copy of log4javascript.

+							</div>

+						</li>

+						<li class="property">

+							<div class="name">logLog</div>

+							<div class="summary">

+								log4javascript's internal logging object. <a href="#loglog">See below for more details</a>.

+							</div>

+						</li>

+					</ul>

+					<h4>Methods</h4>

+					<ul class="propertieslist">

+						<li class="method">

+							<div class="name">getLogger</div>

+							<div class="methodsignature"><code>Logger <strong>getLogger</strong>([String <em>loggerName</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">loggerName</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								<p>

+									Returns a logger with the specified name, creating it if a logger with that name does not

+									already exist. If no name is specified, a logger is returned with name <code>[anonymous]</code>, and

+									subsequent calls to <code>getLogger()</code> (with no logger name specified) will return

+									this same logger object.

+								</p>

+								<p>

+									Note that the names <code>[anonymous]</code>, <code>[default]</code>, <code>[null]</code>

+									and <code>root</code> are reserved for

+									the anonymous logger, default logger, null logger and root logger respectively.

+								</p>

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getDefaultLogger</div>

+							<div class="methodsignature"><code>Logger <strong>getDefaultLogger</strong>()</code></div>

+							<div class="summary">

+								Convenience method that returns the default logger. The default logger

+								has a single appender: a <code><a href="#popupappender">PopUpAppender</a></code>

+								with the default layout, width and height, and with <code>focusPopUp</code> set to false

+								and <code>lazyInit</code>, <code>useOldPopUp</code> and

+								<code>complainAboutPopUpBlocking</code> all set to true.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getNullLogger</div>

+							<div class="methodsignature"><code>Logger <strong>getNullLogger</strong>()</code></div>

+							<div class="summary">

+								Returns an empty logger with no appenders. Useful for disabling all logging.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getRootLogger</div>

+							<div class="methodsignature"><code>Logger <strong>getRootLogger</strong>()</code></div>

+							<div class="summary">

+								Returns the root logger from which all other loggers derive.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">resetConfiguration</div>

+							<div class="methodsignature"><code>void <strong>resetConfiguration</strong>()</code></div>

+							<div class="summary">

+								Resets the all loggers to their default level.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">setEnabled</div>

+							<div class="methodsignature"><code>void <strong>setEnabled</strong>(Boolean <em>enabled</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">enabled</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Enables or disables all logging, depending on <code>enabled</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns true or false depending on whether logging is enabled.

+							</div>

+						</li>

+						<li class="method" id="log4javascriptaddeventlistener">

+							<div class="name">addEventListener</div>

+							<div class="methodsignature"><code>void <strong>addEventListener</strong>(String <em>eventType</em>, Function <em>listener</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">eventType</code>

+								</li>

+								<li class="param">

+									<code class="paramname">listener</code>

+								</li>

+							</ul>

+							<div class="summary">

+								<p>

+									Adds a function to be called when an event of the type specified occurs in log4javascript.

+									Supported event types are <code>load</code> (occurs once the page has loaded) and

+									<code>error</code>.

+								</p>

+								<p>

+									Each listener is pased three paramaters:

+								</p>

+								<ul>

+									<li><code>sender</code>. The object that raised the event (i.e. the log4javascript object);</li>

+									<li><code>eventType</code>. The type of the event;</li>

+									<li>

+										<code>eventArgs</code>. An object containing of event-specific arguments. For the <code>error</code> event,

+										this is an object with properties <code>message</code> and <code>exception</code>. For the <code>load</code>

+										event this is an empty object.

+									</li>

+								</ul>

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">removeEventListener</div>

+							<div class="methodsignature"><code>void <strong>removeEventListener</strong>(String <em>eventType</em>, Function <em>listener</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">eventType</code>

+								</li>

+								<li class="param">

+									<code class="paramname">listener</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Removes the event listener function supplied for the event of the type specified.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">dispatchEvent</div>

+							<div class="methodsignature"><code>void <strong>dispatchEvent</strong>(String <em>eventType</em>, Object <em>eventArgs</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">eventType</code>

+								</li>

+								<li class="param">

+									<code class="paramname">eventArgs</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Raises an event of type <code>eventType</code> on the <code>log4javascript</code> object.

+								Each of the listeners for this type of event (registered via <code>addEventListener</code>)

+								is called and passed <code>eventArgs</code> as the third parameter.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">setEventTypes</div>

+							<div class="methodsignature"><code>void <strong>setEventTypes</strong>(Array <em>eventTypes</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">eventTypes</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Used internally to specify the types of events that the <code>log4javascript</code> object can raise.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">setShowStackTraces</div>

+							<div class="methodsignature"><code>void <strong>setShowStackTraces</strong>(Boolean <em>show</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">show</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Enables or disables displaying of error stack traces, depending on <code>show</code>.

+								By default, stack traces are not displayed. (Only works in Firefox)

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">evalInScope</div>

+							<div class="methodsignature"><code>Object <strong>evalInScope</strong>(String <em>expr</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">expr</code>

+								</li>

+							</ul>

+							<div class="summary">

+								This evaluates the given expression in the log4javascript scope, thus allowing

+								scripts to access internal log4javascript variables and functions. This was written

+								for the purposes of automated testing but could be used by custom extensions to

+								log4javascript.

+							</div>

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="levels">

+					<h2>Levels</h2>

+					<p>

+						Levels are available as static properties of the <code>log4javascript.Level</code>

+						object. In ascending order of severity:

+					</p>

+					<ol>

+						<li><code>log4javascript.Level.ALL</code></li>

+						<li><code>log4javascript.Level.TRACE</code></li>

+						<li><code>log4javascript.Level.DEBUG</code></li>

+						<li><code>log4javascript.Level.INFO</code></li>

+						<li><code>log4javascript.Level.WARN</code></li>

+						<li><code>log4javascript.Level.ERROR</code></li>

+						<li><code>log4javascript.Level.FATAL</code></li>

+						<li><code>log4javascript.Level.OFF</code></li>

+					</ol>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="loggers">

+					<h2>Loggers</h2>

+					<p>

+						It is possible to have multiple loggers in log4javascript. For example, you

+						may wish to have a logger for debugging purposes that logs messages to a

+						pop-up window and a separate logger that reports any client-side application

+						errors to the server via Ajax.

+					</p>

+					<div id="loggerhierarchy">

+						<h3>Logger hierarchy and appender additivity</h3>

+						<p>

+							From version 1.4, log4javascript has hierarchical loggers, implemented in the same way

+							as log4j. In summary, you specify a logger's parent logger by means of a dot between the

+							parent logger name and the child logger name. Therefore the logger <code>tim.app.security</code>

+							inherits from <code>tim.app</code>, which in turn inherits from <code>tim</code> which,

+							finally, inherits from the root logger.

+						</p>

+						<p>

+							What inheritance means for a logger is that in the absence of a threshold level set

+							specifically on the logger it inherits its level from its parent; also, a logger inherits

+							all its parent's appenders (this is known as <em>appender additivity</em> in log4j. This

+							behaviour can be enabled or disabled via <code>setAdditivity()</code>. See below). In the

+							above example, if the root logger has a level of <code>DEBUG</code> and one appender,

+							each of the loggers <code>tim.app.security</code>, <code>tim.app</code> and <code>tim</code> would

+							inherit the root level's appender. If, say, <code>tim.app</code>'s threshold level was set

+							to <code>WARN</code>, <code>tim</code>'s effective level would remain at <code>DEBUG</code>

+							(inherited from the root logger) while <code>tim.app.security</code>'s effective level would

+							be <code>WARN</code>, inherited from <code>tim.app</code>. The important thing to note is

+							that appenders accumulate down the logger hierarchy while levels are simply inherited from

+							the nearest ancestor with a threshold level set.

+						</p>

+						<p>

+							For a detailed explanation of the logger hierarchy, see the

+							<a href="http://logging.apache.org/log4j/docs/manual.html" target="_blank"

+							   title="Log4j manual (opens in new window)">log4j manual</a>.

+						</p>

+					</div>

+					<p><strong>Notes</strong></p>

+					<ul>

+						<li>

+							It is not possible to instantiate loggers directly. Instead you must use

+							one of the methods of the <code>log4javascript</code> object: <code>getLogger</code>,

+							<code>getRootLogger</code>, <code>getDefaultLogger</code> or <code>getNullLogger</code>.

+						</li>

+					</ul>

+					<h4>Logger methods</h4>

+					<ul class="propertieslist">

+						<li class="method">

+							<div class="name">addAppender</div>

+							<div class="methodsignature"><code>void <strong>addAppender</strong>(Appender <em>appender</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">appender</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Adds the given appender.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">removeAppender</div>

+							<div class="methodsignature"><code>void <strong>removeAppender</strong>(Appender <em>appender</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">appender</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Removes the given appender.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">removeAllAppenders</div>

+							<div class="methodsignature"><code>void <strong>removeAllAppenders</strong>()</code></div>

+							<div class="summary">

+								Clears all appenders for the current logger.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">setLevel</div>

+							<div class="methodsignature"><code>void <strong>setLevel</strong>(Level <em>level</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">level</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Sets the level. Log messages of a lower level than <code>level</code> will not be logged.

+								Default value is <code>DEBUG</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getLevel</div>

+							<div class="methodsignature"><code>Level <strong>getLevel</strong>()</code></div>

+							<div class="summary">

+								Returns the level explicitly set for this logger or <code>null</code> if none has been set.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getEffectiveLevel</div>

+							<div class="methodsignature"><code>Level <strong>getEffectiveLevel</strong>()</code></div>

+							<div class="summary">

+								Returns the level at which the logger is operating. This is either the level explicitly

+								set on the logger or, if no level has been set, the effective level of the logger's parent.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">setAdditivity</div>

+							<div class="methodsignature"><code>void <strong>setAdditivity</strong>(Boolean <em>additivity</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">additivity</code>

+								</li>

+							</ul>

+							<div class="summary">

+								<p>

+									Sets whether appender additivity is enabled (the default) or disabled. If set to false, this

+									particular logger will not inherit any appenders form its ancestors. Any descendant of this

+									logger, however, will inherit from its ancestors as normal, unless its own additivity is

+									explicitly set to false.

+								</p>

+								<p>

+									Default value is <code>true</code>.

+								</p>

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getAdditivity</div>

+							<div class="methodsignature"><code>Level <strong>getLevel</strong>()</code></div>

+							<div class="summary">

+								Returns whether additivity is enabled for this logger.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">log</div>

+							<div class="methodsignature"><code>void <strong>log</strong>(Level <em>level</em>, Object <em>params</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">level</code>

+								</li>

+								<li class="param">

+									<code class="paramname">params</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Generic logging method used by wrapper methods such as <code>debug</code>,

+								<code>error</code> etc.

+							</div>

+							<p><strong>Notes</strong></p>

+							<ul>

+								<li>

+									The signature of this method has changed in 1.4.

+								</li>

+							</ul>

+						</li>

+						<li class="method">

+							<div class="name">trace</div>

+							<div class="methodsignature"><code>void <strong>trace</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>TRACE</code>.

+							</div>

+							<p><strong>Notes</strong></p>

+							<ul>

+								<li>

+									Logging of multiple messages in one call is new in 1.4.

+								</li>

+							</ul>

+						</li>

+						<li class="method">

+							<div class="name">debug</div>

+							<div class="methodsignature"><code>void <strong>debug</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>DEBUG</code>.

+							</div>

+							<p><strong>Notes</strong></p>

+							<ul>

+								<li>

+									Logging of multiple messages in one call is new in 1.4.

+								</li>

+							</ul>

+						</li>

+						<li class="method">

+							<div class="name">info</div>

+							<div class="methodsignature"><code>void <strong>info</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>INFO</code>.

+							</div>

+							<p><strong>Notes</strong></p>

+							<ul>

+								<li>

+									Logging of multiple messages in one call is new in 1.4.

+								</li>

+							</ul>

+						</li>

+						<li class="method">

+							<div class="name">warn</div>

+							<div class="methodsignature"><code>void <strong>warn</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>WARN</code>.

+							</div>

+							<p><strong>Notes</strong></p>

+							<ul>

+								<li>

+									Logging of multiple messages in one call is new in 1.4.

+								</li>

+							</ul>

+						</li>

+						<li class="method">

+							<div class="name">error</div>

+							<div class="methodsignature"><code>void <strong>error</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>ERROR</code>.

+							</div>

+							<p><strong>Notes</strong></p>

+							<ul>

+								<li>

+									Logging of multiple messages in one call is new in 1.4.

+								</li>

+							</ul>

+						</li>

+						<li class="method">

+							<div class="name">fatal</div>

+							<div class="methodsignature"><code>void <strong>fatal</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>FATAL</code>.

+							</div>

+							<p><strong>Notes</strong></p>

+							<ul>

+								<li>

+									Logging of multiple messages in one call is new in 1.4.

+								</li>

+							</ul>

+						</li>

+						<li class="method">

+							<div class="name">isEnabledFor</div>

+							<div class="methodsignature"><code>Boolean <strong>isEnabledFor</strong>(Level <em>level</em>, Error <em>exception</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">level</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Returns whether the logger is enabled for the specified level. 

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isTraceEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isTraceEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>TRACE</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isDebugEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isDebugEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>DEBUG</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isInfoEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isInfoEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>INFO</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isWarnEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isWarnEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>WARN</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isErrorEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isErrorEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>ERROR</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isFatalEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isFatalEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>FATAL</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">group</div>

+							<div class="methodsignature"><code>void <strong>group</strong>(String <em>name</em>, Boolean <em>initiallyExpanded</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">name</code>

+								</li>

+								<li class="param">

+									<code class="paramname">initiallyExpanded</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Starts a new group of log messages. In appenders that support grouping (currently

+								<code><a href="#popupappender">PopUpAppender</a></code> and

+								<code><a href="#inpageappender">InPageAppender</a></code>), a group appears as an expandable

+								section in the console, labelled with the <code>name</code> specified.

+								Specifying <code>initiallyExpanded</code> determines whether the

+								group starts off expanded (the default is <code>true</code>). Groups may be nested.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">groupEnd</div>

+							<div class="methodsignature"><code>void <strong>groupEnd</strong>()</code></div>

+							<div class="summary">

+								Ends the current group. If there is no group then this function has no effect.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">time</div>

+							<div class="methodsignature"><code>void <strong>time</strong>(String <em>name</em>, Level <em>level</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">name</code>

+								</li>

+								<li class="param">

+									<code class="paramname">level</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Starts a timer with name <code>name</code>. When the timer is ended with a

+								call to <code>timeEnd</code> using the same name, the amount of time that

+								has elapsed in milliseconds since the timer was started is logged at level

+								<code>level</code>. If not level is supplied, the level defaults to <code>INFO</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">timeEnd</div>

+							<div class="methodsignature"><code>void <strong>timeEnd</strong>(String <em>name</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">name</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Ends the timer with name <code>name</code> and logs the time elapsed.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">assert</div>

+							<div class="methodsignature"><code>void <strong>assert</strong>(Object <em>expr</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">expr</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Asserts the given expression is <code>true</code> or evaluates to <code>true</code>.

+								If so, nothing is logged. If not, an error is logged at the <code>ERROR</code> level.

+							</div>

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="appenders">

+					<h2>Appenders</h2>

+					<div id="appender">

+						<h3>Appender</h3>

+						<p>

+							There are methods common to all appenders, as listed below.

+						</p>

+						<h4>Methods</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">doAppend</div>

+								<div class="methodsignature"><code>void <strong>doAppend</strong>(LoggingEvent <em>loggingEvent</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">loggingEvent</code>

+									</li>

+								</ul>

+								<div class="summary">

+									<p>

+										Checks the logging event's level is at least as severe as the appender's

+										threshold and calls the appender's <code>append</code> method if so.

+									</p>

+									<p>

+										This method should not in general be used directly or overridden.

+									</p>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">append</div>

+								<div class="methodsignature"><code>void <strong>append</strong>(LoggingEvent <em>loggingEvent</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">loggingEvent</code>

+									</li>

+								</ul>

+								<div class="summary">

+									Appender-specific method to append a log message. Every appender object should implement

+									this method.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setLayout</div>

+								<div class="methodsignature"><code>void <strong>setLayout</strong>(Layout <em>layout</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">layout</code>

+									</li>

+								</ul>

+								<div class="summary">

+									Sets the appender's layout.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getLayout</div>

+								<div class="methodsignature"><code>Layout <strong>getLayout</strong>()</code></div>

+								<div class="summary">

+									Returns the appender's layout.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setThreshold</div>

+								<div class="methodsignature"><code>void <strong>setThreshold</strong>(Level <em>level</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">level</code>

+									</li>

+								</ul>

+								<div class="summary">

+									Sets the appender's threshold. Log messages of level less severe than this

+									threshold will not be logged.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getThreshold</div>

+								<div class="methodsignature"><code>Level <strong>getThreshold</strong>()</code></div>

+								<div class="summary">

+									Returns the appender's threshold.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">toString</div>

+								<div class="methodsignature"><code>string <strong>toString</strong>()</code></div>

+								<div class="summary">

+									Returns a string representation of the appender. Every appender object should implement

+									this method.

+								</div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="alertappender">

+						<h3>AlertAppender</h3>

+						<p class="editions">Editions: <strong>Standard</strong></p>

+						<p>

+							Displays a log message as a JavaScript alert.

+						</p>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">AlertAppender</div>

+								<div class="methodsignature"><code><strong>AlertAppender</strong>()</code></div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="ajaxappender">

+						<h3>AjaxAppender</h3>

+						<p class="editions">Editions: <strong>Standard, Production</strong></p>

+						<p>

+							A flexible appender that asynchronously  sends log messages to a server via HTTP

+							(Ajax, if you insist, though the 'x' of Ajax only comes into play in any form if you use an

+							<code><a href="#xmllayout">XmlLayout</a></code>).

+						</p>

+						<p>

+							The default configuration is to send each log message as a separate HTTP post

+							request to the server using an <code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>,

+							without waiting for a response before sending any subsequent requests. However,

+							an <code>AjaxAppender</code> may be configured to do any one of or combinations of the following:

+						</p>

+						<ul>

+							<li>

+								send log messages in batches (if the selected layout supports it - particularly suited

+								to <code>AjaxAppender</code> are <code><a href="#jsonlayout">JsonLayout</a></code> and

+								<code><a href="#xmllayout">XmlLayout</a></code>, both of which allow batching);

+							</li>

+							<li>

+								wait for a response from a previous request before sending the next log message / batch

+								of messages;

+							</li>

+							<li>

+								send all queued log messages at timed intervals.

+							</li>

+						</ul>

+						<p><strong>Notes</strong></p>

+						<ul>

+							<li>

+								AjaxAppender relies on the <code>XMLHttpRequest</code> object. It also requires

+								the presence of correctly implemented <code>setRequestHeader</code> method on

+								this object, which rules out Opera prior to version 8.01. If your browser does not

+								support the necessary objects then one alert will display to explain why it

+								doesn't work, after which the appender will silently switch off.

+							</li>

+							<li>

+								In AjaxAppender only, <code>setLayout</code> may not be called after the first

+								message has been logged.

+							</li>

+							<li>

+								The default layout is <code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>.

+							</li>

+							<li>

+								From version 1.4, log message data is always sent as one or more name/value pairs.

+								In the case of <code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>, data

+								is sent the same as in previous versions. For other layouts such as

+								<code><a href="#jsonlayout">JsonLayout</a></code> and

+								<code><a href="#xmllayout">XmlLayout</a></code>, the formatted log message is posted as

+								the value of a parameter called <code>data</code>, though this may be changed via

+								<code>setPostVarName</code>.

+							</li>

+							<li>

+								From version 1.4, log message timestamps are sent as standard JavaScript times, i.e.

+								the number of milliseconds since 00:00:00 UTC on January 1, 1970.

+							</li>

+							<li>

+								<p>

+									Also from version 1.4, any outstanding log messages may optionally be sent when the

+									main page unloads (i.e. user follows a link, closes the window or refreshes the

+									page). This behaviour may be enabled using <code>setSendAllOnUnload</code>; see

+									below.

+								</p>

+								<p>

+									This behaviour is dependent on <code>window.onbeforeunload</code>; unfortunately,

+									Opera does not always raise this event, so this feature does not work reliably in

+									Opera.

+								</p>

+							</li>

+						</ul>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">AjaxAppender</div>

+								<div class="methodsignature">

+									<code><strong>AjaxAppender</strong>(String <em>url</em>)</code>

+								</div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">url</code>

+										<div>

+											The URL to which log messages should be sent. Note that this is subject

+											to the usual Ajax restrictions: the URL should be in the same domain as that

+											of the page making the request.

+										</div>

+									</li>

+								</ul>

+							</li>

+						</ul>

+						<h4>Methods</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">setSendAllOnUnload</div>

+								<div class="methodsignature"><code>void <strong>setSendAllOnUnload</strong>(Boolean <em>sendAllOnUnload</em>)</code></div>

+								<div class="summary">

+									<p>

+										[<em>not available after first message logged</em>]

+									</p>

+									<p>

+										Whether to send all remaining unsent log messages to the server when the page

+										unloads.

+									</p>

+									<p>

+										Since version 1.4.3, the default value is <code>false</code>. Previously the

+										default was <code>true</code>.

+									</p>

+									<p><strong>Notes</strong></p>

+									<ul>

+										<li>

+											This feature was found not to work prior to version 1.4.3 in WebKit

+											browsers (e.g. Google Chrome, Safari). As a result, a workaround was

+											implemented in 1.4.3 which has the unfortunate side effect of popping up a

+											confirmation dialog to the user if there are any log messages to send when

+											the page unloads. As a result, this feature is now obtrusive for the user

+											and is therefore disabled by default.

+										</li>

+										<li>

+											This feature does not work in any version of Opera.

+										</li>

+									</ul>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isSendAllOnUnload</div>

+								<div class="methodsignature"><code>Boolean <strong>isSendAllOnUnload</strong>()</code></div>

+								<div class="summary">

+									Returns whether all remaining unsent log messages are sent to the server when the page unloads.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setPostVarName</div>

+								<div class="methodsignature"><code>void <strong>setPostVarName</strong>(String <em>postVarName</em>)</code></div>

+								<div class="summary">

+									<p>

+										[<em>not available after first message logged</em>]

+									</p>

+									<p>

+										Sets the post variable name whose value will the formatted log message(s) for

+										each request.

+									</p>

+									<p>

+										Default value is <code>data</code>.

+									</p>

+									<p><strong>Notes</strong></p>

+									<ul>

+										<li>

+											This has no effect if the current layout is an

+											<code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>.

+										</li>

+									</ul>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getPostVarName</div>

+								<div class="methodsignature"><code>String <strong>getPostVarName</strong>()</code></div>

+								<div class="summary">

+									Returns the post variable name whose value will the formatted log message(s) for

+									each request.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setTimed</div>

+								<div class="methodsignature"><code>void <strong>setTimed</strong>(Boolean <em>timed</em>)</code></div>

+								<div class="summary">

+									<p>

+										[<em>not available after first message logged</em>]

+									</p>

+									<p>

+										Whether to send log messages to the server at regular, timed intervals.

+									</p>

+									<p>

+										Default value is <code>false</code>.

+									</p>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isTimed</div>

+								<div class="methodsignature"><code>Boolean <strong>isTimed</strong>()</code></div>

+								<div class="summary">

+									Returns whether log messages are sent to the server at regular, timed intervals.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setWaitForResponse</div>

+								<div class="methodsignature"><code>void <strong>setWaitForResponse</strong>(Boolean <em>waitForResponse</em>)</code></div>

+								<div class="summary">

+									<p>

+										[<em>not available after first message logged</em>]

+									</p>

+									<p>

+										Sets whether to wait for a response from a previous HTTP request from this

+										appender before sending the next log message / batch of messages.

+									</p>

+									<p>

+										Default value is <code>false</code>.

+									</p>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isWaitForResponse</div>

+								<div class="methodsignature"><code>Boolean <strong>isWaitForResponse</strong>()</code></div>

+								<div class="summary">

+									Returns whether the appender waits for a response from a previous HTTP request from this

+									appender before sending the next log message / batch of messages.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setBatchSize</div>

+								<div class="methodsignature"><code>void <strong>setBatchSize</strong>(Number <em>batchSize</em>)</code></div>

+								<div class="summary">

+									<p>

+										[<em>not available after first message logged</em>]

+									</p>

+									<p>

+										Sets the number of log messages to send in each request. If not specified,

+										defaults to <code>1</code>.

+									</p>

+									<p><strong>Notes</strong></p>

+									<ul>

+										<li>

+											Setting this to a number greater than 1 means that the appender will wait

+											until it has forwarded that many valid log messages before sending any more.

+											This also means that if the page unloads for any reason and <code>sendAllOnUnload</code>

+											is not set to <code>true</code>, any log messages waiting in the queue will not be sent.

+										</li>

+										<li>

+											If batching is used in conjunction with timed sending of log messages,

+											messages will still be sent in batches of size <code>batchSize</code>,

+											regardless of how many log messages are queued by the time the timed

+											sending is invoked. Incomplete batches will not be sent except when the

+											page unloads, if <code>sendAllOnUnload</code> is set to <code>true</code>.

+										</li>

+									</ul>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getBatchSize</div>

+								<div class="methodsignature"><code>Number <strong>getBatchSize</strong>()</code></div>

+								<div class="summary">

+									Returns the number of log messages sent in each request. See above for more details.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setTimerInterval</div>

+								<div class="methodsignature"><code>void <strong>setTimerInterval</strong>(Number <em>timerInterval</em>)</code></div>

+								<div class="summary">

+									<p>

+										[<em>not available after first message logged</em>]

+									</p>

+									<p>

+										Sets the length of time in milliseconds between each sending of queued log

+										messages.

+									</p>

+									<p><strong>Notes</strong></p>

+									<ul>

+										<li>

+											<code>timerInterval</code> only has an effect in conjunction with

+											<code>timed</code> (set by <code>setTimed()</code>. If <code>timed</code>

+											is set to false then <code>timerInterval</code> has no effect.

+										</li>

+										<li>

+											Each time the queue of log messages or batches of messages is cleared,

+											the countdown to the next sending only starts once the final request

+											has been sent (and, if <code>waitForResponse</code> is set to <code>true</code>,

+											the final response received). This means that the actual interval at

+											which the queue of messages is cleared cannot be fixed.

+										</li>

+									</ul>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getTimerInterval</div>

+								<div class="methodsignature"><code>Number <strong>getTimerInterval</strong>()</code></div>

+								<div class="summary">

+									Returns the length of time in milliseconds between each sending of queued log

+									messages. See above for more details.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setRequestSuccessCallback</div>

+								<div class="methodsignature"><code>void <strong>setRequestSuccessCallback</strong>(Function <em>requestSuccessCallback</em>)</code></div>

+								<div class="summary">

+									<p>

+										Sets the function that is called whenever a successful request is made, called at the

+										point at which the response is received. This feature can be used to confirm

+										whether a request has been successful and act accordingly.

+									</p>

+									<p>

+										A single parameter, <code>xmlHttp</code>, is passed to the callback function.

+										This is the XMLHttpRequest object that performed the request.

+									</p>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setFailCallback</div>

+								<div class="methodsignature"><code>void <strong>setFailCallback</strong>(Function <em>failCallback</em>)</code></div>

+								<div class="summary">

+									<p>

+										Sets the function that is called whenever any kind of failure occurs in the appender,

+										including browser deficiencies or configuration errors (e.g. supplying a

+										non-existent URL to the appender). This feature can be used to handle

+										AjaxAppender-specific errors.

+									</p>

+									<p>

+										A single parameter, <code>message</code>, is passed to the callback function.

+										This is the error-specific message that caused the failure.

+									</p>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setSessionId</div>

+								<div class="methodsignature"><code>void <strong>setSessionId</strong>(String <em>sessionId</em>)</code></div>

+								<div class="summary">

+									Sets the session id sent to the server each time a request is made.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getSessionId</div>

+								<div class="methodsignature"><code>String <strong>getSessionId</strong>()</code></div>

+								<div class="summary">

+									Returns the session id sent to the server each time a request is made.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">addHeader</div>

+								<div class="methodsignature"><code>void <strong>addHeader</strong>(String <em>name</em>,

+									String <em>value</em>)</code></div>

+								<div class="summary">

+									<p>

+										Adds an HTTP header that is sent with each request.

+									</p>

+									<p>

+										<strong>Since: 1.4.3</strong>

+									</p>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getHeaders</div>

+								<div class="methodsignature"><code>Array <strong>getHeaders</strong>()</code></div>

+								<div class="summary">

+									Returns an array of the additional headers that are sent with each HTTP request.

+									Each array item is an object with properties <code>name</code> and

+									<code>value</code>.

+									<p>

+										<strong>Since: 1.4.3</strong>

+									</p>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">sendAll</div>

+								<div class="methodsignature"><code>void <strong>sendAll</strong>()</code></div>

+								<div class="summary">

+									Sends all log messages in the queue. If log messages are batched then only completed

+									batches are sent.

+								</div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="popupappender">

+						<h3>PopUpAppender</h3>

+						<p class="editions">Editions: <strong>Standard</strong></p>

+						<p>

+							Logs messages to a pop-up console window (note: you will need to disable pop-up

+							blockers to use it). The pop-up displays a list of all log messages, and has

+							the following features:

+						</p>

+						<ul>

+							<li>log messages are colour-coded by severity;</li>

+							<li>log messages are displayed in a monospace font to allow easy readability;</li>

+							<li>switchable wrap mode to allow wrapping of long lines</li>

+							<li>all whitespace in log messages is honoured (except in wrap mode);</li>

+							<li>filters to show and hide messages of a particular level;</li>

+							<li>

+								search facility that allows searching of log messages as you type, with the

+								following features:

+								<ul>

+									<li>supports regular expressions;</li>

+									<li>case sensitive or insensitive matching;</li>

+									<li>buttons to navigate through all the matches;</li>

+									<li>switch to highlight all matches;</li>

+									<li>switch to filter out all log messages that contain no matches;</li>

+									<li>switch to enable or disable the search;</li>

+									<li>search is dynamically applied to every log message as it is added to the console.</li>

+								</ul>

+							</li>

+							<li>switch to toggle between logging from the top down and from the bottom up;</li>

+							<li>switch to turn automatic scrolling when a new message is logged on and off;</li>

+							<li>switch to turn off all logging to the pop-up (useful if a timer is generating unwanted log messages);</li>

+							<li>optional configurable limit to the number of log message that are displayed. If

+								set and this limit is reached, each new log message will cause the oldest one to

+								be discarded;</li>

+							<li>grouped log messages. Groups may be nested and each has a button to show or hide the log messages in that group;</li>

+							<li>clear button to allow user to delete all current log messages.</li>

+							<li>

+								command prompt with up/down arrow history. Command line functions may be added

+								to the appender. Several command line functions are built in:

+								<ul class="propertieslist">

+									<li class="method">

+										<div class="methodsignature"><code><strong>$</strong>(String <em>id</em>)</code></div>

+										<div class="summary">

+											Prints a string representation of a single element with the id supplied.

+										</div>

+									</li>

+									<li class="method">

+										<div class="methodsignature"><code><strong>dir</strong>(Object <em>obj</em>)</code></div>

+										<div class="summary">

+											Prints a list of a properties of the object supplied.

+										</div>

+									</li>

+									<li class="method">

+										<div class="methodsignature"><code><strong>dirxml</strong>(HTMLElement <em>el</em>)</code></div>

+										<div class="summary">

+											Prints the XML source code of an HTML or XML element

+										</div>

+									</li>

+									<li class="method">

+										<div class="methodsignature"><code><strong>cd</strong>(Object <em>win</em>)</code></div>

+										<div class="summary">

+											Changes the scope of execution of commands to the named frame or window (either a

+											window/frame name or a reference to a window object may be supplied).

+										</div>

+									</li>

+									<li class="method">

+										<div class="methodsignature"><code><strong>clear</strong>()</code></div>

+										<div class="summary">

+											Clears the console.

+										</div>

+									</li>

+									<li class="method">

+										<div class="methodsignature"><code><strong>keys</strong>(Object <em>obj</em>)</code></div>

+										<div class="summary">

+											Prints a list of the names of all properties of the object supplied.

+										</div>

+									</li>

+									<li class="method">

+										<div class="methodsignature"><code><strong>values</strong>(Object <em>obj</em>)</code></div>

+										<div class="summary">

+											Prints a list of the values of all properties of the object supplied.

+										</div>

+									</li>

+									<li class="method">

+										<div class="methodsignature"><code><strong>expansionDepth</strong>(Number <em>depth</em>)</code></div>

+										<div class="summary">

+											Sets the number of levels of expansion of objects that are displayed by

+											the command line. The default value is 1.

+										</div>

+									</li>

+								</ul>

+							</li>

+						</ul>

+						<p><strong>Notes</strong></p>

+						<ul>

+							<li>

+								<p>

+									The default layout for this appender is <code><a href="#patternlayout">PatternLayout</a></code>

+									with pattern string

+								</p>

+								<p>

+									<code>%d{HH:mm:ss} %-5p - %m{1}%n</code>

+								</p>

+							</li>

+						</ul>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">PopUpAppender</div>

+								<div class="methodsignature">

+							   		<code><strong>PopUpAppender</strong>([Boolean <em>lazyInit</em>,

+									Boolean <em>initiallyMinimized</em>, Boolean <em>useDocumentWrite</em>,

+									Number <em>width</em>, Number <em>height</em>])</code>

+								</div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">lazyInit</code>

+										[<em>optional</em>]

+										<div>

+											Set this to <code>true</code> to open the pop-up only when the first log

+											message reaches the appender. Otherwise, the pop-up window opens as soon as the

+											appender is created. If not specified, defaults to <code>false</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">initiallyMinimized</code>

+										[<em>optional</em>]

+										<div>

+											<p>

+												Whether the console window should start off hidden / minimized.

+												If not specified, defaults to <code>false</code>.

+											</p>

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">useDocumentWrite</code>

+										[<em>optional</em>]

+										<div>

+											<p>

+												Specifies how the console window is created. By default, the console window is

+												created dynamically using <code>document</code>'s <code>write</code> method. This has the

+												advantage of keeping all the code in one single JavaScript file. However, if your

+												page sets <code>document.domain</code> then the browser prevents script access to

+												a window unless it too has the same value set for <code>document.domain</code>. To

+												get round this issue, you can set <code>useDocumentWrite</code> to <code>false</code>

+												and log4javascript will instead use the external HTML file <code>console.html</code>

+												(or <code>console_uncompressed.html</code> if you're using an uncompressed version of

+												log4javascript.js), which must be placed in the same directory as your log4javascript.js file.

+											</p>

+											<p>

+												Note that if <code>useDocumentWrite</code> is set to <code>true</code>, the old pop-up

+												window will always be closed and a new one created whenever the page is refreshed, even

+												if <code>setUseOldPopUp(true)</code> has been called.

+											</p>

+											<p>

+												In general it's simpler to use the <code>document.write</code> method, so unless your

+												page needs to set <code>document.domain</code>, <code>useDocumentWrite</code> should

+												be set to <code>true</code>.

+											</p>

+											<p>

+												If not specified, defaults to <code>true</code>.

+											</p>

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">width</code>

+										[<em>optional</em>]

+										<div>

+											The outer width in pixels of the pop-up window. If not specified,

+											defaults to <code>600</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">height</code>

+										[<em>optional</em>]

+										<div>

+											The outer height in pixels of the pop-up window. If not specified,

+											defaults to <code>400</code>.

+										</div>

+									</li>

+								</ul>

+							</li>

+						</ul>

+						<h4>Methods</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">isInitiallyMinimized</div>

+								<div class="methodsignature"><code>Boolean <strong>isInitiallyMinimized</strong>()</code></div>

+								<div class="summary">

+									Returns whether the console window starts off hidden / minimized.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setInitiallyMinimized</div>

+								<div class="methodsignature"><code>void <strong>setInitiallyMinimized</strong>(Boolean <em>initiallyMinimized</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets whether the console window should start off hidden / minimized.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isFocusPopUp</div>

+								<div class="methodsignature"><code>Boolean <strong>isFocusPopUp</strong>()</code></div>

+								<div class="summary">

+									Returns whether the pop-up window is focussed (i.e. brought it to the front)

+									when a new log message is added. Default value is <code>false</code>.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setFocusPopUp</div>

+								<div class="methodsignature"><code>void <strong>setFocusPopUp</strong>(Boolean <em>focusPopUp</em>)</code></div>

+								<div class="summary">

+									Sets whether to focus the pop-up window (i.e. bring it to the front)

+									when a new log message is added.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isUseOldPopUp</div>

+								<div class="methodsignature"><code>Boolean <strong>isUseOldPopUp</strong>()</code></div>

+								<div class="summary">

+									<p>

+										Returns whether the same pop-up window is used if the main page is

+										reloaded. If set to <code>true</code>, when the page is reloaded

+										a line is drawn in the pop-up and subsequent log messages are added

+										to the same pop-up. Otherwise, a new pop-up window is created that

+										replaces the original pop-up. If not specified, defaults to

+										<code>true</code>.

+									</p>

+									<p><strong>Notes</strong></p>

+									<ul>

+										<li>

+											In Internet Explorer 5, the browser prevents this from working

+											properly, so a new pop-up window is always created when the main

+											page reloads. Also, the original pop-up does not get closed.

+										</li>

+									</ul>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setUseOldPopUp</div>

+								<div class="methodsignature"><code>void <strong>setUseOldPopUp</strong>(Boolean <em>useOldPopUp</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets whether to use the same pop-up window if the main page is reloaded.

+									See <code>isUseOldPopUp</code> above for details.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isComplainAboutPopUpBlocking</div>

+								<div class="methodsignature"><code>Boolean <strong>isComplainAboutPopUpBlocking</strong>()</code></div>

+								<div class="summary">

+									Returns whether an alert is shown to the user when the pop-up window

+									cannot be created as a result of a pop-up blocker. Default value is <code>true</code>.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setComplainAboutPopUpBlocking</div>

+								<div class="methodsignature"><code>void <strong>setComplainAboutPopUpBlocking</strong>(Boolean <em>complainAboutPopUpBlocking</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets whether to announce to show an alert to the user when the pop-up window

+									cannot be created as a result of a pop-up blocker.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isNewestMessageAtTop</div>

+								<div class="methodsignature"><code>Boolean <strong>isNewestMessageAtTop</strong>()</code></div>

+								<div class="summary">

+									Returns whether new log messages are displayed at the top of the pop-up window.

+									Default value is <code>false</code> (i.e. log messages are appended to the bottom of the window).

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setNewestMessageAtTop</div>

+								<div class="methodsignature"><code>void <strong>setNewestMessageAtTop</strong>(Boolean <em>newestMessageAtTop</em>)</code></div>

+								<div class="summary">

+									Sets whether to display new log messages at the top inside the pop-up window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isScrollToLatestMessage</div>

+								<div class="methodsignature"><code>Boolean <strong>isScrollToLatestMessage</strong>()</code></div>

+								<div class="summary">

+									Returns whether the pop-up window scrolls to display the latest log message when a new message

+									is logged. Default value is <code>true</code>.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setScrollToLatestMessage</div>

+								<div class="methodsignature"><code>void <strong>setScrollToLatestMessage</strong>(Boolean <em>scrollToLatestMessage</em>)</code></div>

+								<div class="summary">

+									Sets whether to scroll the pop-up window to display the latest log message when a new message

+									is logged.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isReopenWhenClosed</div>

+								<div class="methodsignature"><code>Boolean <strong>isReopenWhenClosed</strong>()</code></div>

+								<div class="summary">

+									Returns whether the pop-up window reopens automatically after being closed when a new log message is logged.

+									Default value is <code>false</code>.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setReopenWhenClosed</div>

+								<div class="methodsignature"><code>void <strong>setReopenWhenClosed</strong>(Boolean <em>reopenWhenClosed</em>)</code></div>

+								<div class="summary">

+									Sets whether to reopen the pop-up window automatically after being closed when a new log message is logged.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getWidth</div>

+								<div class="methodsignature"><code>Number <strong>getWidth</strong>()</code></div>

+								<div class="summary">

+									Returns the outer width in pixels of the pop-up window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setWidth</div>

+								<div class="methodsignature"><code>void <strong>setWidth</strong>(Number <em>width</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets the outer width in pixels of the pop-up window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getHeight</div>

+								<div class="methodsignature"><code>Number <strong>getHeight</strong>()</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Returns the outer height in pixels of the pop-up window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setHeight</div>

+								<div class="methodsignature"><code>void <strong>setHeight</strong>(Number <em>height</em>)</code></div>

+								<div class="summary">

+									Sets the outer height in pixels of the pop-up window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getMaxMessages</div>

+								<div class="methodsignature"><code>Number <strong>getMaxMessages</strong>()</code></div>

+								<div class="summary">

+									Returns the largest number of log messages that are displayed and stored

+									by the the console. Once reached, a new log message wil cause the

+									oldest message to be discarded.  Default value is <code>null</code>, which means no

+									limit is applied.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setMaxMessages</div>

+								<div class="methodsignature"><code>void <strong>setMaxMessages</strong>(Number <em>maxMessages</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets the largest number of messages displayed and stored by the console window. Set

+									this to <code>null</code> to make this number unlimited.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isShowCommandLine</div>

+								<div class="methodsignature"><code>Boolean <strong>isShowCommandLine</strong>()</code></div>

+								<div class="summary">

+									Returns whether the console includes a command line.

+									Default value is <code>true</code>.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setShowCommandLine</div>

+								<div class="methodsignature"><code>void <strong>setShowCommandLine</strong>(Boolean <em>showCommandLine</em>)</code></div>

+								<div class="summary">

+									Sets whether the console includes a command line.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getCommandLineObjectExpansionDepth</div>

+								<div class="methodsignature"><code>Number <strong>getCommandLineObjectExpansionDepth</strong>()</code></div>

+								<div class="summary">

+									Returns the number of levels to expand when an object value is logged to the console.

+									Each property of an object above this threshold will be expanded if it is itself an object

+									or array, otherwise its string representation will be displayed. Default value is 1 (i.e.

+									the properties of the object logged will be displayed in their string representation but

+									not expanded).

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setCommandLineObjectExpansionDepth:</div>

+								<div class="methodsignature"><code>void <strong>setCommandLineObjectExpansionDepth</strong>(Number <em>expansionDepth</em>)</code></div>

+								<div class="summary">

+									Sets the number of levels to expand when an object value is logged to the console.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getCommandWindow</div>

+								<div class="methodsignature"><code>Window <strong>getCommandWindow</strong>()</code></div>

+								<div class="summary">

+									Returns a reference to the window in which commands typed into the command line

+									are currently being executed.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setCommandWindow</div>

+								<div class="methodsignature"><code>void <strong>setCommandWindow</strong>(Window <em>commandWindow</em>)</code></div>

+								<div class="summary">

+									Sets the window in which commands typed into the command line are executed.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getCommandLayout</div>

+								<div class="methodsignature"><code>Number <strong>getCommandLayout</strong>()</code></div>

+								<div class="summary">

+									Returns the layout used to format the output for commands typed into the command line.

+									The default value is a <code><a href="#patternlayout">PatternLayout</a></code> with

+									pattern string <code>%m</code>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setCommandLayout</div>

+								<div class="methodsignature"><code>void <strong>setCommandLayout</strong>(Layout <em>commandLayout</em>)</code></div>

+								<div class="summary">

+									Sets the layout used to format the output for commands typed into the command line.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">clear</div>

+								<div class="methodsignature"><code>void <strong>clear</strong>()</code></div>

+								<div class="summary">

+									Clears all messages from the console window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">close</div>

+								<div class="methodsignature"><code>void <strong>close</strong>()</code></div>

+								<div class="summary">

+									Closes the pop-up window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">show</div>

+								<div class="methodsignature"><code>void <strong>show</strong>()</code></div>

+								<div class="summary">

+									Opens the pop-up window, if not already open.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">hide</div>

+								<div class="methodsignature"><code>void <strong>hide</strong>()</code></div>

+								<div class="summary">

+									Closes the pop-up window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">focus</div>

+								<div class="methodsignature"><code>void <strong>focus</strong>()</code></div>

+								<div class="summary">

+									Brings the console window to the top and gives it the focus.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">focusCommandLine</div>

+								<div class="methodsignature"><code>void <strong>focusCommandLine</strong>()</code></div>

+								<div class="summary">

+									Brings the console window to the top and gives the focus to the command line.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">focusSearch</div>

+								<div class="methodsignature"><code>void <strong>focusSearch</strong>()</code></div>

+								<div class="summary">

+									Brings the console window to the top and gives the focus to the search box.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">evalCommandAndAppend</div>

+								<div class="methodsignature"><code>void <strong>evalCommandAndAppend</strong>(String <em>expr</em>)</code></div>

+								<div class="summary">

+									Evaluates the expression and appends the result to the console.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">addCommandLineFunction</div>

+								<div class="methodsignature"><code>void <strong>addCommandLineFunction</strong>(String <em>functionName</em>, Function <em>commandLineFunction</em>)</code></div>

+								<div class="summary">

+									<p>

+										Adds a function with the name specified to the list of functions available on the command line.

+										This feature may be used to add custom functions to the command line.

+									</p>

+									<p>

+										When you call the function on the command line, <code>commandLineFunction</code> is executed with the

+										following three parameters:

+									</p>

+									<ul>

+										<li><em>appender</em>. A reference to the appender in which the command was executed;</li>

+										<li><em>args</em>.

+											An array-like list of parameters passed into the function on the command line

+											(actually a reference to the <code>arguments</code> object representing the parameters passed

+											into the function by the user);</li>

+										<li><em>returnValue</em>. This is an object with two properties that allow the function to control

+											how the result is displayed:

+											<ul>

+												<li><em>appendResult</em>. A boolean value that determines whether the returned value from this

+													function is appended to the console. The default value is <code>true</code>;</li>

+												<li><em>isError</em>. A boolean value that specifies whether the output of this function

+													should be displayed as an error. The default value is <code>false</code>.</li>

+											</ul>

+										</li>

+									</ul>

+									<p>

+										The value returned by the function is formatted by the command layout and appended to the console.

+									</p>

+								</div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="inpageappender">

+						<h3>InPageAppender</h3>

+						<p class="editions">Editions: <strong>Standard</strong></p>

+						<p>

+							Logs messages to a console window in the page. The console is identical

+							to that used by the <code><a href="#popupappender">PopUpAppender</a></code>, except

+							for the absence of a 'Close' button.

+						</p>

+						<p><strong>Notes</strong></p>

+						<ul>

+							<li>

+								Prior to log4javascript 1.3, InPageAppender was known as InlineAppender.

+								For the sake of backwards compatibility, InlineAppender is still included in

+								1.3 and later as an alias for InPageAppender.

+							</li>

+							<li>

+								<p>

+									The default layout for this appender is <code><a href="#patternlayout">PatternLayout</a></code>

+									with pattern string

+								</p>

+								<p>

+									<code>%d{HH:mm:ss} %-5p - %m{1}%n</code>

+								</p>

+							</li>

+						</ul>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">InPageAppender</div>

+								<div class="methodsignature">

+									<code><strong>InPageAppender</strong>(HTMLElement <em>container</em>[,

+									Boolean <em>lazyInit</em>, Boolean <em>initiallyMinimized</em>,

+									Boolean <em>useDocumentWrite</em>, String <em>width</em>, String <em>height</em>])</code>

+								</div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">container</code>

+										<div>

+											The container element for the console window. This should be an HTML element.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">lazyInit</code>

+										[<em>optional</em>]

+										<div>

+											Set this to <code>true</code> to create the console only when the first log

+											message reaches the appender. Otherwise, the console is initialized as soon as the

+											appender is created. If not specified, defaults to <code>true</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">initiallyMinimized</code>

+										[<em>optional</em>]

+										<div>

+											<p>

+												Whether the console window should start off hidden / minimized.

+												If not specified, defaults to <code>false</code>.

+											</p>

+											<p><strong>Notes</strong></p>

+											<ul>

+												<li>

+													In Safari (and possibly other browsers) hiding an <code>iframe</code>

+													resets its document, thus destroying the console window.

+												</li>

+											</ul>

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">useDocumentWrite</code>

+										[<em>optional</em>]

+										<div>

+											<p>

+												Specifies how the console window is created. By default, the console window is

+												created dynamically using <code>document</code>'s <code>write</code> method. This has the

+												advantage of keeping all the code in one single JavaScript file. However, if your

+												page sets <code>document.domain</code> then the browser prevents script access to

+												a window unless it too has the same value set for <code>document.domain</code>. To

+												get round this issue, you can set <code>useDocumentWrite</code> to <code>false</code>

+												and log4javascript will instead use the external HTML file <code>console.html</code>

+												(or <code>console_uncompressed.html</code> if you're using an uncompressed version of

+												log4javascript.js), which must be placed in the same directory as your log4javascript.js file.

+											</p>

+											<p>

+												In general it's simpler to use the <code>document.write</code> method, so unless your

+												page needs to set <code>document.domain</code>, <code>useDocumentWrite</code> should

+												be set to <code>true</code>.

+											</p>

+											<p>

+												If not specified, defaults to <code>true</code>.

+											</p>

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">width</code>

+										[<em>optional</em>]

+										<div>

+											The width of the console window. Any valid CSS length may be used. If not

+											specified, defaults to <code>100%</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">height</code>

+										[<em>optional</em>]

+										<div>

+											The height of the console window. Any valid CSS length may be used. If not

+											specified, defaults to <code>250px</code>.

+										</div>

+									</li>

+								</ul>

+							</li>

+						</ul>

+						<h4>Methods</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">addCssProperty</div>

+								<div class="methodsignature"><code>void <strong>addCssProperty</strong>(String <em>name</em>, String <em>value</em>)</code></div>

+								<div class="summary">

+									Sets a CSS style property on the HTML element containing the console iframe.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isVisible</div>

+								<div class="methodsignature"><code>Boolean <strong>isVisible</strong>()</code></div>

+								<div class="summary">

+									Returns whether the console window is currently visible.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isInitiallyMinimized</div>

+								<div class="methodsignature"><code>Boolean <strong>isInitiallyMinimized</strong>()</code></div>

+								<div class="summary">

+									Returns whether the console window starts off hidden / minimized.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setInitiallyMinimized</div>

+								<div class="methodsignature"><code>void <strong>setInitiallyMinimized</strong>(Boolean <em>initiallyMinimized</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets whether the console window should start off hidden / minimized.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isNewestMessageAtTop</div>

+								<div class="methodsignature"><code>Boolean <strong>isNewestMessageAtTop</strong>()</code></div>

+								<div class="summary">

+									Returns whether new log messages are displayed at the top of the console window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setNewestMessageAtTop</div>

+								<div class="methodsignature"><code>void <strong>setNewestMessageAtTop</strong>(Boolean <em>newestMessageAtTop</em>)</code></div>

+								<div class="summary">

+									Sets whether to display new log messages at the top inside the console window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isScrollToLatestMessage</div>

+								<div class="methodsignature"><code>Boolean <strong>isScrollToLatestMessage</strong>()</code></div>

+								<div class="summary">

+									Returns whether the pop-up window scrolls to display the latest log message when a new message

+									is logged.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setScrollToLatestMessage</div>

+								<div class="methodsignature"><code>void <strong>setScrollToLatestMessage</strong>(Boolean <em>scrollToLatestMessage</em>)</code></div>

+								<div class="summary">

+									Sets whether to scroll the console window to display the latest log message when a new message

+									is logged.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getWidth</div>

+								<div class="methodsignature"><code>String <strong>getWidth</strong>()</code></div>

+								<div class="summary">

+									Returns the outer width of the console window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setWidth</div>

+								<div class="methodsignature"><code>void <strong>setWidth</strong>(String <em>width</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets the outer width of the console window. Any valid CSS length may be used.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getHeight</div>

+								<div class="methodsignature"><code>String <strong>getHeight</strong>()</code></div>

+								<div class="summary">

+									Returns the outer height of the console window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setHeight</div>

+								<div class="methodsignature"><code>void <strong>setHeight</strong>(String <em>height</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets the outer height of the console window. Any valid CSS length may be used.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getMaxMessages</div>

+								<div class="methodsignature"><code>Number <strong>getMaxMessages</strong>()</code></div>

+								<div class="summary">

+									Returns the largest number of messages displayed and stored by the console window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setMaxMessages</div>

+								<div class="methodsignature"><code>void <strong>setMaxMessages</strong>(Number <em>maxMessages</em>)</code></div>

+								<div class="summary">

+									[<em>not available after initialization</em>]

+									<br />

+									Sets the largest number of messages displayed and stored by the console window. Set

+									this to <code>null</code> to make this number unlimited.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">isShowCommandLine</div>

+								<div class="methodsignature"><code>Boolean <strong>isShowCommandLine</strong>()</code></div>

+								<div class="summary">

+									Returns whether the console includes a command line.

+									Default value is <code>true</code>.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setShowCommandLine</div>

+								<div class="methodsignature"><code>void <strong>setShowCommandLine</strong>(Boolean <em>showCommandLine</em>)</code></div>

+								<div class="summary">

+									Sets whether the console includes a command line.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getCommandLineObjectExpansionDepth</div>

+								<div class="methodsignature"><code>Number <strong>getCommandLineObjectExpansionDepth</strong>()</code></div>

+								<div class="summary">

+									Returns the number of levels to expand when an object value is logged to the console.

+									Each property of an object above this threshold will be expanded if it is itself an object

+									or array, otherwise its string representation will be displayed. Default value is 1 (i.e.

+									the properties of the object logged will be displayed in their string representation but

+									not expanded).

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setCommandLineObjectExpansionDepth:</div>

+								<div class="methodsignature"><code>void <strong>setCommandLineObjectExpansionDepth</strong>(Number <em>expansionDepth</em>)</code></div>

+								<div class="summary">

+									Sets the number of levels to expand when an object value is logged to the console.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getCommandWindow</div>

+								<div class="methodsignature"><code>Window <strong>getCommandWindow</strong>()</code></div>

+								<div class="summary">

+									Returns a reference to the window in which commands typed into the command line

+									are currently being executed.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setCommandWindow</div>

+								<div class="methodsignature"><code>void <strong>setCommandWindow</strong>(Window <em>commandWindow</em>)</code></div>

+								<div class="summary">

+									Sets the window in which commands typed into the command line are executed.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getCommandLayout</div>

+								<div class="methodsignature"><code>Number <strong>getCommandLayout</strong>()</code></div>

+								<div class="summary">

+									Returns the layout used to format the output for commands typed into the command line.

+									The default value is a <code><a href="#patternlayout">PatternLayout</a></code> with

+									pattern string <code>%m</code>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setCommandLayout</div>

+								<div class="methodsignature"><code>void <strong>setCommandLayout</strong>(Layout <em>commandLayout</em>)</code></div>

+								<div class="summary">

+									Sets the layout used to format the output for commands typed into the command line.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">clear</div>

+								<div class="methodsignature"><code>void <strong>clear</strong>()</code></div>

+								<div class="summary">

+									Clears all messages from the console window.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">show</div>

+								<div class="methodsignature"><code>void <strong>show</strong>()</code></div>

+								<div class="summary">

+									<p>

+										Shows / unhides the console window.

+									</p>

+									<p><strong>Notes</strong></p>

+									<ul>

+										<li>

+											In Safari (and possibly other browsers), hiding an <code>iframe</code>

+											resets its document, thus destroying the console window.

+										</li>

+									</ul>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">hide</div>

+								<div class="methodsignature"><code>void <strong>hide</strong>()</code></div>

+								<div class="summary">

+									<p>

+										Hides / minimizes the console window.

+									</p>

+									<p><strong>Notes</strong></p>

+									<ul>

+										<li>

+											In Safari (and possibly other browsers), hiding an <code>iframe</code>

+											resets its document, thus destroying the console window.

+										</li>

+									</ul>

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">close</div>

+								<div class="methodsignature"><code>void <strong>close</strong>()</code></div>

+								<div class="summary">

+									Removes the console window iframe from the main document.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">focus</div>

+								<div class="methodsignature"><code>void <strong>focus</strong>()</code></div>

+								<div class="summary">

+									Brings the console window to the top and gives it the focus.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">focusCommandLine</div>

+								<div class="methodsignature"><code>void <strong>focusCommandLine</strong>()</code></div>

+								<div class="summary">

+									Brings the console window to the top and gives the focus to the command line.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">focusSearch</div>

+								<div class="methodsignature"><code>void <strong>focusSearch</strong>()</code></div>

+								<div class="summary">

+									Brings the console window to the top and gives the focus to the search box.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">evalCommandAndAppend</div>

+								<div class="methodsignature"><code>void <strong>evalCommandAndAppend</strong>(String <em>expr</em>)</code></div>

+								<div class="summary">

+									Evaluates the expression and appends the result to the console.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">addCommandLineFunction</div>

+								<div class="methodsignature"><code>void <strong>addCommandLineFunction</strong>(String <em>functionName</em>, Function <em>commandLineFunction</em>)</code></div>

+								<div class="summary">

+									<p>

+										Adds a function with the name specified to the list of functions available on the command line.

+										This feature may be used to add custom functions to the command line.

+									</p>

+									<p>

+										When you call the function on the command line, <code>commandLineFunction</code> is executed with the

+										following three parameters:

+									</p>

+									<ul>

+										<li><em>appender</em>. A reference to the appender in which the command was executed;</li>

+										<li><em>args</em>.

+											An array-like list of parameters passed into the function on the command line

+											(actually a reference to an <code>arguments</code> object);</li>

+										<li><em>returnValue</em>. This is an object with two properties that allow the function to control

+											how the result is displayed:

+											<ul>

+												<li><em>appendResult</em>. A boolean value that determines whether the returned value from this

+													function is appended to the console. The default value is <code>true</code>;</li>

+												<li><em>isError</em>. A boolean value that specifies whether the output of this function

+													should be displayed as an error. The default value is <code>false</code>.</li>

+											</ul>

+										</li>

+									</ul>

+									<p>

+										The value returned by the function is formatted by the command layout and appended to the console.

+									</p>

+								</div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="browserconsoleappender">

+						<h3>BrowserConsoleAppender</h3>

+						<p class="editions">Editions: <strong>Standardl</strong></p>

+						<p>

+							Writes log messages to the browser's built-in console, if present. This only works

+							currently in Safari, Opera and Firefox with the excellent

+							<a href="http://www.getfirebug.com" title="Firebug home page (opens in new window)"

+							target="_blank">Firebug</a> extension installed.

+						</p>

+						<p><strong>Notes</strong></p>

+						<ul>

+							<li>

+								As of log4javascript 1.3, the default threshold for this appender is <code>DEBUG</code>

+								as opposed to <code>WARN</code> as it was previously;

+							</li>

+							<li>

+								<p>

+									As of version 1.3, log4javascript has explicit support for Firebug's logging. This includes

+									the following mapping of log4javascript's log levels onto Firebug's:

+								</p>

+								<ul>

+									<li>log4javascript <code>TRACE</code>, <code>DEBUG</code> -&gt; Firebug <code>debug</code></li>

+									<li>log4javascript <code>INFO</code> -&gt; Firebug <code>info</code></li>

+									<li>log4javascript <code>WARN</code> -&gt; Firebug <code>warn</code></li>

+									<li>log4javascript <code>ERROR</code>, <code>FATAL</code> -&gt; Firebug <code>error</code></li>

+								</ul>

+								<p>

+									... and the ability to pass objects into Firebug and take advantage of its object inspection.

+									This is because the default layout is now <code><a href="#nulllayout">NullLayout</a></code>,

+									which performs no formatting on an object.

+								</p>

+							</li>

+						</ul>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">BrowserConsoleAppender</div>

+								<div class="methodsignature"><code><strong>BrowserConsoleAppender</strong>()</code></div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+				</div>

+				<div id="layouts">

+					<h2>Layouts</h2>

+					<div id="layout">

+						<h3>Layout</h3>

+						<p>

+							There are a few methods common to all layouts:

+						</p>

+						<h4>Methods</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">format</div>

+								<div class="methodsignature"><code>String <strong>format</strong>(LoggingEvent <em>loggingEvent</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">loggingEvent</code>

+									</li>

+								</ul>

+								<div class="summary">

+									Formats the log message. You should override this method in your own layouts.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">ignoresThrowable</div>

+								<div class="methodsignature"><code>Boolean <strong>ignoresThrowable</strong>()</code></div>

+								<div class="summary">

+									Returns whether the layout ignores an error object in a logging event passed

+									to its <code>format</code> method.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getContentType</div>

+								<div class="methodsignature"><code>String <strong>getContentType</strong>()</code></div>

+								<div class="summary">

+									Returns the content type of the output of the layout.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">allowBatching</div>

+								<div class="methodsignature"><code>Boolean <strong>allowBatching</strong>()</code></div>

+								<div class="summary">

+									Returns whether the layout's output is suitable for batching.

+									<code><a href="#jsonlayout">JsonLayout</a></code> and <code><a href="#xmllayout">XmlLayout</a></code>

+									are the only built-in layouts that return true for this method.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">getDataValues</div>

+								<div class="methodsignature"><code>Array <strong>getDataValues</strong>(LoggingEvent <em>loggingEvent</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">loggingEvent</code>

+									</li>

+								</ul>

+								<div class="summary">

+									Used internally by log4javascript in constructing formatted output for some layouts.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setKeys</div>

+								<div class="methodsignature"><code>void <strong>setKeys</strong>(String <em>loggerKey</em>,

+									String <em>timeStampKey</em>, String <em>levelKey</em>, String <em>messageKey</em>,

+									String <em>exceptionKey</em>, String <em>urlKey</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">loggerKey</code>

+										<div>

+											Parameter to use for the log message's logger name. Default is <code>logger</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">timeStampKey</code>

+										<div>

+											Parameter to use for the log message's timestamp.  Default is <code>timestamp</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">levelKey</code>

+										<div>

+											Parameter to use for the log message's level. Default is <code>level</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">messageKey</code>

+										<div>

+											Parameter to use for the message itself. Default is <code>message</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">exceptionKey</code>

+										<div>

+											Parameter to use for the log message's error (exception). Default is <code>exception</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">urlKey</code>

+										<div>

+											Parameter to use for the current page URL. Default is <code>url</code>.

+										</div>

+									</li>

+								</ul>

+								<div class="summary">

+									This method is used to change the default keys used to create formatted name-value pairs

+									for the properties of a log message, for layouts that do this. These layouts are

+									<code><a href="#jsonlayout">JsonLayout</a></code> and

+									<code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setCustomField</div>

+								<div class="methodsignature"><code>void <strong>setCustomField</strong>(String <em>name</em>,

+									String <em>value</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">name</code>

+										<div>

+											Name of the custom property you wish to be included in the formmtted output.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">value</code>

+										<div>

+											Value of the custom property you wish to be included in the formatted output.

+										</div>

+									</li>

+								</ul>

+								<div class="summary">

+									Some layouts (<code><a href="#jsonlayout">JsonLayout</a></code>,

+									<code><a href="#httppostdatalayout">HttpPostDataLayout</a></code>,

+									<code><a href="#patternlayout">PatternLayout</a></code> and

+									<code><a href="#xmllayout">XmlLayout</a></code>) allow you to set

+									custom fields (e.g. a session id to send to the server) to the

+									formatted output. Use this method to set a custom field. If there

+									is already a custom field with the specified name, its value will

+									be updated with <code>value</code>.

+								</div>

+								<p><strong>Notes</strong></p>

+								<ul>

+									<li>

+										<p>

+											From version 1.4, the custom field value may be a function. In this

+											case, the function is run at the time the layout's format method is called,

+											with the following two parameters:

+										</p>

+										<ul>

+											<li><em>layout</em>. A reference to the layout being used;</li>

+											<li><em>loggingEvent</em>. A reference to the logging event being formatted.</li>

+										</ul>

+									</li>

+								</ul>

+							</li>

+							<li class="method">

+								<div class="name">hasCustomFields</div>

+								<div class="methodsignature"><code>Boolean <strong>hasCustomFields</strong>()</code></div>

+								<div class="summary">

+									Returns whether the layout has any custom fields.

+								</div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="nulllayout">

+						<h3>NullLayout</h3>

+						<p class="editions">Editions: <strong>All</strong></p>

+						<p>

+							The most basic layout. NullLayout's <code>format()</code> methods performs no

+							formatting at all and simply returns the message logged.

+						</p>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">NullLayout</div>

+								<div class="methodsignature"><code><strong>NullLayout</strong>()</code></div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="simplelayout">

+						<h3>SimpleLayout</h3>

+						<p class="editions">Editions: <strong>Standard, Production</strong></p>

+						<p>

+							Provides basic formatting. SimpleLayout consists of the level of the log statement,

+							followed by " - " and then the log message itself. For example,

+						</p>

+						<p><code>DEBUG - Hello world</code></p>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">SimpleLayout</div>

+								<div class="methodsignature"><code><strong>SimpleLayout</strong>()</code></div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="patternlayout">

+						<h3>PatternLayout</h3>

+						<p class="editions">Editions: <strong>All</strong></p>

+						<p>

+							Provides a flexible way of formatting a log message by means of a conversion pattern

+							string. The behaviour of this layout is a full implementation of <code>PatternLayout</code>

+							in log4j, with the exception of the set of conversion characters - log4javascript's is

+							necessarily a subset of that of log4j with a few additions of its own, since many of

+							the conversion characters in log4j only make sense in the context of Java.

+						</p>

+						<p>

+							The conversion pattern consists of literal text interspersed with special strings starting with

+							a % symbol called <em>conversion specifiers</em>. A conversion specifier consists of the

+							% symbol, a conversion character (possible characters are listed below) and

+							<em>format modifiers</em>. For full documentation of the conversion pattern, see

+							<a href="http://logging.apache.org/log4j/docs/api/org/apache/log4j/PatternLayout.html" target="_blank">log4j's

+							documentation</a>. Below is a list of all conversion characters available in log4javascript.

+						</p>

+						<h4>Conversion characters</h4>

+						<table border="1" cellspacing="0">

+							<thead>

+								<tr>

+									<th>Conversion Character</th>

+									<th>Effect</th>

+								</tr>

+							</thead>

+							<tbody>

+								<tr>

+									<td>a</td>

+									<td>

+										<p>

+											Outputs log messages specified as an array.

+										</p>

+										<p>

+											Behaves exactly like <code>%m</code>, except that multiple log messages are

+											assumed to have been specified in the logging call as an array rather than

+											as multiple parameters.

+										</p>

+										<p>

+											<strong>Since: 1.4</strong>

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>c</td>

+									<td>

+										<p>

+											Outputs the logger name.

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>d</td>

+									<td>

+										<p>

+											Outputs the date of the logging event. The date conversion specifier

+											may be followed by a date format specifier enclosed between braces. For

+											example, <code>%d{HH:mm:ss,SSS}</code> or

+											<code>%d{dd MMM yyyy HH:mm:ss,SSS}</code>. If no date

+											format specifier is given then ISO8601 format is assumed.

+										</p>

+										<p>

+											The date format specifier is the same as that used by Java's

+											<code><a href="http://java.sun.com/j2se/1.5.0/docs/api/java/text/SimpleDateFormat.html"

+												target="_blank">SimpleDateFormat</a></code>. log4javascript

+											includes a full implementation of SimpleDateFormat's

+											<code>format</code> method, with the exception of the pattern letter

+											'z', (string representation of the timezone) for which the information

+											is not available in JavaScript.

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>f</td>

+									<td>

+										<p>

+											Outputs the value of a custom field set on the layout. If present, the specifier gives

+											the index in the array of custom fields to use; otherwise, the first custom field in the

+											array is used.

+										</p>

+										<p>

+											<strong>Since: 1.3</strong>

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>m</td>

+									<td>

+										<p>

+											Outputs the log messages of the logging event (i.e. the log

+											messages supplied by the client code).

+										</p>

+										<p>

+											As of version 1.4, multiple log messages may be supplied to logging calls.

+											<code>%m</code> displays each log message (using the rules below) one after

+											another, separated by spaces. 

+										</p>

+										<p>

+											As of version 1.3, an object may be specified as the log message and will

+											be expanded to show its properties in the output, provided that a specifier

+											containing the number of levels to expand is provided. If no specifier is

+											provided then the message will be treated as a string regardless of its type.

+											For example, <code>%m{1}</code> will display an expansion of the object one

+											level deep, i.e. each property of the object will be displayed but if the

+											property value is itself an object it will not be expanded and will appear

+											as <code>[object Object]</code>.

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>n</td>

+									<td>

+										<p>

+											Outputs a line separator.

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>p</td>

+									<td>

+										<p>

+											Outputs the level of the logging event.

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>r</td>

+									<td>

+										<p>

+											Outputs the number of milliseconds since log4javascript was initialized.

+										</p>

+									</td>

+								</tr>

+								<tr>

+									<td>%</td>

+									<td>

+										<p>

+											The sequence %% outputs a single percent sign.

+										</p>

+									</td>

+								</tr>

+							</tbody>

+						</table>

+						<h4>Static properties</h4>

+						<ul class="propertieslist">

+							<li class="property">

+								<div class="name">TTCC_CONVERSION_PATTERN</div>

+								<div class="summary">

+									Built-in conversion pattern, equivalent to <code>%r %p %c - %m%n</code>.

+								</div>

+							</li>

+							<li class="property">

+								<div class="name">DEFAULT_CONVERSION_PATTERN</div>

+								<div class="summary">

+									Built-in conversion pattern, equivalent to <code>%m%n</code>.

+								</div>

+							</li>

+							<li class="property">

+								<div class="name">ISO8601_DATEFORMAT</div>

+								<div class="summary">

+									Built-in date format (and also the default), equivalent to

+									<code>yyyy-MM-dd HH:mm:ss,SSS</code>.

+								</div>

+							</li>

+							<li class="property">

+								<div class="name">DATETIME_DATEFORMAT</div>

+								<div class="summary">

+									Built-in date format, equivalent to <code>dd MMM YYYY HH:mm:ss,SSS</code>.

+								</div>

+							</li>

+							<li class="property">

+								<div class="name">ABSOLUTETIME_DATEFORMAT</div>

+								<div class="summary">

+									Built-in date format, equivalent to <code>HH:mm:ss,SSS</code>.

+								</div>

+							</li>

+						</ul>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">PatternLayout</div>

+								<div class="methodsignature"><code><strong>PatternLayout</strong>(String <em>pattern</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">pattern</code>

+										<div>

+											The conversion pattern string to use.

+										</div>

+									</li>

+								</ul>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="xmllayout">

+						<h3>XmlLayout</h3>

+						<p class="editions">Editions: <strong>Standard, Production</strong></p>

+						<p>

+							Based on log4j's <code>XmlLayout</code>, this layout formats a log message as a

+							fragment of XML. An example of the format of the fragment is as follows:

+						</p>

+						<pre>

+&lt;log4javascript:event logger="[default]" timestamp="1201048234203" level="ERROR"&gt;

+&lt;log4javascript:message&gt;&lt;![CDATA[Big problem!]]&gt;&lt;/log4javascript:message&gt;

+&lt;log4javascript:exception&gt;&lt;![CDATA[Nasty error on line number 1

+	in file http://log4javascript.org/test.html]]&gt;&lt;/log4javascript:exception&gt;

+&lt;/log4javascript:event&gt;

+</pre>

+						<p><strong>Notes</strong></p>

+						<ul>

+							<li>

+								This layout supports batching of log messages when used in an

+								<code><a href="#ajaxappender">AjaxAppender</a></code>. A batch of

+								messages is simply concatenated to form a string of several XML

+								frgaments similar to that above.

+							</li>

+							<li>

+								The <code>&lt;log4javascript:exception&gt;</code> element is only present if an

+								exception was passed into the original log call.

+							</li>

+							<li>

+								As of version 1.4, timestamps are returned as milliseconds since midnight of

+								January 1, 1970 rather than seconds as in previous versions. This allows finer

+								measurement of the time a logging event occurred and is also the JavaScript

+								<code>Date</code> object's standard measurement.

+							</li>

+							<li>

+								Also as of version 1.4, multiple messages may be specified as separate parameters

+								in a single logging call. In <code>XmlLayout</code>, multiple messages may be

+								formatted as a single combined message or may be formated as several

+								<code>&lt;log4javascript:message&gt;</code> elements inside one

+								<code>&lt;log4javascript:messages&gt;</code> element as shown below:

+								<br />

+								<pre>

+&lt;log4javascript:event logger="[default]" timestamp="1201048234203" level="ERROR"&gt;

+&lt;log4javascript:messages&gt;

+	&lt;log4javascript:message&gt;&lt;![CDATA[Big problem!]]&gt;&lt;/log4javascript:message&gt;

+	&lt;log4javascript:message&gt;&lt;![CDATA[Value of x when this error

+		occurred: 3]]&gt;&lt;/log4javascript:message&gt;

+&lt;/log4javascript:messages&gt;

+&lt;log4javascript:exception&gt;&lt;![CDATA[Nasty error on line number 1

+	in file http://log4javascript.org/test.html]]&gt;&lt;/log4javascript:exception&gt;

+&lt;/log4javascript:event&gt;

+</pre>

+							</li>

+							<li>

+								As of version 1.3, custom fields may be added to the output. Each field will

+								add a tag of the following form inside the <code>&lt;log4javascript:event&gt;</code>

+								tag:

+								<br />

+								<pre>

+&lt;log4javascript:customfield name="sessionid"&gt;&lt;![CDATA[1234]]&gt;&lt;/log4javascript:customfield&gt;

+</pre>

+							</li>

+						</ul>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">XmlLayout</div>

+								<div class="methodsignature"><code><strong>XmlLayout</strong>([Boolean <em>combineMessages</em>])</code></div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">combineMessages</code>

+										<div>

+											Whether or not to format multiple log messages as a combined single

+											<code>&lt;log4javascript:message&gt;</code> element

+											composed of each individual message separated by line breaks or to include

+											a <code>&lt;log4javascript:message&gt;</code> element for each message inside

+											one <code>&lt;log4javascript:messages&gt;</code> element.

+											If not specified, defaults to <code>true</code>.

+										</div>

+									</li>

+								</ul>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+					<div id="jsonlayout">

+						<h3>JsonLayout</h3>

+						<p class="editions">Editions: <strong>Standard, Production</strong></p>

+						<p>

+							Formats a logging event into JavaScript Object Notation (JSON).

+							JSON is a subset of JavaScript's object literal syntax, meaning that log

+							messages formatted with this layout can be interpreted directly by JavaScript

+							and converted into objects. See

+							<a href="http://json.org/" target="_blank" title="json.org (opens in new window)">json.org</a> for more details

+							about JSON.

+						</p>

+						<p>Example:</p>

+						<pre>

+{

+	"logger": "[default]",

+	"timeStamp": 1201048234203,

+	"level": "ERROR",

+	"url": "http://log4javascript.org/test.html",

+	"message": "Big problem!",

+	"exception": "Nasty error on line number 1 in file

+		http://log4javascript.org/test.html"

+}

+</pre>

+						<p>

+							The <code>exception</code> property is only present if an exception was passed

+							into the original log call.

+						</p>

+						<p><strong>Notes</strong></p>

+						<ul>

+							<li>

+								This layout supports batching of log messages when used in an

+								<code><a href="#ajaxappender">AjaxAppender</a></code>. When sent singly

+								the layout formats the log message as a single JavaScript object literal;

+								when sent as a batch, the messages are formatted as an array literal whose

+								elements are log message objects.

+							</li>

+							<li>

+								<p>

+									As of version 1.3, custom fields may be added to the output. Each field will

+									add a property of the following form to the main object literal:

+								</p>

+								<pre>

+	"sessionid": 1234

+</pre>

+							</li>

+							<li>

+								From version 1.4, the variable names used for log event properties such as

+								the message, timestamp and exception are specified using the <code>setKeys()</code>

+								method of <code><a href="#layout">Layout</a></code>.

+							</li>

+							<li>

+								<p>

+									Also as of version 1.4, multiple messages may be specified as separate parameters

+									in a single logging call. In <code>JsonLayout</code>, multiple messages may be

+									formatted as a single combined message or may be formated as an array of messages

+									as shown below:

+								</p>

+								<pre>

+{

+	"logger": "[default]",

+	"timeStamp": 1201048234203,

+	"level": "ERROR",

+	"url": "http://log4javascript.org/test.html",

+	"message": [

+		"Big problem!",

+		"Value of x when this error occurred: 3"

+	],

+	"exception": "Nasty error on line number 1 in file

+		http://log4javascript.org/test.html"

+}

+</pre>

+							</li>

+						</ul>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">JsonLayout</div>

+								<div class="methodsignature"><code><strong>JsonLayout</strong>([Boolean <em>readable</em>, Boolean <em>combineMessages</em>])</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">readable</code>

+										<div>

+											Whether or not to format each log message with line breaks and tabs.

+											If not specified, defaults to <code>false</code>.

+										</div>

+									</li>

+									<li class="param">

+										<code class="paramname">combineMessages</code>

+										<div>

+											Whether or not to format multiple log messages as a combined single

+											<code>message</code> property composed of each individual message separated by line

+											breaks or to format multiple messages as an array.

+											If not specified, defaults to <code>true</code>.

+										</div>

+									</li>

+								</ul>

+							</li>

+						</ul>

+						<h4>Methods</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">isReadable</div>

+								<div class="methodsignature"><code>Boolean <strong>isReadable</strong>()</code></div>

+								<div class="summary">

+									Returns whether or not to each log message is formatted with line breaks and tabs.

+								</div>

+								<p><strong>Notes</strong></p>

+								<ul>

+									<li>

+										<p>

+											<code>setReadable</code> has been removed in version 1.4. This property can

+											be set via the constructor.

+										</p>

+									</li>

+								</ul>

+							</li>

+						</ul>

+					</div>

+					<div id="httppostdatalayout">

+						<h3>HttpPostDataLayout</h3>

+						<p class="editions">Editions: <strong>Standard, Production</strong></p>

+						<p>

+							Formats the log message as a simple URL-encoded string from which a simple

+							server-side script may extract parameters such as the log message, severity

+							and timestamp. This is the default layout for

+							<code><a href="#ajaxappender">AjaxAppender</a></code>.

+						</p>

+						<h4>Constructor</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">HttpPostDataLayout</div>

+								<div class="methodsignature"><code><strong>HttpPostDataLayout</strong>()</code></div>

+							</li>

+						</ul>

+						<p><strong>Notes</strong></p>

+						<ul>

+							<li>

+								As of version 1.3, custom fields may be added to the output. Each field will

+								be added as a parameter to the post data.

+							</li>

+							<li>

+								From version 1.4, the variable names used for log event properties such as

+								the message, timestamp and exception are specified using the <code>setKeys()</code>

+								method of <code><a href="#layout">Layout</a></code>.

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+				</div>

+				<div id="enabling">

+					<h2>Enabling / disabling log4javascript</h2>

+					<p>

+						All logging can be enabled or disabled in log4javascript in a number of ways:

+					</p>

+					<ul>

+						<li>

+							At any time, you can call

+							<code>log4javascript.setEnabled(<em>enabled</em>)</code>. This will

+							enable or disable all logging, depending on whether <code>enabled</code>

+							is set to <code>true</code> or <code>false</code>.

+						</li>

+						<li>

+							<p>

+								Assign a value to the global variable <code>log4javascript_disabled</code>.

+								The idea of this is so that you can enable or disable logging for a whole site by

+								including a JavaScript file in all your pages, and allowing this file to be

+								included <strong>before</strong> log4javascript.js to guarantee that no logging

+								can take place without having to alter log4javascript.js itself. Your included

+								.js file would include a single line such as the following:

+							</p>

+							<p>

+								<code>var log4javascript_disabled = true;</code>

+							</p>

+						</li>

+						<li>

+							Assign your logger object a value of <code>log4javascript.getNullLogger()</code>.

+						</li>

+						<li>

+							Replace your copy of log4javascript_x.js with stubs/log4javascript_x.js, provided in the

+							distribution. This file has a stub version of each of the functions and methods

+							in the log4javascript API and can simply be dropped in in place of the main file.

+							The compressed version of the stub is typically 15 times smaller than the

+							compressed version of the main file.

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="errorhandling">

+					<h2>log4javascript error handling</h2>

+					<p>

+						log4javascript has a single rudimentary logger-like object of its own to handle

+						messages generated by log4javascript itself. This logger is called <code>LogLog</code>

+						and is accessed via <code>log4javascript.logLog</code>.

+					</p>

+					<div id="loglog">

+						<h4>Methods</h4>

+						<ul class="propertieslist">

+							<li class="method">

+								<div class="name">setQuietMode</div>

+								<div class="methodsignature"><code>void <strong>setQuietMode</strong>(Boolean <em>quietMode</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">quietMode</code>

+										<div>

+											Whether to turn quiet mode on or off.

+										</div>

+									</li>

+								</ul>

+								<div class="summary">

+									Sets whether <code>LogLog</code> is in quiet mode or not. In quiet mode, no

+									messages sent to <code>LogLog</code> have any visible effect. By default,

+									quiet mode is switched off.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">setAlertAllErrors</div>

+								<div class="methodsignature"><code>void <strong>setAlertAllErrors</strong>(Boolean <em>alertAllErrors</em>)</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">showAllErrors</code>

+										<div>

+											Whether to show all errors or just the first.

+										</div>

+									</li>

+								</ul>

+								<div class="summary">

+									Sets how many errors <code>LogLog</code> will display alerts for. By default,

+									only the first error encountered generates an alert to the user. If you turn

+									all errors on by supplying <code>true</code> to this method then all errors

+									will generate alerts.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">debug</div>

+								<div class="methodsignature"><code>void <strong>debug</strong>(String <em>message</em>[, Error <em>exception</em>])</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">message</code>

+									</li>

+									<li class="param">

+										<code class="paramname">exception</code>

+										[<em>optional</em>]

+									</li>

+								</ul>

+								<div class="summary">

+									Logs a debugging message to an in-memory list. This implementation is new in version 1.4.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">displayDebug</div>

+								<div class="methodsignature"><code>void <strong>displayDebug</strong>()</code></div>

+								<div class="summary">

+									Displays an alert of all debugging messages. This method is new in version 1.4.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">warn</div>

+								<div class="methodsignature"><code>void <strong>warn</strong>(String <em>message</em>[, Error <em>exception</em>])</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">message</code>

+									</li>

+									<li class="param">

+										<code class="paramname">exception</code>

+										[<em>optional</em>]

+									</li>

+								</ul>

+								<div class="summary">

+									Currently has no effect.

+								</div>

+							</li>

+							<li class="method">

+								<div class="name">error</div>

+								<div class="methodsignature"><code>void <strong>error</strong>(String <em>message</em>[, Error <em>exception</em>])</code></div>

+								<div class="paramsheading">Parameters:</div>

+								<ul class="params">

+									<li class="param">

+										<code class="paramname">message</code>

+									</li>

+									<li class="param">

+										<code class="paramname">exception</code>

+										[<em>optional</em>]

+									</li>

+								</ul>

+								<div class="summary">

+									Generates an alert to the user if and only if the error is the first one

+									encountered and <code>setAlertAllErrors(true)</code> has not been called.

+								</div>

+							</li>

+						</ul>

+						<p class="linktotop">

+							<a href="#container">Top</a>

+						</p>

+					</div>

+				</div>

+				<div id="differences">

+					<h2>Differences between log4javascript and log4j</h2>

+					<p>

+						For the sake of keeping log4javascript as light and useful as possible, many

+						of the features of log4j that seem over-complex or inappropriate for

+						JavaScript have not been implemented. These include:

+					</p>

+					<ul>

+						<li>Filters</li>

+						<li>Configurators</li>

+						<li>Renderers</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+  				</div>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/manual_lite.html b/planetstack/core/static/log4javascript-1.4.6/docs/manual_lite.html
new file mode 100644
index 0000000..74e5a7d
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/docs/manual_lite.html
@@ -0,0 +1,383 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript 1.4 Lite manual</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="index.html">docs</a>

+					| <a class="navitem" href="quickstart.html">quick start</a>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript 1.4 Lite manual</h1>

+				<h2>Contents</h2>

+				<ul>

+					<li><a href="#intro">Introduction</a></li>

+					<li><a href="#log4javascript">log4javascript static properties/methods</a></li>

+					<li><a href="#levels">Levels</a></li>

+					<li><a href="#loggers">Loggers</a></li>

+					<li><a href="#enabling">Enabling / disabling log4javascript Lite</a></li>

+				</ul>

+				<div id="intro">

+					<h2>Introduction</h2>

+					<p>

+						log4javascript Lite is designed to be a basic, lightweight, cross-browser logging tool. It

+						provides functions to log messages of different severity to a pop-up window using the exactly

+						the same syntax as log4javascript. It is designed for situations when the key requirement is just

+						to display logging messages without needing all the features of the standard version of

+						log4javascript. 

+					</p>

+					<p>

+						Below is the complete list of functions and properties available in log4javascript Lite.

+						They make up a small subset of those provided by the standard version of

+						log4javascript. Each function is <strong>named and called identically to the equivalent

+						function in log4javascript</strong>. Please refer to the

+						<a href="manual.html">log4javascript manual</a> for a detailed explanation

+						of all the concepts alluded to in this document.

+					</p>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="log4javascript">

+					<h2>log4javascript static properties/methods</h2>

+					<h4>Properties</h4>

+					<ul class="propertieslist">

+						<li class="property">

+							<div class="name">version</div>

+							<div class="summary">

+								The version number of your copy of log4javascript.

+							</div>

+						</li>

+						<li class="property">

+							<div class="name">edition</div>

+							<div class="summary">

+								The edition of your copy of log4javascript ("log4javascript_lite" in this case").

+							</div>

+						</li>

+					</ul>

+					<h4>Methods</h4>

+					<ul class="propertieslist">

+						<li class="method">

+							<div class="name">getDefaultLogger</div>

+							<div class="methodsignature"><code>Logger <strong>getDefaultLogger</strong>()</code></div>

+							<div class="summary">

+								Returns the default and only logger (apart from the null logger). The default logger

+								logs to a simple pop-up window.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getNullLogger</div>

+							<div class="methodsignature"><code>Logger <strong>getNullLogger</strong>()</code></div>

+							<div class="summary">

+								Returns an empty logger. Useful for disabling all logging.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">setEnabled</div>

+							<div class="methodsignature"><code>void <strong>setEnabled</strong>(Boolean <em>enabled</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">enabled</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Enables or disables all logging, depending on <code>enabled</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns true or false depending on whether logging is enabled.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">setShowStackTraces</div>

+							<div class="methodsignature"><code>void <strong>setShowStackTraces</strong>(Boolean <em>show</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">show</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Enables or disables displaying of error stack traces, depending on <code>show</code>.

+								By default, stack traces are not displayed. (Only works in Firefox)

+							</div>

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="levels">

+					<h2>Levels</h2>

+					<p>

+						Levels are available as static properties of the <code>log4javascript.Level</code>

+						object. In ascending order of severity:

+					</p>

+					<ol>

+						<li><code>log4javascript.Level.ALL</code></li>

+						<li><code>log4javascript.Level.TRACE</code></li>

+						<li><code>log4javascript.Level.DEBUG</code></li>

+						<li><code>log4javascript.Level.INFO</code></li>

+						<li><code>log4javascript.Level.WARN</code></li>

+						<li><code>log4javascript.Level.ERROR</code></li>

+						<li><code>log4javascript.Level.FATAL</code></li>

+						<li><code>log4javascript.Level.NONE</code></li>

+					</ol>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="loggers">

+					<h2>Loggers</h2>

+					<p>

+						There are only two loggers in log4javascript Lite: the default logger obtained

+						by calling <code>log4javascript.getDefaultLogger()</code> and the empty logger

+						returned by <code>log4javascript.getNullLogger()</code>.

+					</p>

+					<h4>Logger methods</h4>

+					<ul class="propertieslist">

+						<li class="method">

+							<div class="name">setLevel</div>

+							<div class="methodsignature"><code>void <strong>setLevel</strong>(Level <em>level</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">level</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Sets the level. Log messages of a lower level than <code>level</code> will not be logged.

+								Default value is <code>ALL</code> (unlike in log4javascript, where the default level is

+								<code>DEBUG</code>).

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">getLevel</div>

+							<div class="methodsignature"><code>Level <strong>getLevel</strong>()</code></div>

+							<div class="summary">

+								Returns the level for this logger.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">trace</div>

+							<div class="methodsignature"><code>void <strong>trace</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>TRACE</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">debug</div>

+							<div class="methodsignature"><code>void <strong>debug</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>DEBUG</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">info</div>

+							<div class="methodsignature"><code>void <strong>info</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>INFO</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">warn</div>

+							<div class="methodsignature"><code>void <strong>warn</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>WARN</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">error</div>

+							<div class="methodsignature"><code>void <strong>error</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>ERROR</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">fatal</div>

+							<div class="methodsignature"><code>void <strong>fatal</strong>(Object <em>message1</em>[, Object <em>message2</em>, ... ][, Error <em>exception</em>])</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">message1[, message2...]</code>

+								</li>

+								<li class="param">

+									<code class="paramname">exception</code>

+									[<em>optional</em>]

+								</li>

+							</ul>

+							<div class="summary">

+								Logs one or more messages and optionally an error at level <code>FATAL</code>.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isEnabledFor</div>

+							<div class="methodsignature"><code>Boolean <strong>isEnabledFor</strong>(Level <em>level</em>, Error <em>exception</em>)</code></div>

+							<div class="paramsheading">Parameters:</div>

+							<ul class="params">

+								<li class="param">

+									<code class="paramname">level</code>

+								</li>

+							</ul>

+							<div class="summary">

+								Returns whether the logger is enabled for the specified level. 

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isTraceEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isTraceEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>TRACE</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isDebugEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isDebugEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>DEBUG</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isInfoEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isInfoEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>INFO</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isWarnEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isWarnEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>WARN</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isErrorEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isErrorEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>ERROR</code> messages.

+							</div>

+						</li>

+						<li class="method">

+							<div class="name">isFatalEnabled</div>

+							<div class="methodsignature"><code>Boolean <strong>isFatalEnabled</strong>()</code></div>

+							<div class="summary">

+								Returns whether the logger is enabled for <code>FATAL</code> messages.

+							</div>

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+				<div id="enabling">

+					<h2>Enabling / disabling log4javascript Lite</h2>

+					<p>

+						All logging can be enabled or disabled in log4javascript Lite in a number of ways:

+					</p>

+					<ul>

+						<li>

+							At any time, you can call

+							<code>log4javascript.setEnabled(<em>enabled</em>)</code>. This will

+							enable or disable all logging, depending on whether <code>enabled</code>

+							is set to <code>true</code> or <code>false</code>.

+						</li>

+						<li>

+							Assign your logger object a value of <code>log4javascript.getNullLogger()</code>.

+						</li>

+						<li>

+							Replace your copy of log4javascript_lite.js with stubs/log4javascript_lite.js, provided in the

+							distribution. This file has a stub version of each of the functions and methods

+							in the log4javascript Lite API and can simply be dropped in in place of the main file.

+						</li>

+					</ul>

+					<p class="linktotop">

+						<a href="#container">Top</a>

+					</p>

+				</div>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/quickstart.html b/planetstack/core/static/log4javascript-1.4.6/docs/quickstart.html
new file mode 100644
index 0000000..3bffff5
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/docs/quickstart.html
@@ -0,0 +1,230 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript quick start tutorial</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="index.html">docs</a>

+					| <span class="navitem">quick start</span>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript quick start tutorial</h1>

+				<h2>Three step guide</h2>

+				<ol>

+					<li>

+						<h3>Download the code</h3>

+						<p>

+							Unzip the distribution and copy log4javascript.js into the desired

+							location. No other files are necessary.

+						</p>

+					</li>

+					<li>

+						<h3>Initialize log4javascript in your web page</h3>

+						<p>

+							Include log4javascript.js in your page using the code below. This

+							code assumes log4javascript is stored in the same directory as

+							your web page.

+						</p>

+						<pre class="code">

+&lt;script type="text/javascript" src="log4javascript.js"&gt;&lt;/script&gt;

+&lt;script type="text/javascript"&gt;

+	var log = log4javascript.getDefaultLogger();

+&lt;/script&gt;

+</pre>

+						<p>

+							The default logger uses a <code><a href="manual.html#popupappender">PopUpAppender</a></code>

+							which opens a pop-up window. By default, this window will open when the first

+							log message is written. For this to work, you will need to disable any pop-up blockers

+							you may have.

+						</p>

+					</li>

+					<li>

+						<h3>Include logging statements in your code</h3>

+						<p>

+							You have six logging methods at your disposal, depending on the severity

+							of the message you wish to log. By default, all messages are logged

+							in the pop-up window. The logging methods are:

+						</p>

+						<ul>

+							<li><code>log.trace(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>

+							<li><code>log.debug(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>

+							<li><code>log.info(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>

+							<li><code>log.warn(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>

+							<li><code>log.error(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>

+							<li><code>log.fatal(<em>message</em>[, <em>message2</em>, ... ][, <em>exception</em>])</code></li>

+						</ul>

+						<p>

+							And that's it, log away. Below are some examples of common types of logging.

+						</p>

+					</li>

+				</ol>

+				<h2>Logging examples</h2>

+				<ol>

+					<li>

+						<h3>A simple logging message string</h3>

+						<pre class="code">

+	log.info("Hello world");

+</pre>

+displays

+						<pre class="console info">

+19:52:03 INFO  - Hello world

+</pre>

+					</li>

+					<li>

+						<h3>Logging an error with a message</h3>

+						<pre class="code">

+	try {

+		throw new Error("Faking something going wrong!");

+	} catch (e) {

+		log.error("An error occurred", e);

+	}

+</pre>

+displays

+						<pre class="console error">

+19:52:32 ERROR - An error occurred

+Exception: Faking something going wrong! on line number 80 in file basic.html

+</pre>

+					</li>

+					<li>

+						<h3>Logging multiple messages with one logging call</h3>

+						<pre class="code">

+	var a = "Hello";

+	var b = 3;

+	log.debug(a, b);

+</pre>

+displays

+						<pre class="console debug">

+19:53:05 DEBUG  - Hello 3

+</pre>

+					</li>

+					<li>

+						<h3>Logging an object</h3>

+						<p>Logging an object:</p>

+						<pre class="code">

+	var obj = new Object();

+	obj.name = "Octopus";

+	obj.tentacles = 8;

+	log.info(obj);

+</pre>

+displays

+						<pre class="console info">

+19:53:17 INFO  - {

+	name: Octopus,

+	tentacles: 8

+}

+</pre>

+					</li>

+				</ol>

+				<h2>Tweaking the default logger</h2>

+				<p>

+					The default logger is fine as a starting point, but what if you want the default logger

+					with a few different options (say, bringing the pop-up to the front whenever a log message is

+					logged, or having new log messages appear at the top of the pop-up rather than the bottom)?

+				</p>

+				<p>

+					In this case, you will need to create a new logger, then create a

+					<code><a href="manual.html#popupappender">PopUpAppender</a></code>, set options

+					on it, and add it to the logger:

+				</p>

+				<pre class="code">

+&lt;script type="text/javascript" src="log4javascript.js"&gt;&lt;/script&gt;

+&lt;script type="text/javascript"&gt;

+	// Create the logger

+	var log = log4javascript.getLogger();

+

+	// Create a PopUpAppender with default options

+	var popUpAppender = new log4javascript.PopUpAppender();

+

+	// Change the desired configuration options

+	popUpAppender.setFocusPopUp(true);

+	popUpAppender.setNewestMessageAtTop(true);

+

+	// Add the appender to the logger

+	log.addAppender(popUpAppender);

+

+	// Test the logger

+	log.debug("Hello world!");

+&lt;/script&gt;

+</pre>

+				<p>

+					<a href="../examples/example_quickstart_1.html" title="View example (opens in new window)"

+						target="_blank">See this example in action</a> (opens in new window)

+				</p>

+				<p>

+					Refer to the manual for more information about

+					<a href="manual.html#configuration">configuring appenders</a> and more

+					details about <code><a href="manual.html#popupappender">PopUpAppender</a></code>.

+				</p>

+				<h2>Sending log messages to the server</h2>

+				<p>

+					For this you will need to use an <code><a href="manual.html#ajaxappender">AjaxAppender</a></code>

+					as follows:

+				</p>

+				<pre class="code">

+	var ajaxAppender = new log4javascript.AjaxAppender(<em>URL</em>);

+	log.addAppender(ajaxAppender);

+</pre>

+				<p>

+					Now your log messages will appear in the pop-up window and be sent

+					asynchronously to the URL you specify in the form of HTTP post parameters.

+					No server-side code to process these requests is provided with log4javascript.

+				</p>

+				<p>

+					See <code><a href="manual.html#ajaxappender">AjaxAppender</a></code> for more details

+					on formatting log messages.

+				</p>

+				<h2>Changing the format of log messages</h2>

+				<p>

+					Using a <code><a href="manual.html#layouts">Layout</a></code>, you can

+					format log messages however you like. For example:

+				</p>

+				<pre class="code">

+	var log = log4javascript.getLogger("mylogger");

+	var popUpAppender = new log4javascript.PopUpAppender();

+	var layout = new log4javascript.PatternLayout("[%-5p] %m");

+	popUpAppender.setLayout(layout);

+</pre>

+				<p>A call to</p>

+				<pre class="code">

+	log.debug("Hello world");

+</pre>

+				<p>will now result in output in the pop-up window of </p>

+				<pre class="console debug">

+[DEBUG] Hello world

+</pre>

+				<p>

+					See <code><a href="manual.html#patternlayout">PatternLayout</a></code> for more details

+					on formatting log messages.

+				</p>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/docs/whatsnew.html b/planetstack/core/static/log4javascript-1.4.6/docs/whatsnew.html
new file mode 100644
index 0000000..6e4e06f
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/docs/whatsnew.html
@@ -0,0 +1,86 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - what's new in version 1.4</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<link rel="stylesheet" type="text/css" media="screen,print" href="../main.css" title="Default" />

+	</head>

+	<body>

+		<div id="container" class="nonav">

+			<div id="header">

+				<h1><a href="index.html">log4javascript</a></h1>

+			</div>

+			<div id="content">

+				<div id="nav">

+					<a class="navitem" href="../index.html">home</a>

+					| <a class="navitem" href="http://sourceforge.net/projects/log4javascript" target="_blank" title="Download (opens in new window)">download</a>

+					| <a class="navitem" href="index.html">docs</a>

+					| <a class="navitem" href="quickstart.html">quick start</a>

+					| <a class="navitem" href="../demos/index.html">demos</a>

+					| <a class="navitem" href="http://log4javascript.org" target="_blank">website</a>

+					| <a class="navitem" href="http://www.timdown.co.uk" target="_blank">timdown.co.uk</a>

+				</div>

+				<h1>log4javascript - what's new in version 1.4</h1>

+				<ul>

+					<li>

+						log4javascript now comes in three different editions: Standard, Production

+						and Lite. <a href="distribution.html">Full details here</a>.

+					</li>

+					<li>

+						Loggers are now hierarchical and work exactly the same as log4j loggers.

+						This means that a logger with no level set on it inherits its level from its parent,

+						and inherits all of its parents appenders.

+					</li>

+					<li>

+						The logging console used by <code><a href="manual.html#popupappender">PopUpAppender</a></code> and

+						<code><a href="manual.html#inpageappender">InPageAppender</a></code>now has a command line, featuring

+						a command history navigated with the up and down arrow keys and a number of built-in command line

+						functions.

+					</li>

+					<li>

+						It is now possible to specify multiple messages in a single log call.

+					</li>

+					<li>

+						Log messages may be grouped in the logging console.

+					</li>

+					<li>

+						Built-in timers.

+					</li>

+					<li>

+						Improved <code><a href="manual.html#ajaxappender">AjaxAppender</a></code>, with the ability

+						to send all pending log calls to the server when navigating away from a page. Timestamps now

+						include milliseconds. All log messages or batches of log messages are now posted as

+						name-value pairs.

+					</li>

+					<li>

+						Support for IE8 beta 2.

+					</li>

+					<li>

+						Many minor enhancements and bug fixes. See the <a href="../changelog.txt">change log</a> for full

+						details.

+					</li>

+				</ul>

+				<p>

+					Please note that there are a few minor <a href="backwardsincompatibilities.html">incompatibilities

+					with earlier versions of log4javascript</a>.

+				</p>

+			</div>

+			<div id="footer">

+				<span class="externallinkinfo">

+					<strong>NB.</strong> All external links open in a new window.

+				</span>

+				Written by Tim Down. <a href="mailto:tim@log4javascript.org">tim@log4javascript.org</a>

+				<br />

+				log4javascript is distributed under the <a href="http://www.apache.org/licenses/LICENSE-2.0.html"

+					title="Apache License, Version 2.0 (opens in new window)" target="_blank">Apache License,

+					Version 2.0</a>

+

+			</div>

+		</div>

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/examples/demo.html b/planetstack/core/static/log4javascript-1.4.6/examples/demo.html
new file mode 100644
index 0000000..118b879
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/examples/demo.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript demo redirect</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="noindex" />

+		<meta http-equiv="refresh" content="0; url=../demos/basic.html" />

+	</head>

+	<body>

+		This page has been replaced by <a href="/demos/basic.html">the basic demo page</a>.

+		Please use this link if you are not redirected automatically.

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/examples/example_manual.html b/planetstack/core/static/log4javascript-1.4.6/examples/example_manual.html
new file mode 100644
index 0000000..68189e3
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/examples/example_manual.html
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript example from  manual</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<script type="text/javascript" src="../js/log4javascript.js"></script>

+		<script type="text/javascript">

+			//<![CDATA[

+			var log = log4javascript.getLogger();

+			var popUpAppender = new log4javascript.PopUpAppender();

+			var popUpLayout = new log4javascript.PatternLayout("%d{HH:mm:ss} %-5p - %m%n");

+			popUpAppender.setLayout(popUpLayout);

+			log.addAppender(popUpAppender);

+			var ajaxAppender = new log4javascript.AjaxAppender("myloggingservlet.do");

+			ajaxAppender.setThreshold(log4javascript.Level.ERROR);

+			log.addAppender(ajaxAppender);

+			log.debug("Debugging message (appears in pop-up)");

+			log.error("Error message (appears in pop-up and in server log)");

+			//]]>

+		</script>

+	</head>

+	<body>

+		<h1>log4javascript example from  manual</h1>

+

+

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/examples/example_quickstart_1.html b/planetstack/core/static/log4javascript-1.4.6/examples/example_quickstart_1.html
new file mode 100644
index 0000000..3ae4a9f
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/examples/example_quickstart_1.html
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript quick start example 1</title>

+		<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />

+		<meta name="author" content="Tim Down - tim@log4javascript.org" />

+		<meta name="description" content="log4javascript, a logging framework for JavaScript based on log4j" />

+		<meta name="robots" content="all" />

+		<script type="text/javascript" src="../js/log4javascript.js"></script>

+		<script type="text/javascript">

+			//<![CDATA[

+			// Create the logger

+			var log = log4javascript.getLogger(); 

+		

+			// Create a PopUpAppender with default options

+			var popUpAppender = new log4javascript.PopUpAppender();

+			

+			// Change the desired configuration options

+			popUpAppender.setFocusPopUp(true);

+			popUpAppender.setNewestMessageAtTop(true);

+			

+			// Add the appender to the logger

+			log.addAppender(popUpAppender);

+			

+			// Test the logger

+			log.debug("Hello world!");

+			//]]>

+		</script>

+	</head>

+	<body>

+		<h1>log4javascript quick start example 1</h1>

+	

+	

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/examples/myloggingservlet.do b/planetstack/core/static/log4javascript-1.4.6/examples/myloggingservlet.do
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/examples/myloggingservlet.do
diff --git a/planetstack/core/static/log4javascript-1.4.6/js/console.html b/planetstack/core/static/log4javascript-1.4.6/js/console.html
new file mode 100644
index 0000000..476d272
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/console.html
@@ -0,0 +1,263 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+<head>

+<title>log4javascript</title>

+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

+<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->

+<meta http-equiv="X-UA-Compatible" content="IE=7" />

+<script type="text/javascript">var isIe = false, isIePre7 = false;</script>

+<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->

+<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->

+<script type="text/javascript">

+//<![CDATA[

+var loggingEnabled=true;var logQueuedEventsTimer=null;var logEntries=[];var logEntriesAndSeparators=[];var logItems=[];var renderDelay=100;var unrenderedLogItemsExist=false;var rootGroup,currentGroup=null;var loaded=false;var currentLogItem=null;var logMainContainer;function copyProperties(obj,props){for(var i in props){obj[i]=props[i];}}

+function LogItem(){}

+LogItem.prototype={mainContainer:null,wrappedContainer:null,unwrappedContainer:null,group:null,appendToLog:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].appendToLog();}

+this.group.update();},doRemove:function(doUpdate,removeFromGroup){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].remove();}

+this.unwrappedElementContainer=null;this.wrappedElementContainer=null;this.mainElementContainer=null;}

+if(this.group&&removeFromGroup){this.group.removeChild(this,doUpdate);}

+if(this===currentLogItem){currentLogItem=null;}},remove:function(doUpdate,removeFromGroup){this.doRemove(doUpdate,removeFromGroup);},render:function(){},accept:function(visitor){visitor.visit(this);},getUnwrappedDomContainer:function(){return this.group.unwrappedElementContainer.contentDiv;},getWrappedDomContainer:function(){return this.group.wrappedElementContainer.contentDiv;},getMainDomContainer:function(){return this.group.mainElementContainer.contentDiv;}};LogItem.serializedItemKeys={LOG_ENTRY:0,GROUP_START:1,GROUP_END:2};function LogItemContainerElement(){}

+LogItemContainerElement.prototype={appendToLog:function(){var insertBeforeFirst=(newestAtTop&&this.containerDomNode.hasChildNodes());if(insertBeforeFirst){this.containerDomNode.insertBefore(this.mainDiv,this.containerDomNode.firstChild);}else{this.containerDomNode.appendChild(this.mainDiv);}}};function SeparatorElementContainer(containerDomNode){this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="separator";this.mainDiv.innerHTML="&nbsp;";}

+SeparatorElementContainer.prototype=new LogItemContainerElement();SeparatorElementContainer.prototype.remove=function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;};function Separator(){this.rendered=false;}

+Separator.prototype=new LogItem();copyProperties(Separator.prototype,{render:function(){var containerDomNode=this.group.contentDiv;if(isIe){this.unwrappedElementContainer=new SeparatorElementContainer(this.getUnwrappedDomContainer());this.wrappedElementContainer=new SeparatorElementContainer(this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new SeparatorElementContainer(this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}

+this.content=this.formattedMessage;this.rendered=true;}});function GroupElementContainer(group,containerDomNode,isRoot,isWrapped){this.group=group;this.containerDomNode=containerDomNode;this.isRoot=isRoot;this.isWrapped=isWrapped;this.expandable=false;if(this.isRoot){if(isIe){this.contentDiv=logMainContainer.appendChild(document.createElement("div"));this.contentDiv.id=this.isWrapped?"log_wrapped":"log_unwrapped";}else{this.contentDiv=logMainContainer;}}else{var groupElementContainer=this;this.mainDiv=document.createElement("div");this.mainDiv.className="group";this.headingDiv=this.mainDiv.appendChild(document.createElement("div"));this.headingDiv.className="groupheading";this.expander=this.headingDiv.appendChild(document.createElement("span"));this.expander.className="expander unselectable greyedout";this.expander.unselectable=true;var expanderText=this.group.expanded?"-":"+";this.expanderTextNode=this.expander.appendChild(document.createTextNode(expanderText));this.headingDiv.appendChild(document.createTextNode(" "+this.group.name));this.contentDiv=this.mainDiv.appendChild(document.createElement("div"));var contentCssClass=this.group.expanded?"expanded":"collapsed";this.contentDiv.className="groupcontent "+contentCssClass;this.expander.onclick=function(){if(groupElementContainer.group.expandable){groupElementContainer.group.toggleExpanded();}};}}

+GroupElementContainer.prototype=new LogItemContainerElement();copyProperties(GroupElementContainer.prototype,{toggleExpanded:function(){if(!this.isRoot){var oldCssClass,newCssClass,expanderText;if(this.group.expanded){newCssClass="expanded";oldCssClass="collapsed";expanderText="-";}else{newCssClass="collapsed";oldCssClass="expanded";expanderText="+";}

+replaceClass(this.contentDiv,newCssClass,oldCssClass);this.expanderTextNode.nodeValue=expanderText;}},remove:function(){if(!this.isRoot){this.headingDiv=null;this.expander.onclick=null;this.expander=null;this.expanderTextNode=null;this.contentDiv=null;this.containerDomNode=null;this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;}},reverseChildren:function(){var node=null;var childDomNodes=[];while((node=this.contentDiv.firstChild)){this.contentDiv.removeChild(node);childDomNodes.push(node);}

+while((node=childDomNodes.pop())){this.contentDiv.appendChild(node);}},update:function(){if(!this.isRoot){if(this.group.expandable){removeClass(this.expander,"greyedout");}else{addClass(this.expander,"greyedout");}}},clear:function(){if(this.isRoot){this.contentDiv.innerHTML="";}}});function Group(name,isRoot,initiallyExpanded){this.name=name;this.group=null;this.isRoot=isRoot;this.initiallyExpanded=initiallyExpanded;this.elementContainers=[];this.children=[];this.expanded=initiallyExpanded;this.rendered=false;this.expandable=false;}

+Group.prototype=new LogItem();copyProperties(Group.prototype,{addChild:function(logItem){this.children.push(logItem);logItem.group=this;},render:function(){if(isIe){var unwrappedDomContainer,wrappedDomContainer;if(this.isRoot){unwrappedDomContainer=logMainContainer;wrappedDomContainer=logMainContainer;}else{unwrappedDomContainer=this.getUnwrappedDomContainer();wrappedDomContainer=this.getWrappedDomContainer();}

+this.unwrappedElementContainer=new GroupElementContainer(this,unwrappedDomContainer,this.isRoot,false);this.wrappedElementContainer=new GroupElementContainer(this,wrappedDomContainer,this.isRoot,true);this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{var mainDomContainer=this.isRoot?logMainContainer:this.getMainDomContainer();this.mainElementContainer=new GroupElementContainer(this,mainDomContainer,this.isRoot,false);this.elementContainers=[this.mainElementContainer];}

+this.rendered=true;},toggleExpanded:function(){this.expanded=!this.expanded;for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].toggleExpanded();}},expand:function(){if(!this.expanded){this.toggleExpanded();}},accept:function(visitor){visitor.visitGroup(this);},reverseChildren:function(){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].reverseChildren();}}},update:function(){var previouslyExpandable=this.expandable;this.expandable=(this.children.length!==0);if(this.expandable!==previouslyExpandable){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].update();}}},flatten:function(){var visitor=new GroupFlattener();this.accept(visitor);return visitor.logEntriesAndSeparators;},removeChild:function(child,doUpdate){array_remove(this.children,child);child.group=null;if(doUpdate){this.update();}},remove:function(doUpdate,removeFromGroup){for(var i=0,len=this.children.length;i<len;i++){this.children[i].remove(false,false);}

+this.children=[];this.update();if(this===currentGroup){currentGroup=this.group;}

+this.doRemove(doUpdate,removeFromGroup);},serialize:function(items){items.push([LogItem.serializedItemKeys.GROUP_START,this.name]);for(var i=0,len=this.children.length;i<len;i++){this.children[i].serialize(items);}

+if(this!==currentGroup){items.push([LogItem.serializedItemKeys.GROUP_END]);}},clear:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clear();}}});function LogEntryElementContainer(){}

+LogEntryElementContainer.prototype=new LogItemContainerElement();copyProperties(LogEntryElementContainer.prototype,{remove:function(){this.doRemove();},doRemove:function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;this.contentElement=null;this.containerDomNode=null;},setContent:function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=content;}},setSearchMatch:function(isMatch){var oldCssClass=isMatch?"searchnonmatch":"searchmatch";var newCssClass=isMatch?"searchmatch":"searchnonmatch";replaceClass(this.mainDiv,newCssClass,oldCssClass);},clearSearch:function(){removeClass(this.mainDiv,"searchmatch");removeClass(this.mainDiv,"searchnonmatch");}});function LogEntryWrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.mainDiv.className="logentry wrapped "+this.logEntry.level;this.contentElement=this.mainDiv;}

+LogEntryWrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryWrappedElementContainer.prototype.setContent=function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=wrappedContent;}};function LogEntryUnwrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry unwrapped "+this.logEntry.level;this.pre=this.mainDiv.appendChild(document.createElement("pre"));this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.pre.className="unwrapped";this.contentElement=this.pre;}

+LogEntryUnwrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryUnwrappedElementContainer.prototype.remove=function(){this.doRemove();this.pre=null;};function LogEntryMainElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry nonielogentry "+this.logEntry.level;this.contentElement=this.mainDiv.appendChild(document.createElement("span"));this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));}

+LogEntryMainElementContainer.prototype=new LogEntryElementContainer();function LogEntry(level,formattedMessage){this.level=level;this.formattedMessage=formattedMessage;this.rendered=false;}

+LogEntry.prototype=new LogItem();copyProperties(LogEntry.prototype,{render:function(){var logEntry=this;var containerDomNode=this.group.contentDiv;if(isIe){this.formattedMessage=this.formattedMessage.replace(/\r\n/g,"\r");this.unwrappedElementContainer=new LogEntryUnwrappedElementContainer(this,this.getUnwrappedDomContainer());this.wrappedElementContainer=new LogEntryWrappedElementContainer(this,this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new LogEntryMainElementContainer(this,this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}

+this.content=this.formattedMessage;this.rendered=true;},setContent:function(content,wrappedContent){if(content!=this.content){if(isIe&&(content!==this.formattedMessage)){content=content.replace(/\r\n/g,"\r");}

+for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setContent(content,wrappedContent);}

+this.content=content;}},getSearchMatches:function(){var matches=[];var i,len;if(isIe){var unwrappedEls=getElementsByClass(this.unwrappedElementContainer.mainDiv,"searchterm","span");var wrappedEls=getElementsByClass(this.wrappedElementContainer.mainDiv,"searchterm","span");for(i=0,len=unwrappedEls.length;i<len;i++){matches[i]=new Match(this.level,null,unwrappedEls[i],wrappedEls[i]);}}else{var els=getElementsByClass(this.mainElementContainer.mainDiv,"searchterm","span");for(i=0,len=els.length;i<len;i++){matches[i]=new Match(this.level,els[i]);}}

+return matches;},setSearchMatch:function(isMatch){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setSearchMatch(isMatch);}},clearSearch:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clearSearch();}},accept:function(visitor){visitor.visitLogEntry(this);},serialize:function(items){items.push([LogItem.serializedItemKeys.LOG_ENTRY,this.level,this.formattedMessage]);}});function LogItemVisitor(){}

+LogItemVisitor.prototype={visit:function(logItem){},visitParent:function(logItem){if(logItem.group){logItem.group.accept(this);}},visitChildren:function(logItem){for(var i=0,len=logItem.children.length;i<len;i++){logItem.children[i].accept(this);}},visitLogEntry:function(logEntry){this.visit(logEntry);},visitSeparator:function(separator){this.visit(separator);},visitGroup:function(group){this.visit(group);}};function GroupFlattener(){this.logEntriesAndSeparators=[];}

+GroupFlattener.prototype=new LogItemVisitor();GroupFlattener.prototype.visitGroup=function(group){this.visitChildren(group);};GroupFlattener.prototype.visitLogEntry=function(logEntry){this.logEntriesAndSeparators.push(logEntry);};GroupFlattener.prototype.visitSeparator=function(separator){this.logEntriesAndSeparators.push(separator);};window.onload=function(){if(location.search){var queryBits=unescape(location.search).substr(1).split("&"),nameValueBits;for(var i=0,len=queryBits.length;i<len;i++){nameValueBits=queryBits[i].split("=");if(nameValueBits[0]=="log4javascript_domain"){document.domain=nameValueBits[1];break;}}}

+logMainContainer=$("log");if(isIePre7){addClass(logMainContainer,"oldIe");}

+rootGroup=new Group("root",true);rootGroup.render();currentGroup=rootGroup;setCommandInputWidth();setLogContainerHeight();toggleLoggingEnabled();toggleSearchEnabled();toggleSearchFilter();toggleSearchHighlight();applyFilters();checkAllLevels();toggleWrap();toggleNewestAtTop();toggleScrollToLatest();renderQueuedLogItems();loaded=true;$("command").value="";$("command").autocomplete="off";$("command").onkeydown=function(evt){evt=getEvent(evt);if(evt.keyCode==10||evt.keyCode==13){evalCommandLine();stopPropagation(evt);}else if(evt.keyCode==27){this.value="";this.focus();}else if(evt.keyCode==38&&commandHistory.length>0){currentCommandIndex=Math.max(0,currentCommandIndex-1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}else if(evt.keyCode==40&&commandHistory.length>0){currentCommandIndex=Math.min(commandHistory.length-1,currentCommandIndex+1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}};$("command").onkeypress=function(evt){evt=getEvent(evt);if(evt.keyCode==38&&commandHistory.length>0&&evt.preventDefault){evt.preventDefault();}};$("command").onkeyup=function(evt){evt=getEvent(evt);if(evt.keyCode==27&&evt.preventDefault){evt.preventDefault();this.focus();}};document.onkeydown=function keyEventHandler(evt){evt=getEvent(evt);switch(evt.keyCode){case 69:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){evalLastCommand();cancelKeyEvent(evt);return false;}

+break;case 75:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusSearch();cancelKeyEvent(evt);return false;}

+break;case 40:case 76:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusCommandLine();cancelKeyEvent(evt);return false;}

+break;}};setTimeout(setLogContainerHeight,20);setShowCommandLine(showCommandLine);doSearch();};window.onunload=function(){if(mainWindowExists()){appender.unload();}

+appender=null;};function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}

+function setLoggingEnabled(enable){loggingEnabled=enable;}

+var appender=null;function setAppender(appenderParam){appender=appenderParam;}

+function setShowCloseButton(showCloseButton){$("closeButton").style.display=showCloseButton?"inline":"none";}

+function setShowHideButton(showHideButton){$("hideButton").style.display=showHideButton?"inline":"none";}

+var newestAtTop=false;function LogItemContentReverser(){}

+LogItemContentReverser.prototype=new LogItemVisitor();LogItemContentReverser.prototype.visitGroup=function(group){group.reverseChildren();this.visitChildren(group);};function setNewestAtTop(isNewestAtTop){var oldNewestAtTop=newestAtTop;var i,iLen,j,jLen;newestAtTop=Boolean(isNewestAtTop);if(oldNewestAtTop!=newestAtTop){var visitor=new LogItemContentReverser();rootGroup.accept(visitor);if(currentSearch){var currentMatch=currentSearch.matches[currentMatchIndex];var matchIndex=0;var matches=[];var actOnLogEntry=function(logEntry){var logEntryMatches=logEntry.getSearchMatches();for(j=0,jLen=logEntryMatches.length;j<jLen;j++){matches[matchIndex]=logEntryMatches[j];if(currentMatch&&logEntryMatches[j].equals(currentMatch)){currentMatchIndex=matchIndex;}

+matchIndex++;}};if(newestAtTop){for(i=logEntries.length-1;i>=0;i--){actOnLogEntry(logEntries[i]);}}else{for(i=0,iLen=logEntries.length;i<iLen;i++){actOnLogEntry(logEntries[i]);}}

+currentSearch.matches=matches;if(currentMatch){currentMatch.setCurrent();}}else if(scrollToLatest){doScrollToLatest();}}

+$("newestAtTop").checked=isNewestAtTop;}

+function toggleNewestAtTop(){var isNewestAtTop=$("newestAtTop").checked;setNewestAtTop(isNewestAtTop);}

+var scrollToLatest=true;function setScrollToLatest(isScrollToLatest){scrollToLatest=isScrollToLatest;if(scrollToLatest){doScrollToLatest();}

+$("scrollToLatest").checked=isScrollToLatest;}

+function toggleScrollToLatest(){var isScrollToLatest=$("scrollToLatest").checked;setScrollToLatest(isScrollToLatest);}

+function doScrollToLatest(){var l=logMainContainer;if(typeof l.scrollTop!="undefined"){if(newestAtTop){l.scrollTop=0;}else{var latestLogEntry=l.lastChild;if(latestLogEntry){l.scrollTop=l.scrollHeight;}}}}

+var closeIfOpenerCloses=true;function setCloseIfOpenerCloses(isCloseIfOpenerCloses){closeIfOpenerCloses=isCloseIfOpenerCloses;}

+var maxMessages=null;function setMaxMessages(max){maxMessages=max;pruneLogEntries();}

+var showCommandLine=false;function setShowCommandLine(isShowCommandLine){showCommandLine=isShowCommandLine;if(loaded){$("commandLine").style.display=showCommandLine?"block":"none";setCommandInputWidth();setLogContainerHeight();}}

+function focusCommandLine(){if(loaded){$("command").focus();}}

+function focusSearch(){if(loaded){$("searchBox").focus();}}

+function getLogItems(){var items=[];for(var i=0,len=logItems.length;i<len;i++){logItems[i].serialize(items);}

+return items;}

+function setLogItems(items){var loggingReallyEnabled=loggingEnabled;loggingEnabled=true;for(var i=0,len=items.length;i<len;i++){switch(items[i][0]){case LogItem.serializedItemKeys.LOG_ENTRY:log(items[i][1],items[i][2]);break;case LogItem.serializedItemKeys.GROUP_START:group(items[i][1]);break;case LogItem.serializedItemKeys.GROUP_END:groupEnd();break;}}

+loggingEnabled=loggingReallyEnabled;}

+function log(logLevel,formattedMessage){if(loggingEnabled){var logEntry=new LogEntry(logLevel,formattedMessage);logEntries.push(logEntry);logEntriesAndSeparators.push(logEntry);logItems.push(logEntry);currentGroup.addChild(logEntry);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}

+logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}

+function renderQueuedLogItems(){logQueuedEventsTimer=null;var pruned=pruneLogEntries();var initiallyHasMatches=currentSearch?currentSearch.hasMatches():false;for(var i=0,len=logItems.length;i<len;i++){if(!logItems[i].rendered){logItems[i].render();logItems[i].appendToLog();if(currentSearch&&(logItems[i]instanceof LogEntry)){currentSearch.applyTo(logItems[i]);}}}

+if(currentSearch){if(pruned){if(currentSearch.hasVisibleMatches()){if(currentMatchIndex===null){setCurrentMatchIndex(0);}

+displayMatches();}else{displayNoMatches();}}else if(!initiallyHasMatches&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}}

+if(scrollToLatest){doScrollToLatest();}

+unrenderedLogItemsExist=false;}

+function pruneLogEntries(){if((maxMessages!==null)&&(logEntriesAndSeparators.length>maxMessages)){var numberToDelete=logEntriesAndSeparators.length-maxMessages;var prunedLogEntries=logEntriesAndSeparators.slice(0,numberToDelete);if(currentSearch){currentSearch.removeMatches(prunedLogEntries);}

+var group;for(var i=0;i<numberToDelete;i++){group=logEntriesAndSeparators[i].group;array_remove(logItems,logEntriesAndSeparators[i]);array_remove(logEntries,logEntriesAndSeparators[i]);logEntriesAndSeparators[i].remove(true,true);if(group.children.length===0&&group!==currentGroup&&group!==rootGroup){array_remove(logItems,group);group.remove(true,true);}}

+logEntriesAndSeparators=array_removeFromStart(logEntriesAndSeparators,numberToDelete);return true;}

+return false;}

+function group(name,startExpanded){if(loggingEnabled){initiallyExpanded=(typeof startExpanded==="undefined")?true:Boolean(startExpanded);var newGroup=new Group(name,false,initiallyExpanded);currentGroup.addChild(newGroup);currentGroup=newGroup;logItems.push(newGroup);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}

+logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}

+function groupEnd(){currentGroup=(currentGroup===rootGroup)?rootGroup:currentGroup.group;}

+function mainPageReloaded(){currentGroup=rootGroup;var separator=new Separator();logEntriesAndSeparators.push(separator);logItems.push(separator);currentGroup.addChild(separator);}

+function closeWindow(){if(appender&&mainWindowExists()){appender.close(true);}else{window.close();}}

+function hide(){if(appender&&mainWindowExists()){appender.hide();}}

+var mainWindow=window;var windowId="log4javascriptConsoleWindow_"+new Date().getTime()+"_"+(""+Math.random()).substr(2);function setMainWindow(win){mainWindow=win;mainWindow[windowId]=window;if(opener&&closeIfOpenerCloses){pollOpener();}}

+function pollOpener(){if(closeIfOpenerCloses){if(mainWindowExists()){setTimeout(pollOpener,500);}else{closeWindow();}}}

+function mainWindowExists(){try{return(mainWindow&&!mainWindow.closed&&mainWindow[windowId]==window);}catch(ex){}

+return false;}

+var logLevels=["TRACE","DEBUG","INFO","WARN","ERROR","FATAL"];function getCheckBox(logLevel){return $("switch_"+logLevel);}

+function getIeWrappedLogContainer(){return $("log_wrapped");}

+function getIeUnwrappedLogContainer(){return $("log_unwrapped");}

+function applyFilters(){for(var i=0;i<logLevels.length;i++){if(getCheckBox(logLevels[i]).checked){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}

+updateSearchFromFilters();}

+function toggleAllLevels(){var turnOn=$("switch_ALL").checked;for(var i=0;i<logLevels.length;i++){getCheckBox(logLevels[i]).checked=turnOn;if(turnOn){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}}

+function checkAllLevels(){for(var i=0;i<logLevels.length;i++){if(!getCheckBox(logLevels[i]).checked){getCheckBox("ALL").checked=false;return;}}

+getCheckBox("ALL").checked=true;}

+function clearLog(){rootGroup.clear();currentGroup=rootGroup;logEntries=[];logItems=[];logEntriesAndSeparators=[];doSearch();}

+function toggleWrap(){var enable=$("wrap").checked;if(enable){addClass(logMainContainer,"wrap");}else{removeClass(logMainContainer,"wrap");}

+refreshCurrentMatch();}

+var searchTimer=null;function scheduleSearch(){try{clearTimeout(searchTimer);}catch(ex){}

+searchTimer=setTimeout(doSearch,500);}

+function Search(searchTerm,isRegex,searchRegex,isCaseSensitive){this.searchTerm=searchTerm;this.isRegex=isRegex;this.searchRegex=searchRegex;this.isCaseSensitive=isCaseSensitive;this.matches=[];}

+Search.prototype={hasMatches:function(){return this.matches.length>0;},hasVisibleMatches:function(){if(this.hasMatches()){for(var i=0;i<this.matches.length;i++){if(this.matches[i].isVisible()){return true;}}}

+return false;},match:function(logEntry){var entryText=String(logEntry.formattedMessage);var matchesSearch=false;if(this.isRegex){matchesSearch=this.searchRegex.test(entryText);}else if(this.isCaseSensitive){matchesSearch=(entryText.indexOf(this.searchTerm)>-1);}else{matchesSearch=(entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase())>-1);}

+return matchesSearch;},getNextVisibleMatchIndex:function(){for(var i=currentMatchIndex+1;i<this.matches.length;i++){if(this.matches[i].isVisible()){return i;}}

+for(i=0;i<=currentMatchIndex;i++){if(this.matches[i].isVisible()){return i;}}

+return-1;},getPreviousVisibleMatchIndex:function(){for(var i=currentMatchIndex-1;i>=0;i--){if(this.matches[i].isVisible()){return i;}}

+for(var i=this.matches.length-1;i>=currentMatchIndex;i--){if(this.matches[i].isVisible()){return i;}}

+return-1;},applyTo:function(logEntry){var doesMatch=this.match(logEntry);if(doesMatch){logEntry.group.expand();logEntry.setSearchMatch(true);var logEntryContent;var wrappedLogEntryContent;var searchTermReplacementStartTag="<span class=\"searchterm\">";var searchTermReplacementEndTag="<"+"/span>";var preTagName=isIe?"pre":"span";var preStartTag="<"+preTagName+" class=\"pre\">";var preEndTag="<"+"/"+preTagName+">";var startIndex=0;var searchIndex,matchedText,textBeforeMatch;if(this.isRegex){var flags=this.isCaseSensitive?"g":"gi";var capturingRegex=new RegExp("("+this.searchRegex.source+")",flags);var rnd=(""+Math.random()).substr(2);var startToken="%%s"+rnd+"%%";var endToken="%%e"+rnd+"%%";logEntryContent=logEntry.formattedMessage.replace(capturingRegex,startToken+"$1"+endToken);logEntryContent=escapeHtml(logEntryContent);var result;var searchString=logEntryContent;logEntryContent="";wrappedLogEntryContent="";while((searchIndex=searchString.indexOf(startToken,startIndex))>-1){var endTokenIndex=searchString.indexOf(endToken,searchIndex);matchedText=searchString.substring(searchIndex+startToken.length,endTokenIndex);textBeforeMatch=searchString.substring(startIndex,searchIndex);logEntryContent+=preStartTag+textBeforeMatch+preEndTag;logEntryContent+=searchTermReplacementStartTag+preStartTag+matchedText+

+preEndTag+searchTermReplacementEndTag;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+

+matchedText+searchTermReplacementEndTag;}

+startIndex=endTokenIndex+endToken.length;}

+logEntryContent+=preStartTag+searchString.substr(startIndex)+preEndTag;if(isIe){wrappedLogEntryContent+=searchString.substr(startIndex);}}else{logEntryContent="";wrappedLogEntryContent="";var searchTermReplacementLength=searchTermReplacementStartTag.length+

+this.searchTerm.length+searchTermReplacementEndTag.length;var searchTermLength=this.searchTerm.length;var searchTermLowerCase=this.searchTerm.toLowerCase();var logTextLowerCase=logEntry.formattedMessage.toLowerCase();while((searchIndex=logTextLowerCase.indexOf(searchTermLowerCase,startIndex))>-1){matchedText=escapeHtml(logEntry.formattedMessage.substr(searchIndex,this.searchTerm.length));textBeforeMatch=escapeHtml(logEntry.formattedMessage.substring(startIndex,searchIndex));var searchTermReplacement=searchTermReplacementStartTag+

+preStartTag+matchedText+preEndTag+searchTermReplacementEndTag;logEntryContent+=preStartTag+textBeforeMatch+preEndTag+searchTermReplacement;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+

+matchedText+searchTermReplacementEndTag;}

+startIndex=searchIndex+searchTermLength;}

+var textAfterLastMatch=escapeHtml(logEntry.formattedMessage.substr(startIndex));logEntryContent+=preStartTag+textAfterLastMatch+preEndTag;if(isIe){wrappedLogEntryContent+=textAfterLastMatch;}}

+logEntry.setContent(logEntryContent,wrappedLogEntryContent);var logEntryMatches=logEntry.getSearchMatches();this.matches=this.matches.concat(logEntryMatches);}else{logEntry.setSearchMatch(false);logEntry.setContent(logEntry.formattedMessage,logEntry.formattedMessage);}

+return doesMatch;},removeMatches:function(logEntries){var matchesToRemoveCount=0;var currentMatchRemoved=false;var matchesToRemove=[];var i,iLen,j,jLen;for(i=0,iLen=this.matches.length;i<iLen;i++){for(j=0,jLen=logEntries.length;j<jLen;j++){if(this.matches[i].belongsTo(logEntries[j])){matchesToRemove.push(this.matches[i]);if(i===currentMatchIndex){currentMatchRemoved=true;}}}}

+var newMatch=currentMatchRemoved?null:this.matches[currentMatchIndex];if(currentMatchRemoved){for(i=currentMatchIndex,iLen=this.matches.length;i<iLen;i++){if(this.matches[i].isVisible()&&!array_contains(matchesToRemove,this.matches[i])){newMatch=this.matches[i];break;}}}

+for(i=0,iLen=matchesToRemove.length;i<iLen;i++){array_remove(this.matches,matchesToRemove[i]);matchesToRemove[i].remove();}

+if(this.hasVisibleMatches()){if(newMatch===null){setCurrentMatchIndex(0);}else{var newMatchIndex=0;for(i=0,iLen=this.matches.length;i<iLen;i++){if(newMatch===this.matches[i]){newMatchIndex=i;break;}}

+setCurrentMatchIndex(newMatchIndex);}}else{currentMatchIndex=null;displayNoMatches();}}};function getPageOffsetTop(el,container){var currentEl=el;var y=0;while(currentEl&&currentEl!=container){y+=currentEl.offsetTop;currentEl=currentEl.offsetParent;}

+return y;}

+function scrollIntoView(el){var logContainer=logMainContainer;if(!$("wrap").checked){var logContainerLeft=logContainer.scrollLeft;var logContainerRight=logContainerLeft+logContainer.offsetWidth;var elLeft=el.offsetLeft;var elRight=elLeft+el.offsetWidth;if(elLeft<logContainerLeft||elRight>logContainerRight){logContainer.scrollLeft=elLeft-(logContainer.offsetWidth-el.offsetWidth)/2;}}

+var logContainerTop=logContainer.scrollTop;var logContainerBottom=logContainerTop+logContainer.offsetHeight;var elTop=getPageOffsetTop(el)-getToolBarsHeight();var elBottom=elTop+el.offsetHeight;if(elTop<logContainerTop||elBottom>logContainerBottom){logContainer.scrollTop=elTop-(logContainer.offsetHeight-el.offsetHeight)/2;}}

+function Match(logEntryLevel,spanInMainDiv,spanInUnwrappedPre,spanInWrappedDiv){this.logEntryLevel=logEntryLevel;this.spanInMainDiv=spanInMainDiv;if(isIe){this.spanInUnwrappedPre=spanInUnwrappedPre;this.spanInWrappedDiv=spanInWrappedDiv;}

+this.mainSpan=isIe?spanInUnwrappedPre:spanInMainDiv;}

+Match.prototype={equals:function(match){return this.mainSpan===match.mainSpan;},setCurrent:function(){if(isIe){addClass(this.spanInUnwrappedPre,"currentmatch");addClass(this.spanInWrappedDiv,"currentmatch");var elementToScroll=$("wrap").checked?this.spanInWrappedDiv:this.spanInUnwrappedPre;scrollIntoView(elementToScroll);}else{addClass(this.spanInMainDiv,"currentmatch");scrollIntoView(this.spanInMainDiv);}},belongsTo:function(logEntry){if(isIe){return isDescendant(this.spanInUnwrappedPre,logEntry.unwrappedPre);}else{return isDescendant(this.spanInMainDiv,logEntry.mainDiv);}},setNotCurrent:function(){if(isIe){removeClass(this.spanInUnwrappedPre,"currentmatch");removeClass(this.spanInWrappedDiv,"currentmatch");}else{removeClass(this.spanInMainDiv,"currentmatch");}},isOrphan:function(){return isOrphan(this.mainSpan);},isVisible:function(){return getCheckBox(this.logEntryLevel).checked;},remove:function(){if(isIe){this.spanInUnwrappedPre=null;this.spanInWrappedDiv=null;}else{this.spanInMainDiv=null;}}};var currentSearch=null;var currentMatchIndex=null;function doSearch(){var searchBox=$("searchBox");var searchTerm=searchBox.value;var isRegex=$("searchRegex").checked;var isCaseSensitive=$("searchCaseSensitive").checked;var i;if(searchTerm===""){$("searchReset").disabled=true;$("searchNav").style.display="none";removeClass(document.body,"searching");removeClass(searchBox,"hasmatches");removeClass(searchBox,"nomatches");for(i=0;i<logEntries.length;i++){logEntries[i].clearSearch();logEntries[i].setContent(logEntries[i].formattedMessage,logEntries[i].formattedMessage);}

+currentSearch=null;setLogContainerHeight();}else{$("searchReset").disabled=false;$("searchNav").style.display="block";var searchRegex;var regexValid;if(isRegex){try{searchRegex=isCaseSensitive?new RegExp(searchTerm,"g"):new RegExp(searchTerm,"gi");regexValid=true;replaceClass(searchBox,"validregex","invalidregex");searchBox.title="Valid regex";}catch(ex){regexValid=false;replaceClass(searchBox,"invalidregex","validregex");searchBox.title="Invalid regex: "+(ex.message?ex.message:(ex.description?ex.description:"unknown error"));return;}}else{searchBox.title="";removeClass(searchBox,"validregex");removeClass(searchBox,"invalidregex");}

+addClass(document.body,"searching");currentSearch=new Search(searchTerm,isRegex,searchRegex,isCaseSensitive);for(i=0;i<logEntries.length;i++){currentSearch.applyTo(logEntries[i]);}

+setLogContainerHeight();if(currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}else{displayNoMatches();}}}

+function updateSearchFromFilters(){if(currentSearch){if(currentSearch.hasMatches()){if(currentMatchIndex===null){currentMatchIndex=0;}

+var currentMatch=currentSearch.matches[currentMatchIndex];if(currentMatch.isVisible()){displayMatches();setCurrentMatchIndex(currentMatchIndex);}else{currentMatch.setNotCurrent();var nextVisibleMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextVisibleMatchIndex>-1){setCurrentMatchIndex(nextVisibleMatchIndex);displayMatches();}else{displayNoMatches();}}}else{displayNoMatches();}}}

+function refreshCurrentMatch(){if(currentSearch&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(currentMatchIndex);}}

+function displayMatches(){replaceClass($("searchBox"),"hasmatches","nomatches");$("searchBox").title=""+currentSearch.matches.length+" matches found";$("searchNav").style.display="block";setLogContainerHeight();}

+function displayNoMatches(){replaceClass($("searchBox"),"nomatches","hasmatches");$("searchBox").title="No matches found";$("searchNav").style.display="none";setLogContainerHeight();}

+function toggleSearchEnabled(enable){enable=(typeof enable=="undefined")?!$("searchDisable").checked:enable;$("searchBox").disabled=!enable;$("searchReset").disabled=!enable;$("searchRegex").disabled=!enable;$("searchNext").disabled=!enable;$("searchPrevious").disabled=!enable;$("searchCaseSensitive").disabled=!enable;$("searchNav").style.display=(enable&&($("searchBox").value!=="")&&currentSearch&&currentSearch.hasVisibleMatches())?"block":"none";if(enable){removeClass($("search"),"greyedout");addClass(document.body,"searching");if($("searchHighlight").checked){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}

+if($("searchFilter").checked){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}

+$("searchDisable").checked=!enable;}else{addClass($("search"),"greyedout");removeClass(document.body,"searching");removeClass(logMainContainer,"searchhighlight");removeClass(logMainContainer,"searchfilter");}

+setLogContainerHeight();}

+function toggleSearchFilter(){var enable=$("searchFilter").checked;if(enable){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}

+refreshCurrentMatch();}

+function toggleSearchHighlight(){var enable=$("searchHighlight").checked;if(enable){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}}

+function clearSearch(){$("searchBox").value="";doSearch();}

+function searchNext(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var nextMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextMatchIndex>currentMatchIndex||confirm("Reached the end of the page. Start from the top?")){setCurrentMatchIndex(nextMatchIndex);}}}

+function searchPrevious(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var previousMatchIndex=currentSearch.getPreviousVisibleMatchIndex();if(previousMatchIndex<currentMatchIndex||confirm("Reached the start of the page. Continue from the bottom?")){setCurrentMatchIndex(previousMatchIndex);}}}

+function setCurrentMatchIndex(index){currentMatchIndex=index;currentSearch.matches[currentMatchIndex].setCurrent();}

+function addClass(el,cssClass){if(!hasClass(el,cssClass)){if(el.className){el.className+=" "+cssClass;}else{el.className=cssClass;}}}

+function hasClass(el,cssClass){if(el.className){var classNames=el.className.split(" ");return array_contains(classNames,cssClass);}

+return false;}

+function removeClass(el,cssClass){if(hasClass(el,cssClass)){var existingClasses=el.className.split(" ");var newClasses=[];for(var i=0,len=existingClasses.length;i<len;i++){if(existingClasses[i]!=cssClass){newClasses[newClasses.length]=existingClasses[i];}}

+el.className=newClasses.join(" ");}}

+function replaceClass(el,newCssClass,oldCssClass){removeClass(el,oldCssClass);addClass(el,newCssClass);}

+function getElementsByClass(el,cssClass,tagName){var elements=el.getElementsByTagName(tagName);var matches=[];for(var i=0,len=elements.length;i<len;i++){if(hasClass(elements[i],cssClass)){matches.push(elements[i]);}}

+return matches;}

+function $(id){return document.getElementById(id);}

+function isDescendant(node,ancestorNode){while(node!=null){if(node===ancestorNode){return true;}

+node=node.parentNode;}

+return false;}

+function isOrphan(node){var currentNode=node;while(currentNode){if(currentNode==document.body){return false;}

+currentNode=currentNode.parentNode;}

+return true;}

+function escapeHtml(str){return str.replace(/&/g,"&amp;").replace(/[<]/g,"&lt;").replace(/>/g,"&gt;");}

+function getWindowWidth(){if(window.innerWidth){return window.innerWidth;}else if(document.documentElement&&document.documentElement.clientWidth){return document.documentElement.clientWidth;}else if(document.body){return document.body.clientWidth;}

+return 0;}

+function getWindowHeight(){if(window.innerHeight){return window.innerHeight;}else if(document.documentElement&&document.documentElement.clientHeight){return document.documentElement.clientHeight;}else if(document.body){return document.body.clientHeight;}

+return 0;}

+function getToolBarsHeight(){return $("switches").offsetHeight;}

+function getChromeHeight(){var height=getToolBarsHeight();if(showCommandLine){height+=$("commandLine").offsetHeight;}

+return height;}

+function setLogContainerHeight(){if(logMainContainer){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";logMainContainer.style.height=""+

+Math.max(0,windowHeight-getChromeHeight())+"px";}}

+function setCommandInputWidth(){if(showCommandLine){$("command").style.width=""+Math.max(0,$("commandLineContainer").offsetWidth-

+($("evaluateButton").offsetWidth+13))+"px";}}

+window.onresize=function(){setCommandInputWidth();setLogContainerHeight();};if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}

+return this.length;};}

+if(!Array.prototype.pop){Array.prototype.pop=function(){if(this.length>0){var val=this[this.length-1];this.length=this.length-1;return val;}};}

+if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}

+this.length=this.length-1;return firstItem;}};}

+if(!Array.prototype.splice){Array.prototype.splice=function(startIndex,deleteCount){var itemsAfterDeleted=this.slice(startIndex+deleteCount);var itemsDeleted=this.slice(startIndex,startIndex+deleteCount);this.length=startIndex;var argumentsArray=[];for(var i=0,len=arguments.length;i<len;i++){argumentsArray[i]=arguments[i];}

+var itemsToAppend=(argumentsArray.length>2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i<len;i++){this.push(itemsToAppend[i]);}

+return itemsDeleted;};}

+function array_remove(arr,val){var index=-1;for(var i=0,len=arr.length;i<len;i++){if(arr[i]===val){index=i;break;}}

+if(index>=0){arr.splice(index,1);return index;}else{return false;}}

+function array_removeFromStart(array,numberToRemove){if(Array.prototype.splice){array.splice(0,numberToRemove);}else{for(var i=numberToRemove,len=array.length;i<len;i++){array[i-numberToRemove]=array[i];}

+array.length=array.length-numberToRemove;}

+return array;}

+function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}

+return false;}

+function getErrorMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}

+return""+ex;}

+function moveCaretToEnd(input){if(input.setSelectionRange){input.focus();var length=input.value.length;input.setSelectionRange(length,length);}else if(input.createTextRange){var range=input.createTextRange();range.collapse(false);range.select();}

+input.focus();}

+function stopPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}}

+function getEvent(evt){return evt?evt:event;}

+function getTarget(evt){return evt.target?evt.target:evt.srcElement;}

+function getRelatedTarget(evt){if(evt.relatedTarget){return evt.relatedTarget;}else if(evt.srcElement){switch(evt.type){case"mouseover":return evt.fromElement;case"mouseout":return evt.toElement;default:return evt.srcElement;}}}

+function cancelKeyEvent(evt){evt.returnValue=false;stopPropagation(evt);}

+function evalCommandLine(){var expr=$("command").value;evalCommand(expr);$("command").value="";}

+function evalLastCommand(){if(lastCommand!=null){evalCommand(lastCommand);}}

+var lastCommand=null;var commandHistory=[];var currentCommandIndex=0;function evalCommand(expr){if(appender){appender.evalCommandAndAppend(expr);}else{var prefix=">>> "+expr+"\r\n";try{log("INFO",prefix+eval(expr));}catch(ex){log("ERROR",prefix+"Error: "+getErrorMessage(ex));}}

+if(expr!=commandHistory[commandHistory.length-1]){commandHistory.push(expr);if(appender){appender.storeCommandHistory(commandHistory);}}

+currentCommandIndex=(expr==commandHistory[currentCommandIndex])?currentCommandIndex+1:commandHistory.length;lastCommand=expr;}

+//]]>

+</script>

+<style type="text/css">

+body{background-color:white;color:black;padding:0;margin:0;font-family:tahoma,verdana,arial,helvetica,sans-serif;overflow:hidden}div#switchesContainer input{margin-bottom:0}div.toolbar{border-top:solid #ffffff 1px;border-bottom:solid #aca899 1px;background-color:#f1efe7;padding:3px 5px;font-size:68.75%}div.toolbar,div#search input{font-family:tahoma,verdana,arial,helvetica,sans-serif}div.toolbar input.button{padding:0 5px;font-size:100%}div.toolbar input.hidden{display:none}div#switches input#clearButton{margin-left:20px}div#levels label{font-weight:bold}div#levels label,div#options label{margin-right:5px}div#levels label#wrapLabel{font-weight:normal}div#search label{margin-right:10px}div#search label.searchboxlabel{margin-right:0}div#search input{font-size:100%}div#search input.validregex{color:green}div#search input.invalidregex{color:red}div#search input.nomatches{color:white;background-color:#ff6666}div#search input.nomatches{color:white;background-color:#ff6666}div#searchNav{display:none}div#commandLine{display:none}div#commandLine input#command{font-size:100%;font-family:Courier New,Courier}div#commandLine input#evaluateButton{}*.greyedout{color:gray !important;border-color:gray !important}*.greyedout *.alwaysenabled{color:black}*.unselectable{-khtml-user-select:none;-moz-user-select:none;user-select:none}div#log{font-family:Courier New,Courier;font-size:75%;width:100%;overflow:auto;clear:both;position:relative}div.group{border-color:#cccccc;border-style:solid;border-width:1px 0 1px 1px;overflow:visible}div.oldIe div.group,div.oldIe div.group *,div.oldIe *.logentry{height:1%}div.group div.groupheading span.expander{border:solid black 1px;font-family:Courier New,Courier;font-size:0.833em;background-color:#eeeeee;position:relative;top:-1px;color:black;padding:0 2px;cursor:pointer;cursor:hand;height:1%}div.group div.groupcontent{margin-left:10px;padding-bottom:2px;overflow:visible}div.group div.expanded{display:block}div.group div.collapsed{display:none}*.logentry{overflow:visible;display:none;white-space:pre}span.pre{white-space:pre}pre.unwrapped{display:inline !important}pre.unwrapped pre.pre,div.wrapped pre.pre{display:inline}div.wrapped pre.pre{white-space:normal}div.wrapped{display:none}body.searching *.logentry span.currentmatch{color:white !important;background-color:green !important}body.searching div.searchhighlight *.logentry span.searchterm{color:black;background-color:yellow}div.wrap *.logentry{white-space:normal !important;border-width:0 0 1px 0;border-color:#dddddd;border-style:dotted}div.wrap #log_wrapped,#log_unwrapped{display:block}div.wrap #log_unwrapped,#log_wrapped{display:none}div.wrap *.logentry span.pre{overflow:visible;white-space:normal}div.wrap *.logentry pre.unwrapped{display:none}div.wrap *.logentry span.wrapped{display:inline}div.searchfilter *.searchnonmatch{display:none !important}div#log *.TRACE,label#label_TRACE{color:#666666}div#log *.DEBUG,label#label_DEBUG{color:green}div#log *.INFO,label#label_INFO{color:#000099}div#log *.WARN,label#label_WARN{color:#999900}div#log *.ERROR,label#label_ERROR{color:red}div#log *.FATAL,label#label_FATAL{color:#660066}div.TRACE#log *.TRACE,div.DEBUG#log *.DEBUG,div.INFO#log *.INFO,div.WARN#log *.WARN,div.ERROR#log *.ERROR,div.FATAL#log *.FATAL{display:block}div#log div.separator{background-color:#cccccc;margin:5px 0;line-height:1px}

+</style>

+</head>

+<body id="body">

+<div id="switchesContainer">

+<div id="switches">

+<div id="levels" class="toolbar">

+Filters:

+<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>

+<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>

+<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>

+<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>

+<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>

+<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>

+<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>

+</div>

+<div id="search" class="toolbar">

+<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />

+<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />

+<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>

+<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>

+<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>

+<div id="searchNav">

+<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />

+<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />

+<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>

+<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>

+</div>

+</div>

+<div id="options" class="toolbar">

+Options:

+<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>

+<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>

+<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>

+<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>

+<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />

+<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />

+<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />

+</div>

+</div>

+</div>

+<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>

+<div id="commandLine" class="toolbar">

+<div id="commandLineContainer">

+<input type="text" id="command" title="Enter a JavaScript command here and hit return or press 'Evaluate'" />

+<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />

+</div>

+</div>

+</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/console_uncompressed.html b/planetstack/core/static/log4javascript-1.4.6/js/console_uncompressed.html
new file mode 100644
index 0000000..55679f8
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/console_uncompressed.html
@@ -0,0 +1,2279 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript</title>

+		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

+		<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->

+		<meta http-equiv="X-UA-Compatible" content="IE=7" />

+		<script type="text/javascript">var isIe = false, isIePre7 = false;</script>

+		<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->

+		<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->

+		<script type="text/javascript">

+			//<![CDATA[

+			var loggingEnabled = true;

+			var logQueuedEventsTimer = null;

+			var logEntries = [];

+			var logEntriesAndSeparators = [];

+			var logItems = [];

+			var renderDelay = 100;

+			var unrenderedLogItemsExist = false;

+			var rootGroup, currentGroup = null;

+			var loaded = false;

+			var currentLogItem = null;

+			var logMainContainer;

+

+			function copyProperties(obj, props) {

+				for (var i in props) {

+					obj[i] = props[i];

+				}

+			}

+

+			/*----------------------------------------------------------------*/

+

+			function LogItem() {

+			}

+

+			LogItem.prototype = {

+				mainContainer: null,

+				wrappedContainer: null,

+				unwrappedContainer: null,

+				group: null,

+

+				appendToLog: function() {

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].appendToLog();

+					}

+					this.group.update();

+				},

+

+				doRemove: function(doUpdate, removeFromGroup) {

+					if (this.rendered) {

+						for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+							this.elementContainers[i].remove();

+						}

+						this.unwrappedElementContainer = null;

+						this.wrappedElementContainer = null;

+						this.mainElementContainer = null;

+					}

+					if (this.group && removeFromGroup) {

+						this.group.removeChild(this, doUpdate);

+					}

+					if (this === currentLogItem) {

+						currentLogItem = null;

+					}

+				},

+

+				remove: function(doUpdate, removeFromGroup) {

+					this.doRemove(doUpdate, removeFromGroup);

+				},

+

+				render: function() {},

+

+				accept: function(visitor) {

+					visitor.visit(this);

+				},

+

+				getUnwrappedDomContainer: function() {

+					return this.group.unwrappedElementContainer.contentDiv;

+				},

+

+				getWrappedDomContainer: function() {

+					return this.group.wrappedElementContainer.contentDiv;

+				},

+

+				getMainDomContainer: function() {

+					return this.group.mainElementContainer.contentDiv;

+				}

+			};

+

+			LogItem.serializedItemKeys = {LOG_ENTRY: 0, GROUP_START: 1, GROUP_END: 2};

+

+			/*----------------------------------------------------------------*/

+

+			function LogItemContainerElement() {

+			}

+

+			LogItemContainerElement.prototype = {

+				appendToLog: function() {

+					var insertBeforeFirst = (newestAtTop && this.containerDomNode.hasChildNodes());

+					if (insertBeforeFirst) {

+						this.containerDomNode.insertBefore(this.mainDiv, this.containerDomNode.firstChild);

+					} else {

+						this.containerDomNode.appendChild(this.mainDiv);

+					}

+				}

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function SeparatorElementContainer(containerDomNode) {

+				this.containerDomNode = containerDomNode;

+				this.mainDiv = document.createElement("div");

+				this.mainDiv.className = "separator";

+				this.mainDiv.innerHTML = "&nbsp;";

+			}

+

+			SeparatorElementContainer.prototype = new LogItemContainerElement();

+

+			SeparatorElementContainer.prototype.remove = function() {

+				this.mainDiv.parentNode.removeChild(this.mainDiv);

+				this.mainDiv = null;

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function Separator() {

+				this.rendered = false;

+			}

+

+			Separator.prototype = new LogItem();

+

+			copyProperties(Separator.prototype, {

+				render: function() {

+					var containerDomNode = this.group.contentDiv;

+					if (isIe) {

+						this.unwrappedElementContainer = new SeparatorElementContainer(this.getUnwrappedDomContainer());

+						this.wrappedElementContainer = new SeparatorElementContainer(this.getWrappedDomContainer());

+						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];

+					} else {

+						this.mainElementContainer = new SeparatorElementContainer(this.getMainDomContainer());

+						this.elementContainers = [this.mainElementContainer];

+					}

+					this.content = this.formattedMessage;

+					this.rendered = true;

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function GroupElementContainer(group, containerDomNode, isRoot, isWrapped) {

+				this.group = group;

+				this.containerDomNode = containerDomNode;

+				this.isRoot = isRoot;

+				this.isWrapped = isWrapped;

+				this.expandable = false;

+

+				if (this.isRoot) {

+					if (isIe) {

+						this.contentDiv = logMainContainer.appendChild(document.createElement("div"));

+						this.contentDiv.id = this.isWrapped ? "log_wrapped" : "log_unwrapped";

+					} else {

+						this.contentDiv = logMainContainer;

+					}

+				} else {

+					var groupElementContainer = this;

+					

+					this.mainDiv = document.createElement("div");

+					this.mainDiv.className = "group";

+

+					this.headingDiv = this.mainDiv.appendChild(document.createElement("div"));

+					this.headingDiv.className = "groupheading";

+

+					this.expander = this.headingDiv.appendChild(document.createElement("span"));

+					this.expander.className = "expander unselectable greyedout";

+					this.expander.unselectable = true;

+					var expanderText = this.group.expanded ? "-" : "+";

+					this.expanderTextNode = this.expander.appendChild(document.createTextNode(expanderText));

+					

+					this.headingDiv.appendChild(document.createTextNode(" " + this.group.name));

+

+					this.contentDiv = this.mainDiv.appendChild(document.createElement("div"));

+					var contentCssClass = this.group.expanded ? "expanded" : "collapsed";

+					this.contentDiv.className = "groupcontent " + contentCssClass;

+

+					this.expander.onclick = function() {

+						if (groupElementContainer.group.expandable) {

+							groupElementContainer.group.toggleExpanded();

+						}

+					};

+				}

+			}

+

+			GroupElementContainer.prototype = new LogItemContainerElement();

+

+			copyProperties(GroupElementContainer.prototype, {

+				toggleExpanded: function() {

+					if (!this.isRoot) {

+						var oldCssClass, newCssClass, expanderText;

+						if (this.group.expanded) {

+							newCssClass = "expanded";

+							oldCssClass = "collapsed";

+							expanderText = "-";

+						} else {

+							newCssClass = "collapsed";

+							oldCssClass = "expanded";

+							expanderText = "+";

+						}

+						replaceClass(this.contentDiv, newCssClass, oldCssClass);

+						this.expanderTextNode.nodeValue = expanderText;

+					}

+				},

+

+				remove: function() {

+					if (!this.isRoot) {

+						this.headingDiv = null;

+						this.expander.onclick = null;

+						this.expander = null;

+						this.expanderTextNode = null;

+						this.contentDiv = null;

+						this.containerDomNode = null;

+						this.mainDiv.parentNode.removeChild(this.mainDiv);

+						this.mainDiv = null;

+					}

+				},

+

+				reverseChildren: function() {

+					// Invert the order of the log entries

+					var node = null;

+

+					// Remove all the log container nodes

+					var childDomNodes = [];

+					while ((node = this.contentDiv.firstChild)) {

+						this.contentDiv.removeChild(node);

+						childDomNodes.push(node);

+					}

+

+					// Put them all back in reverse order

+					while ((node = childDomNodes.pop())) {

+						this.contentDiv.appendChild(node);

+					}

+				},

+

+				update: function() {

+					if (!this.isRoot) {

+						if (this.group.expandable) {

+							removeClass(this.expander, "greyedout");

+						} else {

+							addClass(this.expander, "greyedout");

+						}

+					}

+				},

+

+				clear: function() {

+					if (this.isRoot) {

+						this.contentDiv.innerHTML = "";

+					}

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function Group(name, isRoot, initiallyExpanded) {

+				this.name = name;

+				this.group = null;

+				this.isRoot = isRoot;

+				this.initiallyExpanded = initiallyExpanded;

+				this.elementContainers = [];

+				this.children = [];

+				this.expanded = initiallyExpanded;

+				this.rendered = false;

+				this.expandable = false;

+			}

+

+			Group.prototype = new LogItem();

+

+			copyProperties(Group.prototype, {

+				addChild: function(logItem) {

+					this.children.push(logItem);

+					logItem.group = this;

+				},

+

+				render: function() {

+					if (isIe) {

+						var unwrappedDomContainer, wrappedDomContainer;

+						if (this.isRoot) {

+							unwrappedDomContainer = logMainContainer;

+							wrappedDomContainer = logMainContainer;

+						} else {

+							unwrappedDomContainer = this.getUnwrappedDomContainer();

+							wrappedDomContainer = this.getWrappedDomContainer();

+						}

+						this.unwrappedElementContainer = new GroupElementContainer(this, unwrappedDomContainer, this.isRoot, false);

+						this.wrappedElementContainer = new GroupElementContainer(this, wrappedDomContainer, this.isRoot, true);

+						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];

+					} else {

+						var mainDomContainer = this.isRoot ? logMainContainer : this.getMainDomContainer();

+						this.mainElementContainer = new GroupElementContainer(this, mainDomContainer, this.isRoot, false);

+						this.elementContainers = [this.mainElementContainer];

+					}

+					this.rendered = true;

+				},

+

+				toggleExpanded: function() {

+					this.expanded = !this.expanded;

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].toggleExpanded();

+					}

+				},

+

+				expand: function() {

+					if (!this.expanded) {

+						this.toggleExpanded();

+					}

+				},

+

+				accept: function(visitor) {

+					visitor.visitGroup(this);

+				},

+

+				reverseChildren: function() {

+					if (this.rendered) {

+						for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+							this.elementContainers[i].reverseChildren();

+						}

+					}

+				},

+

+				update: function() {

+					var previouslyExpandable = this.expandable;

+					this.expandable = (this.children.length !== 0);

+					if (this.expandable !== previouslyExpandable) {

+						for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+							this.elementContainers[i].update();

+						}

+					}

+				},

+

+				flatten: function() {

+					var visitor = new GroupFlattener();

+					this.accept(visitor);

+					return visitor.logEntriesAndSeparators;

+				},

+

+				removeChild: function(child, doUpdate) {

+					array_remove(this.children, child);

+					child.group = null;

+					if (doUpdate) {

+						this.update();

+					}

+				},

+

+				remove: function(doUpdate, removeFromGroup) {

+					for (var i = 0, len = this.children.length; i < len; i++) {

+						this.children[i].remove(false, false);

+					}

+					this.children = [];

+					this.update();

+					if (this === currentGroup) {

+						currentGroup = this.group;

+					}

+					this.doRemove(doUpdate, removeFromGroup);

+				},

+

+				serialize: function(items) {

+					items.push([LogItem.serializedItemKeys.GROUP_START, this.name]);

+					for (var i = 0, len = this.children.length; i < len; i++) {

+						this.children[i].serialize(items);

+					}

+					if (this !== currentGroup) {

+						items.push([LogItem.serializedItemKeys.GROUP_END]);

+					}

+				},

+

+				clear: function() {

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].clear();

+					}

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntryElementContainer() {

+			}

+

+			LogEntryElementContainer.prototype = new LogItemContainerElement();

+

+			copyProperties(LogEntryElementContainer.prototype, {

+				remove: function() {

+					this.doRemove();

+				},

+

+				doRemove: function() {

+					this.mainDiv.parentNode.removeChild(this.mainDiv);

+					this.mainDiv = null;

+					this.contentElement = null;

+					this.containerDomNode = null;

+				},

+

+				setContent: function(content, wrappedContent) {

+					if (content === this.formattedMessage) {

+						this.contentElement.innerHTML = "";

+						this.contentElement.appendChild(document.createTextNode(this.formattedMessage));

+					} else {

+						this.contentElement.innerHTML = content;

+					}

+				},

+

+				setSearchMatch: function(isMatch) {

+					var oldCssClass = isMatch ? "searchnonmatch" : "searchmatch";

+					var newCssClass = isMatch ? "searchmatch" : "searchnonmatch";

+					replaceClass(this.mainDiv, newCssClass, oldCssClass);

+				},

+

+				clearSearch: function() {

+					removeClass(this.mainDiv, "searchmatch");

+					removeClass(this.mainDiv, "searchnonmatch");

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntryWrappedElementContainer(logEntry, containerDomNode) {

+				this.logEntry = logEntry;

+				this.containerDomNode = containerDomNode;

+				this.mainDiv = document.createElement("div");

+				this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));

+				this.mainDiv.className = "logentry wrapped " + this.logEntry.level;

+				this.contentElement = this.mainDiv;

+			}

+

+			LogEntryWrappedElementContainer.prototype = new LogEntryElementContainer();

+

+			LogEntryWrappedElementContainer.prototype.setContent = function(content, wrappedContent) {

+				if (content === this.formattedMessage) {

+					this.contentElement.innerHTML = "";

+					this.contentElement.appendChild(document.createTextNode(this.formattedMessage));

+				} else {

+					this.contentElement.innerHTML = wrappedContent;

+				}

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntryUnwrappedElementContainer(logEntry, containerDomNode) {

+				this.logEntry = logEntry;

+				this.containerDomNode = containerDomNode;

+				this.mainDiv = document.createElement("div");

+				this.mainDiv.className = "logentry unwrapped " + this.logEntry.level;

+				this.pre = this.mainDiv.appendChild(document.createElement("pre"));

+				this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));

+				this.pre.className = "unwrapped";

+				this.contentElement = this.pre;

+			}

+

+			LogEntryUnwrappedElementContainer.prototype = new LogEntryElementContainer();

+

+			LogEntryUnwrappedElementContainer.prototype.remove = function() {

+				this.doRemove();

+				this.pre = null;

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntryMainElementContainer(logEntry, containerDomNode) {

+				this.logEntry = logEntry;

+				this.containerDomNode = containerDomNode;

+				this.mainDiv = document.createElement("div");

+				this.mainDiv.className = "logentry nonielogentry " + this.logEntry.level;

+				this.contentElement = this.mainDiv.appendChild(document.createElement("span"));

+				this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));

+			}

+

+			LogEntryMainElementContainer.prototype = new LogEntryElementContainer();

+

+			/*----------------------------------------------------------------*/

+

+			function LogEntry(level, formattedMessage) {

+				this.level = level;

+				this.formattedMessage = formattedMessage;

+				this.rendered = false;

+			}

+

+			LogEntry.prototype = new LogItem();

+

+			copyProperties(LogEntry.prototype, {

+				render: function() {

+					var logEntry = this;

+					var containerDomNode = this.group.contentDiv;

+

+					// Support for the CSS attribute white-space in IE for Windows is

+					// non-existent pre version 6 and slightly odd in 6, so instead

+					// use two different HTML elements

+					if (isIe) {

+						this.formattedMessage = this.formattedMessage.replace(/\r\n/g, "\r"); // Workaround for IE's treatment of white space

+						this.unwrappedElementContainer = new LogEntryUnwrappedElementContainer(this, this.getUnwrappedDomContainer());

+						this.wrappedElementContainer = new LogEntryWrappedElementContainer(this, this.getWrappedDomContainer());

+						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];

+					} else {

+						this.mainElementContainer = new LogEntryMainElementContainer(this, this.getMainDomContainer());

+						this.elementContainers = [this.mainElementContainer];

+					}

+					this.content = this.formattedMessage;

+					this.rendered = true;

+				},

+

+				setContent: function(content, wrappedContent) {

+					if (content != this.content) {

+						if (isIe && (content !== this.formattedMessage)) {

+							content = content.replace(/\r\n/g, "\r"); // Workaround for IE's treatment of white space

+						}

+						for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+							this.elementContainers[i].setContent(content, wrappedContent);

+						}

+						this.content = content;

+					}

+				},

+

+				getSearchMatches: function() {

+					var matches = [];

+					var i, len;

+					if (isIe) {

+						var unwrappedEls = getElementsByClass(this.unwrappedElementContainer.mainDiv, "searchterm", "span");

+						var wrappedEls = getElementsByClass(this.wrappedElementContainer.mainDiv, "searchterm", "span");

+						for (i = 0, len = unwrappedEls.length; i < len; i++) {

+							matches[i] = new Match(this.level, null, unwrappedEls[i], wrappedEls[i]);

+						}

+					} else {

+						var els = getElementsByClass(this.mainElementContainer.mainDiv, "searchterm", "span");

+						for (i = 0, len = els.length; i < len; i++) {

+							matches[i] = new Match(this.level, els[i]);

+						}

+					}

+					return matches;

+				},

+

+				setSearchMatch: function(isMatch) {

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].setSearchMatch(isMatch);

+					}

+				},

+

+				clearSearch: function() {

+					for (var i = 0, len = this.elementContainers.length; i < len; i++) {

+						this.elementContainers[i].clearSearch();

+					}

+				},

+

+				accept: function(visitor) {

+					visitor.visitLogEntry(this);

+				},

+

+				serialize: function(items) {

+					items.push([LogItem.serializedItemKeys.LOG_ENTRY, this.level, this.formattedMessage]);

+				}

+			});

+

+			/*----------------------------------------------------------------*/

+

+			function LogItemVisitor() {

+			}

+

+			LogItemVisitor.prototype = {

+				visit: function(logItem) {

+				},

+

+				visitParent: function(logItem) {

+					if (logItem.group) {

+						logItem.group.accept(this);

+					}

+				},

+

+				visitChildren: function(logItem) {

+					for (var i = 0, len = logItem.children.length; i < len; i++) {

+						logItem.children[i].accept(this);

+					}

+				},

+

+				visitLogEntry: function(logEntry) {

+					this.visit(logEntry);

+				},

+

+				visitSeparator: function(separator) {

+					this.visit(separator);

+				},

+

+				visitGroup: function(group) {

+					this.visit(group);

+				}

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function GroupFlattener() {

+				this.logEntriesAndSeparators = [];

+			}

+

+			GroupFlattener.prototype = new LogItemVisitor();

+

+			GroupFlattener.prototype.visitGroup = function(group) {

+				this.visitChildren(group);

+			};

+

+			GroupFlattener.prototype.visitLogEntry = function(logEntry) {

+				this.logEntriesAndSeparators.push(logEntry);

+			};

+

+			GroupFlattener.prototype.visitSeparator = function(separator) {

+				this.logEntriesAndSeparators.push(separator);

+			};

+

+			/*----------------------------------------------------------------*/

+

+			window.onload = function() {

+				// Sort out document.domain

+				if (location.search) {

+					var queryBits = unescape(location.search).substr(1).split("&"), nameValueBits;

+					for (var i = 0, len = queryBits.length; i < len; i++) {

+						nameValueBits = queryBits[i].split("=");

+						if (nameValueBits[0] == "log4javascript_domain") {

+							document.domain = nameValueBits[1];

+							break;

+						}

+					}

+				}

+

+				// Create DOM objects

+				logMainContainer = $("log");

+				if (isIePre7) {

+					addClass(logMainContainer, "oldIe");

+				}

+

+				rootGroup = new Group("root", true);

+				rootGroup.render();

+				currentGroup = rootGroup;

+				

+				setCommandInputWidth();

+				setLogContainerHeight();

+				toggleLoggingEnabled();

+				toggleSearchEnabled();

+				toggleSearchFilter();

+				toggleSearchHighlight();

+				applyFilters();

+				checkAllLevels();

+				toggleWrap();

+				toggleNewestAtTop();

+				toggleScrollToLatest();

+				renderQueuedLogItems();

+				loaded = true;

+				$("command").value = "";

+				$("command").autocomplete = "off";

+				$("command").onkeydown = function(evt) {

+					evt = getEvent(evt);

+					if (evt.keyCode == 10 || evt.keyCode == 13) { // Return/Enter

+						evalCommandLine();

+						stopPropagation(evt);

+					} else if (evt.keyCode == 27) { // Escape

+						this.value = "";

+						this.focus();

+					} else if (evt.keyCode == 38 && commandHistory.length > 0) { // Up

+						currentCommandIndex = Math.max(0, currentCommandIndex - 1);

+						this.value = commandHistory[currentCommandIndex];

+						moveCaretToEnd(this);

+					} else if (evt.keyCode == 40 && commandHistory.length > 0) { // Down

+						currentCommandIndex = Math.min(commandHistory.length - 1, currentCommandIndex + 1);

+						this.value = commandHistory[currentCommandIndex];

+						moveCaretToEnd(this);

+					}

+				};

+

+				// Prevent the keypress moving the caret in Firefox

+				$("command").onkeypress = function(evt) {

+					evt = getEvent(evt);

+					if (evt.keyCode == 38 && commandHistory.length > 0 && evt.preventDefault) { // Up

+						evt.preventDefault();

+					}

+				};

+

+				// Prevent the keyup event blurring the input in Opera

+				$("command").onkeyup = function(evt) {

+					evt = getEvent(evt);

+					if (evt.keyCode == 27 && evt.preventDefault) { // Up

+						evt.preventDefault();

+						this.focus();

+					}

+				};

+

+				// Add document keyboard shortcuts

+				document.onkeydown = function keyEventHandler(evt) {

+					evt = getEvent(evt);

+					switch (evt.keyCode) {

+						case 69: // Ctrl + shift + E: re-execute last command

+							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {

+								evalLastCommand();

+								cancelKeyEvent(evt);

+								return false;

+							}

+							break;

+						case 75: // Ctrl + shift + K: focus search

+							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {

+								focusSearch();

+								cancelKeyEvent(evt);

+								return false;

+							}

+							break;

+						case 40: // Ctrl + shift + down arrow: focus command line

+						case 76: // Ctrl + shift + L: focus command line

+							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {

+								focusCommandLine();

+								cancelKeyEvent(evt);

+								return false;

+							}

+							break;

+					}

+				};

+

+				// Workaround to make sure log div starts at the correct size

+				setTimeout(setLogContainerHeight, 20);

+

+				setShowCommandLine(showCommandLine);

+				doSearch();

+			};

+

+			window.onunload = function() {

+				if (mainWindowExists()) {

+					appender.unload();

+				}

+				appender = null;

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function toggleLoggingEnabled() {

+				setLoggingEnabled($("enableLogging").checked);

+			}

+

+			function setLoggingEnabled(enable) {

+				loggingEnabled = enable;

+			}

+

+			var appender = null;

+

+			function setAppender(appenderParam) {

+				appender = appenderParam;

+			}

+

+			function setShowCloseButton(showCloseButton) {

+				$("closeButton").style.display = showCloseButton ? "inline" : "none";

+			}

+

+			function setShowHideButton(showHideButton) {

+				$("hideButton").style.display = showHideButton ? "inline" : "none";

+			}

+

+			var newestAtTop = false;

+

+			/*----------------------------------------------------------------*/

+

+			function LogItemContentReverser() {

+			}

+			

+			LogItemContentReverser.prototype = new LogItemVisitor();

+			

+			LogItemContentReverser.prototype.visitGroup = function(group) {

+				group.reverseChildren();

+				this.visitChildren(group);

+			};

+

+			/*----------------------------------------------------------------*/

+

+			function setNewestAtTop(isNewestAtTop) {

+				var oldNewestAtTop = newestAtTop;

+				var i, iLen, j, jLen;

+				newestAtTop = Boolean(isNewestAtTop);

+				if (oldNewestAtTop != newestAtTop) {

+					var visitor = new LogItemContentReverser();

+					rootGroup.accept(visitor);

+

+					// Reassemble the matches array

+					if (currentSearch) {

+						var currentMatch = currentSearch.matches[currentMatchIndex];

+						var matchIndex = 0;

+						var matches = [];

+						var actOnLogEntry = function(logEntry) {

+							var logEntryMatches = logEntry.getSearchMatches();

+							for (j = 0, jLen = logEntryMatches.length; j < jLen; j++) {

+								matches[matchIndex] = logEntryMatches[j];

+								if (currentMatch && logEntryMatches[j].equals(currentMatch)) {

+									currentMatchIndex = matchIndex;

+								}

+								matchIndex++;

+							}

+						};

+						if (newestAtTop) {

+							for (i = logEntries.length - 1; i >= 0; i--) {

+								actOnLogEntry(logEntries[i]);

+							}

+						} else {

+							for (i = 0, iLen = logEntries.length; i < iLen; i++) {

+								actOnLogEntry(logEntries[i]);

+							}

+						}

+						currentSearch.matches = matches;

+						if (currentMatch) {

+							currentMatch.setCurrent();

+						}

+					} else if (scrollToLatest) {

+						doScrollToLatest();

+					}

+				}

+				$("newestAtTop").checked = isNewestAtTop;

+			}

+

+			function toggleNewestAtTop() {

+				var isNewestAtTop = $("newestAtTop").checked;

+				setNewestAtTop(isNewestAtTop);

+			}

+

+			var scrollToLatest = true;

+

+			function setScrollToLatest(isScrollToLatest) {

+				scrollToLatest = isScrollToLatest;

+				if (scrollToLatest) {

+					doScrollToLatest();

+				}

+				$("scrollToLatest").checked = isScrollToLatest;

+			}

+

+			function toggleScrollToLatest() {

+				var isScrollToLatest = $("scrollToLatest").checked;

+				setScrollToLatest(isScrollToLatest);

+			}

+

+			function doScrollToLatest() {

+				var l = logMainContainer;

+				if (typeof l.scrollTop != "undefined") {

+					if (newestAtTop) {

+						l.scrollTop = 0;

+					} else {

+						var latestLogEntry = l.lastChild;

+						if (latestLogEntry) {

+							l.scrollTop = l.scrollHeight;

+						}

+					}

+				}

+			}

+

+			var closeIfOpenerCloses = true;

+

+			function setCloseIfOpenerCloses(isCloseIfOpenerCloses) {

+				closeIfOpenerCloses = isCloseIfOpenerCloses;

+			}

+

+			var maxMessages = null;

+

+			function setMaxMessages(max) {

+				maxMessages = max;

+				pruneLogEntries();

+			}

+

+			var showCommandLine = false;

+

+			function setShowCommandLine(isShowCommandLine) {

+				showCommandLine = isShowCommandLine;

+				if (loaded) {

+					$("commandLine").style.display = showCommandLine ? "block" : "none";

+					setCommandInputWidth();

+					setLogContainerHeight();

+				}

+			}

+

+			function focusCommandLine() {

+				if (loaded) {

+					$("command").focus();

+				}

+			}

+

+			function focusSearch() {

+				if (loaded) {

+					$("searchBox").focus();

+				}

+			}

+

+			function getLogItems() {

+				var items = [];

+				for (var i = 0, len = logItems.length; i < len; i++) {

+					logItems[i].serialize(items);

+				}

+				return items;

+			}

+

+			function setLogItems(items) {

+				var loggingReallyEnabled = loggingEnabled;

+				// Temporarily turn logging on

+				loggingEnabled = true;

+				for (var i = 0, len = items.length; i < len; i++) {

+					switch (items[i][0]) {

+						case LogItem.serializedItemKeys.LOG_ENTRY:

+							log(items[i][1], items[i][2]);

+							break;

+						case LogItem.serializedItemKeys.GROUP_START:

+							group(items[i][1]);

+							break;

+						case LogItem.serializedItemKeys.GROUP_END:

+							groupEnd();

+							break;

+					}

+				}

+				loggingEnabled = loggingReallyEnabled;

+			}

+

+			function log(logLevel, formattedMessage) {

+				if (loggingEnabled) {

+					var logEntry = new LogEntry(logLevel, formattedMessage);

+					logEntries.push(logEntry);

+					logEntriesAndSeparators.push(logEntry);

+					logItems.push(logEntry);

+					currentGroup.addChild(logEntry);

+					if (loaded) {

+						if (logQueuedEventsTimer !== null) {

+							clearTimeout(logQueuedEventsTimer);

+						}

+						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);

+						unrenderedLogItemsExist = true;

+					}

+				}

+			}

+

+			function renderQueuedLogItems() {

+				logQueuedEventsTimer = null;

+				var pruned = pruneLogEntries();

+

+				// Render any unrendered log entries and apply the current search to them

+				var initiallyHasMatches = currentSearch ? currentSearch.hasMatches() : false;

+				for (var i = 0, len = logItems.length; i < len; i++) {

+					if (!logItems[i].rendered) {

+						logItems[i].render();

+						logItems[i].appendToLog();

+						if (currentSearch && (logItems[i] instanceof LogEntry)) {

+							currentSearch.applyTo(logItems[i]);

+						}

+					}

+				}

+				if (currentSearch) {

+					if (pruned) {

+						if (currentSearch.hasVisibleMatches()) {

+							if (currentMatchIndex === null) {

+								setCurrentMatchIndex(0);

+							}

+							displayMatches();

+						} else {

+							displayNoMatches();

+						}

+					} else if (!initiallyHasMatches && currentSearch.hasVisibleMatches()) {

+						setCurrentMatchIndex(0);

+						displayMatches();

+					}

+				}

+				if (scrollToLatest) {

+					doScrollToLatest();

+				}

+				unrenderedLogItemsExist = false;

+			}

+

+			function pruneLogEntries() {

+				if ((maxMessages !== null) && (logEntriesAndSeparators.length > maxMessages)) {

+					var numberToDelete = logEntriesAndSeparators.length - maxMessages;

+					var prunedLogEntries = logEntriesAndSeparators.slice(0, numberToDelete);

+					if (currentSearch) {

+						currentSearch.removeMatches(prunedLogEntries);

+					}

+					var group;

+					for (var i = 0; i < numberToDelete; i++) {

+						group = logEntriesAndSeparators[i].group;

+						array_remove(logItems, logEntriesAndSeparators[i]);

+						array_remove(logEntries, logEntriesAndSeparators[i]);

+						logEntriesAndSeparators[i].remove(true, true);

+						if (group.children.length === 0 && group !== currentGroup && group !== rootGroup) {

+							array_remove(logItems, group);

+							group.remove(true, true);

+						}

+					}

+					logEntriesAndSeparators = array_removeFromStart(logEntriesAndSeparators, numberToDelete);

+					return true;

+				}

+				return false;

+			}

+

+			function group(name, startExpanded) {

+				if (loggingEnabled) {

+					initiallyExpanded = (typeof startExpanded === "undefined") ? true : Boolean(startExpanded);

+					var newGroup = new Group(name, false, initiallyExpanded);

+					currentGroup.addChild(newGroup);

+					currentGroup = newGroup;

+					logItems.push(newGroup);

+					if (loaded) {

+						if (logQueuedEventsTimer !== null) {

+							clearTimeout(logQueuedEventsTimer);

+						}

+						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);

+						unrenderedLogItemsExist = true;

+					}

+				}

+			}

+

+			function groupEnd() {

+				currentGroup = (currentGroup === rootGroup) ? rootGroup : currentGroup.group;

+			}

+

+			function mainPageReloaded() {

+				currentGroup = rootGroup;

+				var separator = new Separator();

+				logEntriesAndSeparators.push(separator);

+				logItems.push(separator);

+				currentGroup.addChild(separator);

+			}

+

+			function closeWindow() {

+				if (appender && mainWindowExists()) {

+					appender.close(true);

+				} else {

+					window.close();

+				}

+			}

+

+			function hide() {

+				if (appender && mainWindowExists()) {

+					appender.hide();

+				}

+			}

+

+			var mainWindow = window;

+			var windowId = "log4javascriptConsoleWindow_" + new Date().getTime() + "_" + ("" + Math.random()).substr(2);

+

+			function setMainWindow(win) {

+				mainWindow = win;

+				mainWindow[windowId] = window;

+				// If this is a pop-up, poll the opener to see if it's closed

+				if (opener && closeIfOpenerCloses) {

+					pollOpener();

+				}

+			}

+

+			function pollOpener() {

+				if (closeIfOpenerCloses) {

+					if (mainWindowExists()) {

+						setTimeout(pollOpener, 500);

+					} else {

+						closeWindow();

+					}

+				}

+			}

+

+			function mainWindowExists() {

+				try {

+					return (mainWindow && !mainWindow.closed &&

+						mainWindow[windowId] == window);

+				} catch (ex) {}

+				return false;

+			}

+

+			var logLevels = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"];

+

+			function getCheckBox(logLevel) {

+				return $("switch_" + logLevel);

+			}

+

+			function getIeWrappedLogContainer() {

+				return $("log_wrapped");

+			}

+

+			function getIeUnwrappedLogContainer() {

+				return $("log_unwrapped");

+			}

+

+			function applyFilters() {

+				for (var i = 0; i < logLevels.length; i++) {

+					if (getCheckBox(logLevels[i]).checked) {

+						addClass(logMainContainer, logLevels[i]);

+					} else {

+						removeClass(logMainContainer, logLevels[i]);

+					}

+				}

+				updateSearchFromFilters();

+			}

+

+			function toggleAllLevels() {

+				var turnOn = $("switch_ALL").checked;

+				for (var i = 0; i < logLevels.length; i++) {

+					getCheckBox(logLevels[i]).checked = turnOn;

+					if (turnOn) {

+						addClass(logMainContainer, logLevels[i]);

+					} else {

+						removeClass(logMainContainer, logLevels[i]);

+					}

+				}

+			}

+

+			function checkAllLevels() {

+				for (var i = 0; i < logLevels.length; i++) {

+					if (!getCheckBox(logLevels[i]).checked) {

+						getCheckBox("ALL").checked = false;

+						return;

+					}

+				}

+				getCheckBox("ALL").checked = true;

+			}

+

+			function clearLog() {

+				rootGroup.clear();

+				currentGroup = rootGroup;

+				logEntries = [];

+				logItems = [];

+				logEntriesAndSeparators = [];

+ 				doSearch();

+			}

+

+			function toggleWrap() {

+				var enable = $("wrap").checked;

+				if (enable) {

+					addClass(logMainContainer, "wrap");

+				} else {

+					removeClass(logMainContainer, "wrap");

+				}

+				refreshCurrentMatch();

+			}

+

+			/* ------------------------------------------------------------------- */

+

+			// Search

+

+			var searchTimer = null;

+

+			function scheduleSearch() {

+				try {

+					clearTimeout(searchTimer);

+				} catch (ex) {

+					// Do nothing

+				}

+				searchTimer = setTimeout(doSearch, 500);

+			}

+

+			function Search(searchTerm, isRegex, searchRegex, isCaseSensitive) {

+				this.searchTerm = searchTerm;

+				this.isRegex = isRegex;

+				this.searchRegex = searchRegex;

+				this.isCaseSensitive = isCaseSensitive;

+				this.matches = [];

+			}

+

+			Search.prototype = {

+				hasMatches: function() {

+					return this.matches.length > 0;

+				},

+

+				hasVisibleMatches: function() {

+					if (this.hasMatches()) {

+						for (var i = 0; i < this.matches.length; i++) {

+							if (this.matches[i].isVisible()) {

+								return true;

+							}

+						}

+					}

+					return false;

+				},

+

+				match: function(logEntry) {

+					var entryText = String(logEntry.formattedMessage);

+					var matchesSearch = false;

+					if (this.isRegex) {

+						matchesSearch = this.searchRegex.test(entryText);

+					} else if (this.isCaseSensitive) {

+						matchesSearch = (entryText.indexOf(this.searchTerm) > -1);

+					} else {

+						matchesSearch = (entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1);

+					}

+					return matchesSearch;

+				},

+

+				getNextVisibleMatchIndex: function() {

+					for (var i = currentMatchIndex + 1; i < this.matches.length; i++) {

+						if (this.matches[i].isVisible()) {

+							return i;

+						}

+					}

+					// Start again from the first match

+					for (i = 0; i <= currentMatchIndex; i++) {

+						if (this.matches[i].isVisible()) {

+							return i;

+						}

+					}

+					return -1;

+				},

+

+				getPreviousVisibleMatchIndex: function() {

+					for (var i = currentMatchIndex - 1; i >= 0; i--) {

+						if (this.matches[i].isVisible()) {

+							return i;

+						}

+					}

+					// Start again from the last match

+					for (var i = this.matches.length - 1; i >= currentMatchIndex; i--) {

+						if (this.matches[i].isVisible()) {

+							return i;

+						}

+					}

+					return -1;

+				},

+

+				applyTo: function(logEntry) {

+					var doesMatch = this.match(logEntry);

+					if (doesMatch) {

+						logEntry.group.expand();

+						logEntry.setSearchMatch(true);

+						var logEntryContent;

+						var wrappedLogEntryContent;

+						var searchTermReplacementStartTag = "<span class=\"searchterm\">";

+						var searchTermReplacementEndTag = "<" + "/span>";

+						var preTagName = isIe ? "pre" : "span";

+						var preStartTag = "<" + preTagName + " class=\"pre\">";

+						var preEndTag = "<" + "/" + preTagName + ">";

+						var startIndex = 0;

+						var searchIndex, matchedText, textBeforeMatch;

+						if (this.isRegex) {

+							var flags = this.isCaseSensitive ? "g" : "gi";

+							var capturingRegex = new RegExp("(" + this.searchRegex.source + ")", flags);

+

+							// Replace the search term with temporary tokens for the start and end tags

+							var rnd = ("" + Math.random()).substr(2);

+							var startToken = "%%s" + rnd + "%%";

+							var endToken = "%%e" + rnd + "%%";

+							logEntryContent = logEntry.formattedMessage.replace(capturingRegex, startToken + "$1" + endToken);

+

+							// Escape the HTML to get rid of angle brackets

+							logEntryContent = escapeHtml(logEntryContent);

+

+							// Substitute the proper HTML back in for the search match

+							var result;

+							var searchString = logEntryContent;

+							logEntryContent = "";

+							wrappedLogEntryContent = "";

+							while ((searchIndex = searchString.indexOf(startToken, startIndex)) > -1) {

+								var endTokenIndex = searchString.indexOf(endToken, searchIndex);

+								matchedText = searchString.substring(searchIndex + startToken.length, endTokenIndex);

+								textBeforeMatch = searchString.substring(startIndex, searchIndex);

+								logEntryContent += preStartTag + textBeforeMatch + preEndTag;

+								logEntryContent += searchTermReplacementStartTag + preStartTag + matchedText +

+									preEndTag + searchTermReplacementEndTag;

+								if (isIe) {

+									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +

+										matchedText + searchTermReplacementEndTag;

+								}

+								startIndex = endTokenIndex + endToken.length;

+							}

+							logEntryContent += preStartTag + searchString.substr(startIndex) + preEndTag;

+							if (isIe) {

+								wrappedLogEntryContent += searchString.substr(startIndex);

+							}

+						} else {

+							logEntryContent = "";

+							wrappedLogEntryContent = "";

+							var searchTermReplacementLength = searchTermReplacementStartTag.length +

+								this.searchTerm.length + searchTermReplacementEndTag.length;

+							var searchTermLength = this.searchTerm.length;

+							var searchTermLowerCase = this.searchTerm.toLowerCase();

+							var logTextLowerCase = logEntry.formattedMessage.toLowerCase();

+							while ((searchIndex = logTextLowerCase.indexOf(searchTermLowerCase, startIndex)) > -1) {

+								matchedText = escapeHtml(logEntry.formattedMessage.substr(searchIndex, this.searchTerm.length));

+								textBeforeMatch = escapeHtml(logEntry.formattedMessage.substring(startIndex, searchIndex));

+								var searchTermReplacement = searchTermReplacementStartTag +

+									preStartTag + matchedText + preEndTag + searchTermReplacementEndTag;

+								logEntryContent += preStartTag + textBeforeMatch + preEndTag + searchTermReplacement;

+								if (isIe) {

+									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +

+										matchedText + searchTermReplacementEndTag;

+								}

+								startIndex = searchIndex + searchTermLength;

+							}

+							var textAfterLastMatch = escapeHtml(logEntry.formattedMessage.substr(startIndex));

+							logEntryContent += preStartTag + textAfterLastMatch + preEndTag;

+							if (isIe) {

+								wrappedLogEntryContent += textAfterLastMatch;

+							}

+						}

+						logEntry.setContent(logEntryContent, wrappedLogEntryContent);

+						var logEntryMatches = logEntry.getSearchMatches();

+						this.matches = this.matches.concat(logEntryMatches);

+					} else {

+						logEntry.setSearchMatch(false);

+						logEntry.setContent(logEntry.formattedMessage, logEntry.formattedMessage);

+					}

+					return doesMatch;

+				},

+

+				removeMatches: function(logEntries) {

+					var matchesToRemoveCount = 0;

+					var currentMatchRemoved = false;

+					var matchesToRemove = [];

+					var i, iLen, j, jLen;

+

+					// Establish the list of matches to be removed

+					for (i = 0, iLen = this.matches.length; i < iLen; i++) {

+						for (j = 0, jLen = logEntries.length; j < jLen; j++) {

+							if (this.matches[i].belongsTo(logEntries[j])) {

+								matchesToRemove.push(this.matches[i]);

+								if (i === currentMatchIndex) {

+									currentMatchRemoved = true;

+								}

+							}

+						}

+					}

+

+					// Set the new current match index if the current match has been deleted

+					// This will be the first match that appears after the first log entry being

+					// deleted, if one exists; otherwise, it's the first match overall

+					var newMatch = currentMatchRemoved ? null : this.matches[currentMatchIndex];

+					if (currentMatchRemoved) {

+						for (i = currentMatchIndex, iLen = this.matches.length; i < iLen; i++) {

+							if (this.matches[i].isVisible() && !array_contains(matchesToRemove, this.matches[i])) {

+								newMatch = this.matches[i];

+								break;

+							}

+						}

+					}

+

+					// Remove the matches

+					for (i = 0, iLen = matchesToRemove.length; i < iLen; i++) {

+						array_remove(this.matches, matchesToRemove[i]);

+						matchesToRemove[i].remove();

+					}

+

+					// Set the new match, if one exists

+					if (this.hasVisibleMatches()) {

+						if (newMatch === null) {

+							setCurrentMatchIndex(0);

+						} else {

+							// Get the index of the new match

+							var newMatchIndex = 0;

+							for (i = 0, iLen = this.matches.length; i < iLen; i++) {

+								if (newMatch === this.matches[i]) {

+									newMatchIndex = i;

+									break;

+								}

+							}

+							setCurrentMatchIndex(newMatchIndex);

+						}

+					} else {

+						currentMatchIndex = null;

+						displayNoMatches();

+					}

+				}

+			};

+

+			function getPageOffsetTop(el, container) {

+				var currentEl = el;

+				var y = 0;

+				while (currentEl && currentEl != container) {

+					y += currentEl.offsetTop;

+					currentEl = currentEl.offsetParent;

+				}

+				return y;

+			}

+

+			function scrollIntoView(el) {

+				var logContainer = logMainContainer;

+				// Check if the whole width of the element is visible and centre if not

+				if (!$("wrap").checked) {

+					var logContainerLeft = logContainer.scrollLeft;

+					var logContainerRight = logContainerLeft  + logContainer.offsetWidth;

+					var elLeft = el.offsetLeft;

+					var elRight = elLeft + el.offsetWidth;

+					if (elLeft < logContainerLeft || elRight > logContainerRight) {

+						logContainer.scrollLeft = elLeft - (logContainer.offsetWidth - el.offsetWidth) / 2;

+					}

+				}

+				// Check if the whole height of the element is visible and centre if not

+				var logContainerTop = logContainer.scrollTop;

+				var logContainerBottom = logContainerTop  + logContainer.offsetHeight;

+				var elTop = getPageOffsetTop(el) - getToolBarsHeight();

+				var elBottom = elTop + el.offsetHeight;

+				if (elTop < logContainerTop || elBottom > logContainerBottom) {

+					logContainer.scrollTop = elTop - (logContainer.offsetHeight - el.offsetHeight) / 2;

+				}

+			}

+

+			function Match(logEntryLevel, spanInMainDiv, spanInUnwrappedPre, spanInWrappedDiv) {

+				this.logEntryLevel = logEntryLevel;

+				this.spanInMainDiv = spanInMainDiv;

+				if (isIe) {

+					this.spanInUnwrappedPre = spanInUnwrappedPre;

+					this.spanInWrappedDiv = spanInWrappedDiv;

+				}

+				this.mainSpan = isIe ? spanInUnwrappedPre : spanInMainDiv;

+			}

+

+			Match.prototype = {

+				equals: function(match) {

+					return this.mainSpan === match.mainSpan;

+				},

+

+				setCurrent: function() {

+					if (isIe) {

+						addClass(this.spanInUnwrappedPre, "currentmatch");

+						addClass(this.spanInWrappedDiv, "currentmatch");

+						// Scroll the visible one into view

+						var elementToScroll = $("wrap").checked ? this.spanInWrappedDiv : this.spanInUnwrappedPre;

+						scrollIntoView(elementToScroll);

+					} else {

+						addClass(this.spanInMainDiv, "currentmatch");

+						scrollIntoView(this.spanInMainDiv);

+					}

+				},

+

+				belongsTo: function(logEntry) {

+					if (isIe) {

+						return isDescendant(this.spanInUnwrappedPre, logEntry.unwrappedPre);

+					} else {

+						return isDescendant(this.spanInMainDiv, logEntry.mainDiv);

+					}

+				},

+

+				setNotCurrent: function() {

+					if (isIe) {

+						removeClass(this.spanInUnwrappedPre, "currentmatch");

+						removeClass(this.spanInWrappedDiv, "currentmatch");

+					} else {

+						removeClass(this.spanInMainDiv, "currentmatch");

+					}

+				},

+

+				isOrphan: function() {

+					return isOrphan(this.mainSpan);

+				},

+

+				isVisible: function() {

+					return getCheckBox(this.logEntryLevel).checked;

+				},

+

+				remove: function() {

+					if (isIe) {

+						this.spanInUnwrappedPre = null;

+						this.spanInWrappedDiv = null;

+					} else {

+						this.spanInMainDiv = null;

+					}

+				}

+			};

+

+			var currentSearch = null;

+			var currentMatchIndex = null;

+

+			function doSearch() {

+				var searchBox = $("searchBox");

+				var searchTerm = searchBox.value;

+				var isRegex = $("searchRegex").checked;

+				var isCaseSensitive = $("searchCaseSensitive").checked;

+				var i;

+

+				if (searchTerm === "") {

+					$("searchReset").disabled = true;

+					$("searchNav").style.display = "none";

+					removeClass(document.body, "searching");

+					removeClass(searchBox, "hasmatches");

+					removeClass(searchBox, "nomatches");

+					for (i = 0; i < logEntries.length; i++) {

+						logEntries[i].clearSearch();

+						logEntries[i].setContent(logEntries[i].formattedMessage, logEntries[i].formattedMessage);

+					}

+					currentSearch = null;

+					setLogContainerHeight();

+				} else {

+					$("searchReset").disabled = false;

+					$("searchNav").style.display = "block";

+					var searchRegex;

+					var regexValid;

+					if (isRegex) {

+						try {

+							searchRegex = isCaseSensitive ? new RegExp(searchTerm, "g") : new RegExp(searchTerm, "gi");

+							regexValid = true;

+							replaceClass(searchBox, "validregex", "invalidregex");

+							searchBox.title = "Valid regex";

+						} catch (ex) {

+							regexValid = false;

+							replaceClass(searchBox, "invalidregex", "validregex");

+							searchBox.title = "Invalid regex: " + (ex.message ? ex.message : (ex.description ? ex.description : "unknown error"));

+							return;

+						}

+					} else {

+						searchBox.title = "";

+						removeClass(searchBox, "validregex");

+						removeClass(searchBox, "invalidregex");

+					}

+					addClass(document.body, "searching");

+					currentSearch = new Search(searchTerm, isRegex, searchRegex, isCaseSensitive);

+					for (i = 0; i < logEntries.length; i++) {

+						currentSearch.applyTo(logEntries[i]);

+					}

+					setLogContainerHeight();

+

+					// Highlight the first search match

+					if (currentSearch.hasVisibleMatches()) {

+						setCurrentMatchIndex(0);

+						displayMatches();

+					} else {

+						displayNoMatches();

+					}

+				}

+			}

+

+			function updateSearchFromFilters() {

+				if (currentSearch) {

+					if (currentSearch.hasMatches()) {

+						if (currentMatchIndex === null) {

+							currentMatchIndex = 0;

+						}

+						var currentMatch = currentSearch.matches[currentMatchIndex];

+						if (currentMatch.isVisible()) {

+							displayMatches();

+							setCurrentMatchIndex(currentMatchIndex);

+						} else {

+							currentMatch.setNotCurrent();

+							// Find the next visible match, if one exists

+							var nextVisibleMatchIndex = currentSearch.getNextVisibleMatchIndex();

+							if (nextVisibleMatchIndex > -1) {

+								setCurrentMatchIndex(nextVisibleMatchIndex);

+								displayMatches();

+							} else {

+								displayNoMatches();

+							}

+						}

+					} else {

+						displayNoMatches();

+					}

+				}

+			}

+

+			function refreshCurrentMatch() {

+				if (currentSearch && currentSearch.hasVisibleMatches()) {

+					setCurrentMatchIndex(currentMatchIndex);

+				}

+			}

+

+			function displayMatches() {

+				replaceClass($("searchBox"), "hasmatches", "nomatches");

+				$("searchBox").title = "" + currentSearch.matches.length + " matches found";

+				$("searchNav").style.display = "block";

+				setLogContainerHeight();

+			}

+

+			function displayNoMatches() {

+				replaceClass($("searchBox"), "nomatches", "hasmatches");

+				$("searchBox").title = "No matches found";

+				$("searchNav").style.display = "none";

+				setLogContainerHeight();

+			}

+

+			function toggleSearchEnabled(enable) {

+				enable = (typeof enable == "undefined") ? !$("searchDisable").checked : enable;

+				$("searchBox").disabled = !enable;

+				$("searchReset").disabled = !enable;

+				$("searchRegex").disabled = !enable;

+				$("searchNext").disabled = !enable;

+				$("searchPrevious").disabled = !enable;

+				$("searchCaseSensitive").disabled = !enable;

+				$("searchNav").style.display = (enable && ($("searchBox").value !== "") &&

+						currentSearch && currentSearch.hasVisibleMatches()) ?

+					"block" : "none";

+				if (enable) {

+					removeClass($("search"), "greyedout");

+					addClass(document.body, "searching");

+					if ($("searchHighlight").checked) {

+						addClass(logMainContainer, "searchhighlight");

+					} else {

+						removeClass(logMainContainer, "searchhighlight");

+					}

+					if ($("searchFilter").checked) {

+						addClass(logMainContainer, "searchfilter");

+					} else {

+						removeClass(logMainContainer, "searchfilter");

+					}

+					$("searchDisable").checked = !enable;

+				} else {

+					addClass($("search"), "greyedout");

+					removeClass(document.body, "searching");

+					removeClass(logMainContainer, "searchhighlight");

+					removeClass(logMainContainer, "searchfilter");

+				}

+				setLogContainerHeight();

+			}

+

+			function toggleSearchFilter() {

+				var enable = $("searchFilter").checked;

+				if (enable) {

+					addClass(logMainContainer, "searchfilter");

+				} else {

+					removeClass(logMainContainer, "searchfilter");

+				}

+				refreshCurrentMatch();

+			}

+

+			function toggleSearchHighlight() {

+				var enable = $("searchHighlight").checked;

+				if (enable) {

+					addClass(logMainContainer, "searchhighlight");

+				} else {

+					removeClass(logMainContainer, "searchhighlight");

+				}

+			}

+

+			function clearSearch() {

+				$("searchBox").value = "";

+				doSearch();

+			}

+

+			function searchNext() {

+				if (currentSearch !== null && currentMatchIndex !== null) {

+					currentSearch.matches[currentMatchIndex].setNotCurrent();

+					var nextMatchIndex = currentSearch.getNextVisibleMatchIndex();

+					if (nextMatchIndex > currentMatchIndex || confirm("Reached the end of the page. Start from the top?")) {

+						setCurrentMatchIndex(nextMatchIndex);

+					}

+				}

+			}

+

+			function searchPrevious() {

+				if (currentSearch !== null && currentMatchIndex !== null) {

+					currentSearch.matches[currentMatchIndex].setNotCurrent();

+					var previousMatchIndex = currentSearch.getPreviousVisibleMatchIndex();

+					if (previousMatchIndex < currentMatchIndex || confirm("Reached the start of the page. Continue from the bottom?")) {

+						setCurrentMatchIndex(previousMatchIndex);

+					}

+				}

+			}

+

+			function setCurrentMatchIndex(index) {

+				currentMatchIndex = index;

+				currentSearch.matches[currentMatchIndex].setCurrent();

+			}

+

+			/* ------------------------------------------------------------------------- */

+

+			// CSS Utilities

+

+			function addClass(el, cssClass) {

+				if (!hasClass(el, cssClass)) {

+					if (el.className) {

+						el.className += " " + cssClass;

+					} else {

+						el.className = cssClass;

+					}

+				}

+			}

+

+			function hasClass(el, cssClass) {

+				if (el.className) {

+					var classNames = el.className.split(" ");

+					return array_contains(classNames, cssClass);

+				}

+				return false;

+			}

+

+			function removeClass(el, cssClass) {

+				if (hasClass(el, cssClass)) {

+					// Rebuild the className property

+					var existingClasses = el.className.split(" ");

+					var newClasses = [];

+					for (var i = 0, len = existingClasses.length; i < len; i++) {

+						if (existingClasses[i] != cssClass) {

+							newClasses[newClasses.length] = existingClasses[i];

+						}

+					}

+					el.className = newClasses.join(" ");

+				}

+			}

+

+			function replaceClass(el, newCssClass, oldCssClass) {

+				removeClass(el, oldCssClass);

+				addClass(el, newCssClass);

+			}

+

+			/* ------------------------------------------------------------------------- */

+

+			// Other utility functions

+

+			function getElementsByClass(el, cssClass, tagName) {

+				var elements = el.getElementsByTagName(tagName);

+				var matches = [];

+				for (var i = 0, len = elements.length; i < len; i++) {

+					if (hasClass(elements[i], cssClass)) {

+						matches.push(elements[i]);

+					}

+				}

+				return matches;

+			}

+

+			// Syntax borrowed from Prototype library

+			function $(id) {

+				return document.getElementById(id);

+			}

+

+			function isDescendant(node, ancestorNode) {

+				while (node != null) {

+					if (node === ancestorNode) {

+						return true;

+					}

+					node = node.parentNode;

+				}

+				return false;

+			}

+

+			function isOrphan(node) {

+				var currentNode = node;

+				while (currentNode) {

+					if (currentNode == document.body) {

+						return false;

+					}

+					currentNode = currentNode.parentNode;

+				}

+				return true;

+			}

+

+			function escapeHtml(str) {

+				return str.replace(/&/g, "&amp;").replace(/[<]/g, "&lt;").replace(/>/g, "&gt;");

+			}

+

+			function getWindowWidth() {

+				if (window.innerWidth) {

+					return window.innerWidth;

+				} else if (document.documentElement && document.documentElement.clientWidth) {

+					return document.documentElement.clientWidth;

+				} else if (document.body) {

+					return document.body.clientWidth;

+				}

+				return 0;

+			}

+

+			function getWindowHeight() {

+				if (window.innerHeight) {

+					return window.innerHeight;

+				} else if (document.documentElement && document.documentElement.clientHeight) {

+					return document.documentElement.clientHeight;

+				} else if (document.body) {

+					return document.body.clientHeight;

+				}

+				return 0;

+			}

+

+			function getToolBarsHeight() {

+				return $("switches").offsetHeight;

+			}

+

+			function getChromeHeight() {

+				var height = getToolBarsHeight();

+				if (showCommandLine) {

+					height += $("commandLine").offsetHeight;

+				}

+				return height;

+			}

+

+			function setLogContainerHeight() {

+				if (logMainContainer) {

+					var windowHeight = getWindowHeight();

+					$("body").style.height = getWindowHeight() + "px";

+					logMainContainer.style.height = "" +

+						Math.max(0, windowHeight - getChromeHeight()) + "px";

+				}

+			}

+

+			function setCommandInputWidth() {

+				if (showCommandLine) {

+					$("command").style.width = "" + Math.max(0, $("commandLineContainer").offsetWidth -

+						($("evaluateButton").offsetWidth + 13)) + "px";

+				}

+			}

+

+			window.onresize = function() {

+				setCommandInputWidth();

+				setLogContainerHeight();

+			};

+

+			if (!Array.prototype.push) {

+				Array.prototype.push = function() {

+			        for (var i = 0, len = arguments.length; i < len; i++){

+			            this[this.length] = arguments[i];

+			        }

+			        return this.length;

+				};

+			}

+

+			if (!Array.prototype.pop) {

+				Array.prototype.pop = function() {

+					if (this.length > 0) {

+						var val = this[this.length - 1];

+						this.length = this.length - 1;

+						return val;

+					}

+				};

+			}

+

+			if (!Array.prototype.shift) {

+				Array.prototype.shift = function() {

+					if (this.length > 0) {

+						var firstItem = this[0];

+						for (var i = 0, len = this.length - 1; i < len; i++) {

+							this[i] = this[i + 1];

+						}

+						this.length = this.length - 1;

+						return firstItem;

+					}

+				};

+			}

+

+			if (!Array.prototype.splice) {

+				Array.prototype.splice = function(startIndex, deleteCount) {

+					var itemsAfterDeleted = this.slice(startIndex + deleteCount);

+					var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);

+					this.length = startIndex;

+					// Copy the arguments into a proper Array object

+					var argumentsArray = [];

+					for (var i = 0, len = arguments.length; i < len; i++) {

+						argumentsArray[i] = arguments[i];

+					}

+					var itemsToAppend = (argumentsArray.length > 2) ?

+						itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;

+					for (i = 0, len = itemsToAppend.length; i < len; i++) {

+						this.push(itemsToAppend[i]);

+					}

+					return itemsDeleted;

+				};

+			}

+

+			function array_remove(arr, val) {

+				var index = -1;

+				for (var i = 0, len = arr.length; i < len; i++) {

+					if (arr[i] === val) {

+						index = i;

+						break;

+					}

+				}

+				if (index >= 0) {

+					arr.splice(index, 1);

+					return index;

+				} else {

+					return false;

+				}

+			}

+

+			function array_removeFromStart(array, numberToRemove) {

+				if (Array.prototype.splice) {

+					array.splice(0, numberToRemove);

+				} else {

+					for (var i = numberToRemove, len = array.length; i < len; i++) {

+						array[i - numberToRemove] = array[i];

+					}

+					array.length = array.length - numberToRemove;

+				}

+				return array;

+			}

+

+			function array_contains(arr, val) {

+				for (var i = 0, len = arr.length; i < len; i++) {

+					if (arr[i] == val) {

+						return true;

+					}

+				}

+				return false;

+			}

+

+			function getErrorMessage(ex) {

+				if (ex.message) {

+					return ex.message;

+				} else if (ex.description) {

+					return ex.description;

+				}

+				return "" + ex;

+			}

+

+			function moveCaretToEnd(input) {

+				if (input.setSelectionRange) {

+					input.focus();

+					var length = input.value.length;

+					input.setSelectionRange(length, length);

+				} else if (input.createTextRange) {

+					var range = input.createTextRange();

+					range.collapse(false);

+					range.select();

+				}

+				input.focus();

+			}

+

+			function stopPropagation(evt) {

+				if (evt.stopPropagation) {

+					evt.stopPropagation();

+				} else if (typeof evt.cancelBubble != "undefined") {

+					evt.cancelBubble = true;

+				}

+			}

+

+			function getEvent(evt) {

+				return evt ? evt : event;

+			}

+

+			function getTarget(evt) {

+				return evt.target ? evt.target : evt.srcElement;

+			}

+

+			function getRelatedTarget(evt) {

+				if (evt.relatedTarget) {

+					return evt.relatedTarget;

+				} else if (evt.srcElement) {

+					switch(evt.type) {

+						case "mouseover":

+							return evt.fromElement;

+						case "mouseout":

+							return evt.toElement;

+						default:

+							return evt.srcElement;

+					}

+				}

+			}

+

+			function cancelKeyEvent(evt) {

+				evt.returnValue = false;

+				stopPropagation(evt);

+			}

+

+			function evalCommandLine() {

+				var expr = $("command").value;

+				evalCommand(expr);

+				$("command").value = "";

+			}

+

+			function evalLastCommand() {

+				if (lastCommand != null) {

+					evalCommand(lastCommand);

+				}

+			}

+

+			var lastCommand = null;

+			var commandHistory = [];

+			var currentCommandIndex = 0;

+

+			function evalCommand(expr) {

+				if (appender) {

+					appender.evalCommandAndAppend(expr);

+				} else {

+					var prefix = ">>> " + expr + "\r\n";

+					try {

+						log("INFO", prefix + eval(expr));

+					} catch (ex) {

+						log("ERROR", prefix + "Error: " + getErrorMessage(ex));

+					}

+				}

+				// Update command history

+				if (expr != commandHistory[commandHistory.length - 1]) {

+					commandHistory.push(expr);

+					// Update the appender

+					if (appender) {

+						appender.storeCommandHistory(commandHistory);

+					}

+				}

+				currentCommandIndex = (expr == commandHistory[currentCommandIndex]) ? currentCommandIndex + 1 : commandHistory.length;

+				lastCommand = expr;

+			}

+			//]]>

+		</script>

+		<style type="text/css">

+			body {

+				background-color: white;

+				color: black;

+				padding: 0;

+				margin: 0;

+				font-family: tahoma, verdana, arial, helvetica, sans-serif;

+				overflow: hidden;

+			}

+

+			div#switchesContainer input {

+				margin-bottom: 0;

+			}

+

+			div.toolbar {

+				border-top: solid #ffffff 1px;

+				border-bottom: solid #aca899 1px;

+				background-color: #f1efe7;

+				padding: 3px 5px;

+				font-size: 68.75%;

+			}

+

+			div.toolbar, div#search input {

+				font-family: tahoma, verdana, arial, helvetica, sans-serif;

+			}

+

+			div.toolbar input.button {

+				padding: 0 5px;

+				font-size: 100%;

+			}

+

+			div.toolbar input.hidden {

+				display: none;

+			}

+

+			div#switches input#clearButton {

+				margin-left: 20px;

+			}

+

+			div#levels label {

+				font-weight: bold;

+			}

+

+			div#levels label, div#options label {

+				margin-right: 5px;

+			}

+

+			div#levels label#wrapLabel {

+				font-weight: normal;

+			}

+

+			div#search label {

+				margin-right: 10px;

+			}

+

+			div#search label.searchboxlabel {

+				margin-right: 0;

+			}

+

+			div#search input {

+				font-size: 100%;

+			}

+

+			div#search input.validregex {

+				color: green;

+			}

+

+			div#search input.invalidregex {

+				color: red;

+			}

+

+			div#search input.nomatches {

+				color: white;

+				background-color: #ff6666;

+			}

+

+			div#search input.nomatches {

+				color: white;

+				background-color: #ff6666;

+			}

+

+			div#searchNav {

+				display: none;

+			}

+

+			div#commandLine {

+				display: none;

+			}

+

+			div#commandLine input#command {

+				font-size: 100%;

+				font-family: Courier New, Courier;

+			}

+

+			div#commandLine input#evaluateButton {

+			}

+

+			*.greyedout {

+				color: gray !important;

+				border-color: gray !important;

+			}

+

+			*.greyedout *.alwaysenabled { color: black; }

+

+			*.unselectable {

+				-khtml-user-select: none;

+				-moz-user-select: none;

+				user-select: none;

+			}

+

+			div#log {

+				font-family: Courier New, Courier;

+				font-size: 75%;

+				width: 100%;

+				overflow: auto;

+				clear: both;

+				position: relative;

+			}

+

+			div.group {

+				border-color: #cccccc;

+				border-style: solid;

+				border-width: 1px 0 1px 1px;

+				overflow: visible;

+			}

+

+			div.oldIe div.group, div.oldIe div.group *, div.oldIe *.logentry {

+				height: 1%;

+			}

+

+			div.group div.groupheading span.expander {

+				border: solid black 1px;

+				font-family: Courier New, Courier;

+				font-size: 0.833em;

+				background-color: #eeeeee;

+				position: relative;

+				top: -1px;

+				color: black;

+				padding: 0 2px;

+				cursor: pointer;

+				cursor: hand;

+				height: 1%;

+			}

+

+			div.group div.groupcontent {

+				margin-left: 10px;

+				padding-bottom: 2px;

+				overflow: visible;

+			}

+

+			div.group div.expanded {

+				display: block;

+			}

+

+			div.group div.collapsed {

+				display: none;

+			}

+

+			*.logentry {

+				overflow: visible;

+				display: none;

+				white-space: pre;

+			}

+

+			span.pre {

+				white-space: pre;

+			}

+			

+			pre.unwrapped {

+				display: inline !important;

+			}

+

+			pre.unwrapped pre.pre, div.wrapped pre.pre {

+				display: inline;

+			}

+

+			div.wrapped pre.pre {

+				white-space: normal;

+			}

+

+			div.wrapped {

+				display: none;

+			}

+

+			body.searching *.logentry span.currentmatch {

+				color: white !important;

+				background-color: green !important;

+			}

+

+			body.searching div.searchhighlight *.logentry span.searchterm {

+				color: black;

+				background-color: yellow;

+			}

+

+			div.wrap *.logentry {

+				white-space: normal !important;

+				border-width: 0 0 1px 0;

+				border-color: #dddddd;

+				border-style: dotted;

+			}

+

+			div.wrap #log_wrapped, #log_unwrapped {

+				display: block;

+			}

+

+			div.wrap #log_unwrapped, #log_wrapped {

+				display: none;

+			}

+

+			div.wrap *.logentry span.pre {

+				overflow: visible;

+				white-space: normal;

+			}

+

+			div.wrap *.logentry pre.unwrapped {

+				display: none;

+			}

+

+			div.wrap *.logentry span.wrapped {

+				display: inline;

+			}

+

+			div.searchfilter *.searchnonmatch {

+				display: none !important;

+			}

+

+			div#log *.TRACE, label#label_TRACE {

+				color: #666666;

+			}

+

+			div#log *.DEBUG, label#label_DEBUG {

+				color: green;

+			}

+

+			div#log *.INFO, label#label_INFO {

+				color: #000099;

+			}

+

+			div#log *.WARN, label#label_WARN {

+				color: #999900;

+			}

+

+			div#log *.ERROR, label#label_ERROR {

+				color: red;

+			}

+

+			div#log *.FATAL, label#label_FATAL {

+				color: #660066;

+			}

+

+			div.TRACE#log *.TRACE,

+			div.DEBUG#log *.DEBUG,

+			div.INFO#log *.INFO,

+			div.WARN#log *.WARN,

+			div.ERROR#log *.ERROR,

+			div.FATAL#log *.FATAL {

+				display: block;

+			}

+

+			div#log div.separator {

+				background-color: #cccccc;

+				margin: 5px 0;

+				line-height: 1px;

+			}

+		</style>

+	</head>

+

+	<body id="body">

+		<div id="switchesContainer">

+			<div id="switches">

+				<div id="levels" class="toolbar">

+					Filters:

+					<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>

+					<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>

+					<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>

+					<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>

+					<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>

+					<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>

+					<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>

+				</div>

+				<div id="search" class="toolbar">

+					<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />

+					<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />

+					<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>

+					<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>

+					<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>

+					<div id="searchNav">

+						<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />

+						<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />

+						<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>

+						<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>

+					</div>

+				</div>

+				<div id="options" class="toolbar">

+					Options:

+					<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>

+					<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>

+					<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>

+					<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>

+					<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />

+					<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />

+					<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />

+				</div>

+			</div>

+		</div>

+		<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>

+		<div id="commandLine" class="toolbar">

+			<div id="commandLineContainer">

+				<input type="text" id="command" title="Enter a JavaScript command here and hit return or press 'Evaluate'" />

+				<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />

+			</div>

+		</div>

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/liteconsole.html b/planetstack/core/static/log4javascript-1.4.6/js/liteconsole.html
new file mode 100644
index 0000000..840a59b
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/liteconsole.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+<head>

+<title>log4javascript</title>

+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

+<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->

+<meta http-equiv="X-UA-Compatible" content="IE=7" />

+<script type="text/javascript">

+//<![CDATA[

+var loggingEnabled=true;var messagesBeforeDocLoaded=[];function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}

+function setLoggingEnabled(enable){loggingEnabled=enable;}

+function scrollToLatestEntry(){var l=getLogContainer();if(typeof l.scrollTop!="undefined"){var latestLogEntry=l.lastChild;if(latestLogEntry){l.scrollTop=l.scrollHeight;}}}

+function log(logLevel,formattedMessage){if(loggingEnabled){if(loaded){doLog(logLevel,formattedMessage);}else{messagesBeforeDocLoaded.push([logLevel,formattedMessage]);}}}

+function doLog(logLevel,formattedMessage){var logEntry=document.createElement("div");logEntry.appendChild(document.createTextNode(formattedMessage));logEntry.className="logentry "+logLevel.name;getLogContainer().appendChild(logEntry);scrollToLatestEntry();}

+function mainPageReloaded(){var separator=document.createElement("div");separator.className="separator";separator.innerHTML="&nbsp;";getLogContainer().appendChild(separator);}

+var loaded=false;var logLevels=["DEBUG","INFO","WARN","ERROR","FATAL"];window.onload=function(){setLogContainerHeight();toggleLoggingEnabled();for(var i=0;i<messagesBeforeDocLoaded.length;i++){doLog(messagesBeforeDocLoaded[i][0],messagesBeforeDocLoaded[i][1]);}

+messagesBeforeDocLoaded=[];loaded=true;setTimeout(setLogContainerHeight,20);};function getLogContainer(){return $("log");}

+function clearLog(){getLogContainer().innerHTML="";}

+function $(id){return document.getElementById(id);}

+function getWindowHeight(){if(window.innerHeight){return window.innerHeight;}else if(document.documentElement&&document.documentElement.clientHeight){return document.documentElement.clientHeight;}else if(document.body){return document.body.clientHeight;}

+return 0;}

+function getChromeHeight(){return $("toolbar").offsetHeight;}

+function setLogContainerHeight(){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";getLogContainer().style.height=""+

+Math.max(0,windowHeight-getChromeHeight())+"px";}

+window.onresize=function(){setLogContainerHeight();};

+//]]>

+</script>

+<style type="text/css">

+body{background-color:white;color:black;padding:0;margin:0;font-family:tahoma,verdana,arial,helvetica,sans-serif;overflow:hidden}div#toolbar{border-top:solid #ffffff 1px;border-bottom:solid #aca899 1px;background-color:#f1efe7;padding:3px 5px;font-size:68.75%}div#toolbar input.button{padding:0 5px;font-size:100%}div#log{font-family:Courier New,Courier;font-size:75%;width:100%;overflow:auto;clear:both}*.logentry{overflow:visible;white-space:pre}*.TRACE{color:#666666}*.DEBUG{color:green}*.INFO{color:#000099}*.WARN{color:#999900}*.ERROR{color:red}*.FATAL{color:#660066}div#log div.separator{background-color:#cccccc;margin:5px 0;line-height:1px}

+</style>

+</head>

+<body id="body">

+<div id="toolbar">

+Options:

+<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" class="stateful" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Enable logging</label>

+<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="stateful button" title="Clear all log messages"  />

+<input type="button" id="closeButton" value="Close" onclick="window.close()" class="stateful button" title="Close the window" />

+</div>

+<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>

+</body>

+</html>
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/js/liteconsole_uncompressed.html b/planetstack/core/static/log4javascript-1.4.6/js/liteconsole_uncompressed.html
new file mode 100644
index 0000000..df5275f
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/liteconsole_uncompressed.html
@@ -0,0 +1,194 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript</title>

+		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

+		<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->

+		<meta http-equiv="X-UA-Compatible" content="IE=7" />

+		<script type="text/javascript">

+			//<![CDATA[

+			var loggingEnabled = true;

+			var messagesBeforeDocLoaded = [];

+

+			function toggleLoggingEnabled() {

+				setLoggingEnabled($("enableLogging").checked);

+			}

+

+			function setLoggingEnabled(enable) {

+				loggingEnabled = enable;

+			}

+

+			function scrollToLatestEntry() {

+				var l = getLogContainer();

+				if (typeof l.scrollTop != "undefined") {

+					var latestLogEntry = l.lastChild;

+					if (latestLogEntry) {

+						l.scrollTop = l.scrollHeight;

+					}

+				}

+			}

+

+			function log(logLevel, formattedMessage) {

+				if (loggingEnabled) {

+					if (loaded) {

+						doLog(logLevel, formattedMessage);

+					} else {

+						messagesBeforeDocLoaded.push([logLevel, formattedMessage]);

+					}

+				}

+			}

+

+			function doLog(logLevel, formattedMessage) {

+				var logEntry = document.createElement("div");

+				logEntry.appendChild(document.createTextNode(formattedMessage));

+				logEntry.className = "logentry " + logLevel.name;

+				getLogContainer().appendChild(logEntry);

+				scrollToLatestEntry();

+			}

+

+			function mainPageReloaded() {

+				var separator = document.createElement("div");

+				separator.className = "separator";

+				separator.innerHTML = "&nbsp;";

+				getLogContainer().appendChild(separator);

+			}

+

+			var loaded = false;

+			var logLevels = ["DEBUG", "INFO", "WARN", "ERROR", "FATAL"];

+

+			window.onload = function() {

+				setLogContainerHeight();

+				toggleLoggingEnabled();

+				for (var i = 0; i < messagesBeforeDocLoaded.length; i++) {

+					doLog(messagesBeforeDocLoaded[i][0], messagesBeforeDocLoaded[i][1]);

+				}

+				messagesBeforeDocLoaded = [];

+				loaded = true;

+

+				// Workaround to make sure log div starts at the correct size

+				setTimeout(setLogContainerHeight, 20);

+			};

+

+			function getLogContainer() {

+				return $("log");

+			}

+

+			function clearLog() {

+				getLogContainer().innerHTML = "";

+			}

+

+			/* ------------------------------------------------------------------------- */

+

+			// Other utility functions

+

+			// Syntax borrowed from Prototype library

+			function $(id) {

+				return document.getElementById(id);

+			}

+

+			function getWindowHeight() {

+				if (window.innerHeight) {

+					return window.innerHeight;

+				} else if (document.documentElement && document.documentElement.clientHeight) {

+					return document.documentElement.clientHeight;

+				} else if (document.body) {

+					return document.body.clientHeight;

+				}

+				return 0;

+			}

+

+			function getChromeHeight() {

+				return $("toolbar").offsetHeight;

+			}

+

+			function setLogContainerHeight() {

+				var windowHeight = getWindowHeight();

+				$("body").style.height = getWindowHeight() + "px";

+				getLogContainer().style.height = "" +

+					Math.max(0, windowHeight - getChromeHeight()) + "px";

+			}

+

+			window.onresize = function() {

+				setLogContainerHeight();

+			};

+

+			//]]>

+		</script>

+		<style type="text/css">

+			body {

+				background-color: white;

+				color: black;

+				padding: 0;

+				margin: 0;

+				font-family: tahoma, verdana, arial, helvetica, sans-serif;

+				overflow: hidden;

+			}

+			

+			div#toolbar {

+				border-top: solid #ffffff 1px;

+				border-bottom: solid #aca899 1px;

+				background-color: #f1efe7;

+				padding: 3px 5px;

+				font-size: 68.75%;

+			}

+

+			div#toolbar input.button {

+				padding: 0 5px;

+				font-size: 100%;

+			}

+

+			div#log {

+				font-family: Courier New, Courier;

+				font-size: 75%;

+				width: 100%;

+				overflow: auto;

+				clear: both;

+			}

+

+			*.logentry {

+				overflow: visible;

+				white-space: pre;

+			}

+

+			*.TRACE {

+				color: #666666;

+			}

+

+			*.DEBUG {

+				color: green;

+			}

+

+			*.INFO {

+				color: #000099;

+			}

+

+			*.WARN {

+				color: #999900;

+			}

+

+			*.ERROR {

+				color: red;

+			}

+

+			*.FATAL {

+				color: #660066;

+			}

+

+			div#log div.separator {

+				background-color: #cccccc;

+				margin: 5px 0;

+				line-height: 1px;

+			}

+		</style>

+	</head>

+

+	<body id="body">

+		<div id="toolbar">

+			Options:

+			<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" class="stateful" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Enable logging</label>

+			<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="stateful button" title="Clear all log messages"  />

+			<input type="button" id="closeButton" value="Close" onclick="window.close()" class="stateful button" title="Close the window" />

+		</div>

+		<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>

+	</body>

+</html>
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/js/log4javascript.js b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript.js
new file mode 100644
index 0000000..042daa9
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript.js
@@ -0,0 +1,274 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}

+return this.length;};}

+if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}

+this.length=this.length-1;return firstItem;}};}

+if(!Array.prototype.splice){Array.prototype.splice=function(startIndex,deleteCount){var itemsAfterDeleted=this.slice(startIndex+deleteCount);var itemsDeleted=this.slice(startIndex,startIndex+deleteCount);this.length=startIndex;var argumentsArray=[];for(var i=0,len=arguments.length;i<len;i++){argumentsArray[i]=arguments[i];}

+var itemsToAppend=(argumentsArray.length>2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i<len;i++){this.push(itemsToAppend[i]);}

+return itemsDeleted;};}

+var log4javascript=(function(){function isUndefined(obj){return typeof obj=="undefined";}

+function EventSupport(){}

+EventSupport.prototype={eventTypes:[],eventListeners:{},setEventTypes:function(eventTypesParam){if(eventTypesParam instanceof Array){this.eventTypes=eventTypesParam;this.eventListeners={};for(var i=0,len=this.eventTypes.length;i<len;i++){this.eventListeners[this.eventTypes[i]]=[];}}else{handleError("log4javascript.EventSupport ["+this+"]: setEventTypes: eventTypes parameter must be an Array");}},addEventListener:function(eventType,listener){if(typeof listener=="function"){if(!array_contains(this.eventTypes,eventType)){handleError("log4javascript.EventSupport ["+this+"]: addEventListener: no event called '"+eventType+"'");}

+this.eventListeners[eventType].push(listener);}else{handleError("log4javascript.EventSupport ["+this+"]: addEventListener: listener must be a function");}},removeEventListener:function(eventType,listener){if(typeof listener=="function"){if(!array_contains(this.eventTypes,eventType)){handleError("log4javascript.EventSupport ["+this+"]: removeEventListener: no event called '"+eventType+"'");}

+array_remove(this.eventListeners[eventType],listener);}else{handleError("log4javascript.EventSupport ["+this+"]: removeEventListener: listener must be a function");}},dispatchEvent:function(eventType,eventArgs){if(array_contains(this.eventTypes,eventType)){var listeners=this.eventListeners[eventType];for(var i=0,len=listeners.length;i<len;i++){listeners[i](this,eventType,eventArgs);}}else{handleError("log4javascript.EventSupport ["+this+"]: dispatchEvent: no event called '"+eventType+"'");}}};var applicationStartDate=new Date();var uniqueId="log4javascript_"+applicationStartDate.getTime()+"_"+

+Math.floor(Math.random()*100000000);var emptyFunction=function(){};var newLine="\r\n";var pageLoaded=false;function Log4JavaScript(){}

+Log4JavaScript.prototype=new EventSupport();log4javascript=new Log4JavaScript();log4javascript.version="1.4.6";log4javascript.edition="log4javascript";function toStr(obj){if(obj&&obj.toString){return obj.toString();}else{return String(obj);}}

+function getExceptionMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}else{return toStr(ex);}}

+function getUrlFileName(url){var lastSlashIndex=Math.max(url.lastIndexOf("/"),url.lastIndexOf("\\"));return url.substr(lastSlashIndex+1);}

+function getExceptionStringRep(ex){if(ex){var exStr="Exception: "+getExceptionMessage(ex);try{if(ex.lineNumber){exStr+=" on line number "+ex.lineNumber;}

+if(ex.fileName){exStr+=" in file "+getUrlFileName(ex.fileName);}}catch(localEx){logLog.warn("Unable to obtain file and line information for error");}

+if(showStackTraces&&ex.stack){exStr+=newLine+"Stack trace:"+newLine+ex.stack;}

+return exStr;}

+return null;}

+function bool(obj){return Boolean(obj);}

+function trim(str){return str.replace(/^\s+/,"").replace(/\s+$/,"");}

+function splitIntoLines(text){var text2=text.replace(/\r\n/g,"\n").replace(/\r/g,"\n");return text2.split("\n");}

+var urlEncode=(typeof window.encodeURIComponent!="undefined")?function(str){return encodeURIComponent(str);}:function(str){return escape(str).replace(/\+/g,"%2B").replace(/"/g,"%22").replace(/'/g,"%27").replace(/\//g,"%2F").replace(/=/g,"%3D");};var urlDecode=(typeof window.decodeURIComponent!="undefined")?function(str){return decodeURIComponent(str);}:function(str){return unescape(str).replace(/%2B/g,"+").replace(/%22/g,"\"").replace(/%27/g,"'").replace(/%2F/g,"/").replace(/%3D/g,"=");};function array_remove(arr,val){var index=-1;for(var i=0,len=arr.length;i<len;i++){if(arr[i]===val){index=i;break;}}

+if(index>=0){arr.splice(index,1);return true;}else{return false;}}

+function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}

+return false;}

+function extractBooleanFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return bool(param);}}

+function extractStringFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return String(param);}}

+function extractIntFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{try{var value=parseInt(param,10);return isNaN(value)?defaultValue:value;}catch(ex){logLog.warn("Invalid int param "+param,ex);return defaultValue;}}}

+function extractFunctionFromParam(param,defaultValue){if(typeof param=="function"){return param;}else{return defaultValue;}}

+function isError(err){return(err instanceof Error);}

+if(!Function.prototype.apply){Function.prototype.apply=function(obj,args){var methodName="__apply__";if(typeof obj[methodName]!="undefined"){methodName+=String(Math.random()).substr(2);}

+obj[methodName]=this;var argsStrings=[];for(var i=0,len=args.length;i<len;i++){argsStrings[i]="args["+i+"]";}

+var script="obj."+methodName+"("+argsStrings.join(",")+")";var returnValue=eval(script);delete obj[methodName];return returnValue;};}

+if(!Function.prototype.call){Function.prototype.call=function(obj){var args=[];for(var i=1,len=arguments.length;i<len;i++){args[i-1]=arguments[i];}

+return this.apply(obj,args);};}

+function getListenersPropertyName(eventName){return"__log4javascript_listeners__"+eventName;}

+function addEvent(node,eventName,listener,useCapture,win){win=win?win:window;if(node.addEventListener){node.addEventListener(eventName,listener,useCapture);}else if(node.attachEvent){node.attachEvent("on"+eventName,listener);}else{var propertyName=getListenersPropertyName(eventName);if(!node[propertyName]){node[propertyName]=[];node["on"+eventName]=function(evt){evt=getEvent(evt,win);var listenersPropertyName=getListenersPropertyName(eventName);var listeners=this[listenersPropertyName].concat([]);var currentListener;while((currentListener=listeners.shift())){currentListener.call(this,evt);}};}

+node[propertyName].push(listener);}}

+function removeEvent(node,eventName,listener,useCapture){if(node.removeEventListener){node.removeEventListener(eventName,listener,useCapture);}else if(node.detachEvent){node.detachEvent("on"+eventName,listener);}else{var propertyName=getListenersPropertyName(eventName);if(node[propertyName]){array_remove(node[propertyName],listener);}}}

+function getEvent(evt,win){win=win?win:window;return evt?evt:win.event;}

+function stopEventPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}

+evt.returnValue=false;}

+var logLog={quietMode:false,debugMessages:[],setQuietMode:function(quietMode){this.quietMode=bool(quietMode);},numberOfErrors:0,alertAllErrors:false,setAlertAllErrors:function(alertAllErrors){this.alertAllErrors=alertAllErrors;},debug:function(message){this.debugMessages.push(message);},displayDebug:function(){alert(this.debugMessages.join(newLine));},warn:function(message,exception){},error:function(message,exception){if(++this.numberOfErrors==1||this.alertAllErrors){if(!this.quietMode){var alertMessage="log4javascript error: "+message;if(exception){alertMessage+=newLine+newLine+"Original error: "+getExceptionStringRep(exception);}

+alert(alertMessage);}}}};log4javascript.logLog=logLog;log4javascript.setEventTypes(["load","error"]);function handleError(message,exception){logLog.error(message,exception);log4javascript.dispatchEvent("error",{"message":message,"exception":exception});}

+log4javascript.handleError=handleError;var enabled=!((typeof log4javascript_disabled!="undefined")&&log4javascript_disabled);log4javascript.setEnabled=function(enable){enabled=bool(enable);};log4javascript.isEnabled=function(){return enabled;};var useTimeStampsInMilliseconds=true;log4javascript.setTimeStampsInMilliseconds=function(timeStampsInMilliseconds){useTimeStampsInMilliseconds=bool(timeStampsInMilliseconds);};log4javascript.isTimeStampsInMilliseconds=function(){return useTimeStampsInMilliseconds;};log4javascript.evalInScope=function(expr){return eval(expr);};var showStackTraces=false;log4javascript.setShowStackTraces=function(show){showStackTraces=bool(show);};var Level=function(level,name){this.level=level;this.name=name;};Level.prototype={toString:function(){return this.name;},equals:function(level){return this.level==level.level;},isGreaterOrEqual:function(level){return this.level>=level.level;}};Level.ALL=new Level(Number.MIN_VALUE,"ALL");Level.TRACE=new Level(10000,"TRACE");Level.DEBUG=new Level(20000,"DEBUG");Level.INFO=new Level(30000,"INFO");Level.WARN=new Level(40000,"WARN");Level.ERROR=new Level(50000,"ERROR");Level.FATAL=new Level(60000,"FATAL");Level.OFF=new Level(Number.MAX_VALUE,"OFF");log4javascript.Level=Level;function Timer(name,level){this.name=name;this.level=isUndefined(level)?Level.INFO:level;this.start=new Date();}

+Timer.prototype.getElapsedTime=function(){return new Date().getTime()-this.start.getTime();};var anonymousLoggerName="[anonymous]";var defaultLoggerName="[default]";var nullLoggerName="[null]";var rootLoggerName="root";function Logger(name){this.name=name;this.parent=null;this.children=[];var appenders=[];var loggerLevel=null;var isRoot=(this.name===rootLoggerName);var isNull=(this.name===nullLoggerName);var appenderCache=null;var appenderCacheInvalidated=false;this.addChild=function(childLogger){this.children.push(childLogger);childLogger.parent=this;childLogger.invalidateAppenderCache();};var additive=true;this.getAdditivity=function(){return additive;};this.setAdditivity=function(additivity){var valueChanged=(additive!=additivity);additive=additivity;if(valueChanged){this.invalidateAppenderCache();}};this.addAppender=function(appender){if(isNull){handleError("Logger.addAppender: you may not add an appender to the null logger");}else{if(appender instanceof log4javascript.Appender){if(!array_contains(appenders,appender)){appenders.push(appender);appender.setAddedToLogger(this);this.invalidateAppenderCache();}}else{handleError("Logger.addAppender: appender supplied ('"+

+toStr(appender)+"') is not a subclass of Appender");}}};this.removeAppender=function(appender){array_remove(appenders,appender);appender.setRemovedFromLogger(this);this.invalidateAppenderCache();};this.removeAllAppenders=function(){var appenderCount=appenders.length;if(appenderCount>0){for(var i=0;i<appenderCount;i++){appenders[i].setRemovedFromLogger(this);}

+appenders.length=0;this.invalidateAppenderCache();}};this.getEffectiveAppenders=function(){if(appenderCache===null||appenderCacheInvalidated){var parentEffectiveAppenders=(isRoot||!this.getAdditivity())?[]:this.parent.getEffectiveAppenders();appenderCache=parentEffectiveAppenders.concat(appenders);appenderCacheInvalidated=false;}

+return appenderCache;};this.invalidateAppenderCache=function(){appenderCacheInvalidated=true;for(var i=0,len=this.children.length;i<len;i++){this.children[i].invalidateAppenderCache();}};this.log=function(level,params){if(enabled&&level.isGreaterOrEqual(this.getEffectiveLevel())){var exception;var finalParamIndex=params.length-1;var lastParam=params[finalParamIndex];if(params.length>1&&isError(lastParam)){exception=lastParam;finalParamIndex--;}

+var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];}

+var loggingEvent=new LoggingEvent(this,new Date(),level,messages,exception);this.callAppenders(loggingEvent);}};this.callAppenders=function(loggingEvent){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].doAppend(loggingEvent);}};this.setLevel=function(level){if(isRoot&&level===null){handleError("Logger.setLevel: you cannot set the level of the root logger to null");}else if(level instanceof Level){loggerLevel=level;}else{handleError("Logger.setLevel: level supplied to logger "+

+this.name+" is not an instance of log4javascript.Level");}};this.getLevel=function(){return loggerLevel;};this.getEffectiveLevel=function(){for(var logger=this;logger!==null;logger=logger.parent){var level=logger.getLevel();if(level!==null){return level;}}};this.group=function(name,initiallyExpanded){if(enabled){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].group(name,initiallyExpanded);}}};this.groupEnd=function(){if(enabled){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].groupEnd();}}};var timers={};this.time=function(name,level){if(enabled){if(isUndefined(name)){handleError("Logger.time: a name for the timer must be supplied");}else if(level&&!(level instanceof Level)){handleError("Logger.time: level supplied to timer "+

+name+" is not an instance of log4javascript.Level");}else{timers[name]=new Timer(name,level);}}};this.timeEnd=function(name){if(enabled){if(isUndefined(name)){handleError("Logger.timeEnd: a name for the timer must be supplied");}else if(timers[name]){var timer=timers[name];var milliseconds=timer.getElapsedTime();this.log(timer.level,["Timer "+toStr(name)+" completed in "+milliseconds+"ms"]);delete timers[name];}else{logLog.warn("Logger.timeEnd: no timer found with name "+name);}}};this.assert=function(expr){if(enabled&&!expr){var args=[];for(var i=1,len=arguments.length;i<len;i++){args.push(arguments[i]);}

+args=(args.length>0)?args:["Assertion Failure"];args.push(newLine);args.push(expr);this.log(Level.ERROR,args);}};this.toString=function(){return"Logger["+this.name+"]";};}

+Logger.prototype={trace:function(){this.log(Level.TRACE,arguments);},debug:function(){this.log(Level.DEBUG,arguments);},info:function(){this.log(Level.INFO,arguments);},warn:function(){this.log(Level.WARN,arguments);},error:function(){this.log(Level.ERROR,arguments);},fatal:function(){this.log(Level.FATAL,arguments);},isEnabledFor:function(level){return level.isGreaterOrEqual(this.getEffectiveLevel());},isTraceEnabled:function(){return this.isEnabledFor(Level.TRACE);},isDebugEnabled:function(){return this.isEnabledFor(Level.DEBUG);},isInfoEnabled:function(){return this.isEnabledFor(Level.INFO);},isWarnEnabled:function(){return this.isEnabledFor(Level.WARN);},isErrorEnabled:function(){return this.isEnabledFor(Level.ERROR);},isFatalEnabled:function(){return this.isEnabledFor(Level.FATAL);}};Logger.prototype.trace.isEntryPoint=true;Logger.prototype.debug.isEntryPoint=true;Logger.prototype.info.isEntryPoint=true;Logger.prototype.warn.isEntryPoint=true;Logger.prototype.error.isEntryPoint=true;Logger.prototype.fatal.isEntryPoint=true;var loggers={};var loggerNames=[];var ROOT_LOGGER_DEFAULT_LEVEL=Level.DEBUG;var rootLogger=new Logger(rootLoggerName);rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);log4javascript.getRootLogger=function(){return rootLogger;};log4javascript.getLogger=function(loggerName){if(!(typeof loggerName=="string")){loggerName=anonymousLoggerName;logLog.warn("log4javascript.getLogger: non-string logger name "+

+toStr(loggerName)+" supplied, returning anonymous logger");}

+if(loggerName==rootLoggerName){handleError("log4javascript.getLogger: root logger may not be obtained by name");}

+if(!loggers[loggerName]){var logger=new Logger(loggerName);loggers[loggerName]=logger;loggerNames.push(loggerName);var lastDotIndex=loggerName.lastIndexOf(".");var parentLogger;if(lastDotIndex>-1){var parentLoggerName=loggerName.substring(0,lastDotIndex);parentLogger=log4javascript.getLogger(parentLoggerName);}else{parentLogger=rootLogger;}

+parentLogger.addChild(logger);}

+return loggers[loggerName];};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=log4javascript.getLogger(defaultLoggerName);var a=new log4javascript.PopUpAppender();defaultLogger.addAppender(a);}

+return defaultLogger;};var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger(nullLoggerName);nullLogger.setLevel(Level.OFF);}

+return nullLogger;};log4javascript.resetConfiguration=function(){rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);loggers={};};var LoggingEvent=function(logger,timeStamp,level,messages,exception){this.logger=logger;this.timeStamp=timeStamp;this.timeStampInMilliseconds=timeStamp.getTime();this.timeStampInSeconds=Math.floor(this.timeStampInMilliseconds/1000);this.milliseconds=this.timeStamp.getMilliseconds();this.level=level;this.messages=messages;this.exception=exception;};LoggingEvent.prototype={getThrowableStrRep:function(){return this.exception?getExceptionStringRep(this.exception):"";},getCombinedMessages:function(){return(this.messages.length==1)?this.messages[0]:this.messages.join(newLine);},toString:function(){return"LoggingEvent["+this.level+"]";}};log4javascript.LoggingEvent=LoggingEvent;var Layout=function(){};Layout.prototype={defaults:{loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url"},loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url",batchHeader:"",batchFooter:"",batchSeparator:"",returnsPostData:false,overrideTimeStampsSetting:false,useTimeStampsInMilliseconds:null,format:function(){handleError("Layout.format: layout supplied has no format() method");},ignoresThrowable:function(){handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");},getContentType:function(){return"text/plain";},allowBatching:function(){return true;},setTimeStampsInMilliseconds:function(timeStampsInMilliseconds){this.overrideTimeStampsSetting=true;this.useTimeStampsInMilliseconds=bool(timeStampsInMilliseconds);},isTimeStampsInMilliseconds:function(){return this.overrideTimeStampsSetting?this.useTimeStampsInMilliseconds:useTimeStampsInMilliseconds;},getTimeStampValue:function(loggingEvent){return this.isTimeStampsInMilliseconds()?loggingEvent.timeStampInMilliseconds:loggingEvent.timeStampInSeconds;},getDataValues:function(loggingEvent,combineMessages){var dataValues=[[this.loggerKey,loggingEvent.logger.name],[this.timeStampKey,this.getTimeStampValue(loggingEvent)],[this.levelKey,loggingEvent.level.name],[this.urlKey,window.location.href],[this.messageKey,combineMessages?loggingEvent.getCombinedMessages():loggingEvent.messages]];if(!this.isTimeStampsInMilliseconds()){dataValues.push([this.millisecondsKey,loggingEvent.milliseconds]);}

+if(loggingEvent.exception){dataValues.push([this.exceptionKey,getExceptionStringRep(loggingEvent.exception)]);}

+if(this.hasCustomFields()){for(var i=0,len=this.customFields.length;i<len;i++){var val=this.customFields[i].value;if(typeof val==="function"){val=val(this,loggingEvent);}

+dataValues.push([this.customFields[i].name,val]);}}

+return dataValues;},setKeys:function(loggerKey,timeStampKey,levelKey,messageKey,exceptionKey,urlKey,millisecondsKey){this.loggerKey=extractStringFromParam(loggerKey,this.defaults.loggerKey);this.timeStampKey=extractStringFromParam(timeStampKey,this.defaults.timeStampKey);this.levelKey=extractStringFromParam(levelKey,this.defaults.levelKey);this.messageKey=extractStringFromParam(messageKey,this.defaults.messageKey);this.exceptionKey=extractStringFromParam(exceptionKey,this.defaults.exceptionKey);this.urlKey=extractStringFromParam(urlKey,this.defaults.urlKey);this.millisecondsKey=extractStringFromParam(millisecondsKey,this.defaults.millisecondsKey);},setCustomField:function(name,value){var fieldUpdated=false;for(var i=0,len=this.customFields.length;i<len;i++){if(this.customFields[i].name===name){this.customFields[i].value=value;fieldUpdated=true;}}

+if(!fieldUpdated){this.customFields.push({"name":name,"value":value});}},hasCustomFields:function(){return(this.customFields.length>0);},toString:function(){handleError("Layout.toString: all layouts must override this method");}};log4javascript.Layout=Layout;var Appender=function(){};Appender.prototype=new EventSupport();Appender.prototype.layout=new PatternLayout();Appender.prototype.threshold=Level.ALL;Appender.prototype.loggers=[];Appender.prototype.doAppend=function(loggingEvent){if(enabled&&loggingEvent.level.level>=this.threshold.level){this.append(loggingEvent);}};Appender.prototype.append=function(loggingEvent){};Appender.prototype.setLayout=function(layout){if(layout instanceof Layout){this.layout=layout;}else{handleError("Appender.setLayout: layout supplied to "+

+this.toString()+" is not a subclass of Layout");}};Appender.prototype.getLayout=function(){return this.layout;};Appender.prototype.setThreshold=function(threshold){if(threshold instanceof Level){this.threshold=threshold;}else{handleError("Appender.setThreshold: threshold supplied to "+

+this.toString()+" is not a subclass of Level");}};Appender.prototype.getThreshold=function(){return this.threshold;};Appender.prototype.setAddedToLogger=function(logger){this.loggers.push(logger);};Appender.prototype.setRemovedFromLogger=function(logger){array_remove(this.loggers,logger);};Appender.prototype.group=emptyFunction;Appender.prototype.groupEnd=emptyFunction;Appender.prototype.toString=function(){handleError("Appender.toString: all appenders must override this method");};log4javascript.Appender=Appender;function SimpleLayout(){this.customFields=[];}

+SimpleLayout.prototype=new Layout();SimpleLayout.prototype.format=function(loggingEvent){return loggingEvent.level.name+" - "+loggingEvent.getCombinedMessages();};SimpleLayout.prototype.ignoresThrowable=function(){return true;};SimpleLayout.prototype.toString=function(){return"SimpleLayout";};log4javascript.SimpleLayout=SimpleLayout;function NullLayout(){this.customFields=[];}

+NullLayout.prototype=new Layout();NullLayout.prototype.format=function(loggingEvent){return loggingEvent.messages;};NullLayout.prototype.ignoresThrowable=function(){return true;};NullLayout.prototype.toString=function(){return"NullLayout";};log4javascript.NullLayout=NullLayout;function XmlLayout(combineMessages){this.combineMessages=extractBooleanFromParam(combineMessages,true);this.customFields=[];}

+XmlLayout.prototype=new Layout();XmlLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};XmlLayout.prototype.getContentType=function(){return"text/xml";};XmlLayout.prototype.escapeCdata=function(str){return str.replace(/\]\]>/,"]]>]]&gt;<![CDATA[");};XmlLayout.prototype.format=function(loggingEvent){var layout=this;var i,len;function formatMessage(message){message=(typeof message==="string")?message:toStr(message);return"<log4javascript:message><![CDATA["+

+layout.escapeCdata(message)+"]]></log4javascript:message>";}

+var str="<log4javascript:event logger=\""+loggingEvent.logger.name+"\" timestamp=\""+this.getTimeStampValue(loggingEvent)+"\"";if(!this.isTimeStampsInMilliseconds()){str+=" milliseconds=\""+loggingEvent.milliseconds+"\"";}

+str+=" level=\""+loggingEvent.level.name+"\">"+newLine;if(this.combineMessages){str+=formatMessage(loggingEvent.getCombinedMessages());}else{str+="<log4javascript:messages>"+newLine;for(i=0,len=loggingEvent.messages.length;i<len;i++){str+=formatMessage(loggingEvent.messages[i])+newLine;}

+str+="</log4javascript:messages>"+newLine;}

+if(this.hasCustomFields()){for(i=0,len=this.customFields.length;i<len;i++){str+="<log4javascript:customfield name=\""+

+this.customFields[i].name+"\"><![CDATA["+

+this.customFields[i].value.toString()+"]]></log4javascript:customfield>"+newLine;}}

+if(loggingEvent.exception){str+="<log4javascript:exception><![CDATA["+

+getExceptionStringRep(loggingEvent.exception)+"]]></log4javascript:exception>"+newLine;}

+str+="</log4javascript:event>"+newLine+newLine;return str;};XmlLayout.prototype.ignoresThrowable=function(){return false;};XmlLayout.prototype.toString=function(){return"XmlLayout";};log4javascript.XmlLayout=XmlLayout;function escapeNewLines(str){return str.replace(/\r\n|\r|\n/g,"\\r\\n");}

+function JsonLayout(readable,combineMessages){this.readable=extractBooleanFromParam(readable,false);this.combineMessages=extractBooleanFromParam(combineMessages,true);this.batchHeader=this.readable?"["+newLine:"[";this.batchFooter=this.readable?"]"+newLine:"]";this.batchSeparator=this.readable?","+newLine:",";this.setKeys();this.colon=this.readable?": ":":";this.tab=this.readable?"\t":"";this.lineBreak=this.readable?newLine:"";this.customFields=[];}

+JsonLayout.prototype=new Layout();JsonLayout.prototype.isReadable=function(){return this.readable;};JsonLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};JsonLayout.prototype.format=function(loggingEvent){var layout=this;var dataValues=this.getDataValues(loggingEvent,this.combineMessages);var str="{"+this.lineBreak;var i,len;function formatValue(val,prefix,expand){var formattedValue;var valType=typeof val;if(val instanceof Date){formattedValue=String(val.getTime());}else if(expand&&(val instanceof Array)){formattedValue="["+layout.lineBreak;for(var i=0,len=val.length;i<len;i++){var childPrefix=prefix+layout.tab;formattedValue+=childPrefix+formatValue(val[i],childPrefix,false);if(i<val.length-1){formattedValue+=",";}

+formattedValue+=layout.lineBreak;}

+formattedValue+=prefix+"]";}else if(valType!=="number"&&valType!=="boolean"){formattedValue="\""+escapeNewLines(toStr(val).replace(/\"/g,"\\\""))+"\"";}else{formattedValue=val;}

+return formattedValue;}

+for(i=0,len=dataValues.length-1;i<=len;i++){str+=this.tab+"\""+dataValues[i][0]+"\""+this.colon+formatValue(dataValues[i][1],this.tab,true);if(i<len){str+=",";}

+str+=this.lineBreak;}

+str+="}"+this.lineBreak;return str;};JsonLayout.prototype.ignoresThrowable=function(){return false;};JsonLayout.prototype.toString=function(){return"JsonLayout";};JsonLayout.prototype.getContentType=function(){return"application/json";};log4javascript.JsonLayout=JsonLayout;function HttpPostDataLayout(){this.setKeys();this.customFields=[];this.returnsPostData=true;}

+HttpPostDataLayout.prototype=new Layout();HttpPostDataLayout.prototype.allowBatching=function(){return false;};HttpPostDataLayout.prototype.format=function(loggingEvent){var dataValues=this.getDataValues(loggingEvent);var queryBits=[];for(var i=0,len=dataValues.length;i<len;i++){var val=(dataValues[i][1]instanceof Date)?String(dataValues[i][1].getTime()):dataValues[i][1];queryBits.push(urlEncode(dataValues[i][0])+"="+urlEncode(val));}

+return queryBits.join("&");};HttpPostDataLayout.prototype.ignoresThrowable=function(loggingEvent){return false;};HttpPostDataLayout.prototype.toString=function(){return"HttpPostDataLayout";};log4javascript.HttpPostDataLayout=HttpPostDataLayout;function formatObjectExpansion(obj,depth,indentation){var objectsExpanded=[];function doFormat(obj,depth,indentation){var i,j,len,childDepth,childIndentation,childLines,expansion,childExpansion;if(!indentation){indentation="";}

+function formatString(text){var lines=splitIntoLines(text);for(var j=1,jLen=lines.length;j<jLen;j++){lines[j]=indentation+lines[j];}

+return lines.join(newLine);}

+if(obj===null){return"null";}else if(typeof obj=="undefined"){return"undefined";}else if(typeof obj=="string"){return formatString(obj);}else if(typeof obj=="object"&&array_contains(objectsExpanded,obj)){try{expansion=toStr(obj);}catch(ex){expansion="Error formatting property. Details: "+getExceptionStringRep(ex);}

+return expansion+" [already expanded]";}else if((obj instanceof Array)&&depth>0){objectsExpanded.push(obj);expansion="["+newLine;childDepth=depth-1;childIndentation=indentation+"  ";childLines=[];for(i=0,len=obj.length;i<len;i++){try{childExpansion=doFormat(obj[i],childDepth,childIndentation);childLines.push(childIndentation+childExpansion);}catch(ex){childLines.push(childIndentation+"Error formatting array member. Details: "+

+getExceptionStringRep(ex)+"");}}

+expansion+=childLines.join(","+newLine)+newLine+indentation+"]";return expansion;}else if(Object.prototype.toString.call(obj)=="[object Date]"){return obj.toString();}else if(typeof obj=="object"&&depth>0){objectsExpanded.push(obj);expansion="{"+newLine;childDepth=depth-1;childIndentation=indentation+"  ";childLines=[];for(i in obj){try{childExpansion=doFormat(obj[i],childDepth,childIndentation);childLines.push(childIndentation+i+": "+childExpansion);}catch(ex){childLines.push(childIndentation+i+": Error formatting property. Details: "+

+getExceptionStringRep(ex));}}

+expansion+=childLines.join(","+newLine)+newLine+indentation+"}";return expansion;}else{return formatString(toStr(obj));}}

+return doFormat(obj,depth,indentation);}

+var SimpleDateFormat;(function(){var regex=/('[^']*')|(G+|y+|M+|w+|W+|D+|d+|F+|E+|a+|H+|k+|K+|h+|m+|s+|S+|Z+)|([a-zA-Z]+)|([^a-zA-Z']+)/;var monthNames=["January","February","March","April","May","June","July","August","September","October","November","December"];var dayNames=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var TEXT2=0,TEXT3=1,NUMBER=2,YEAR=3,MONTH=4,TIMEZONE=5;var types={G:TEXT2,y:YEAR,M:MONTH,w:NUMBER,W:NUMBER,D:NUMBER,d:NUMBER,F:NUMBER,E:TEXT3,a:TEXT2,H:NUMBER,k:NUMBER,K:NUMBER,h:NUMBER,m:NUMBER,s:NUMBER,S:NUMBER,Z:TIMEZONE};var ONE_DAY=24*60*60*1000;var ONE_WEEK=7*ONE_DAY;var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK=1;var newDateAtMidnight=function(year,month,day){var d=new Date(year,month,day,0,0,0);d.setMilliseconds(0);return d;};Date.prototype.getDifference=function(date){return this.getTime()-date.getTime();};Date.prototype.isBefore=function(d){return this.getTime()<d.getTime();};Date.prototype.getUTCTime=function(){return Date.UTC(this.getFullYear(),this.getMonth(),this.getDate(),this.getHours(),this.getMinutes(),this.getSeconds(),this.getMilliseconds());};Date.prototype.getTimeSince=function(d){return this.getUTCTime()-d.getUTCTime();};Date.prototype.getPreviousSunday=function(){var midday=new Date(this.getFullYear(),this.getMonth(),this.getDate(),12,0,0);var previousSunday=new Date(midday.getTime()-this.getDay()*ONE_DAY);return newDateAtMidnight(previousSunday.getFullYear(),previousSunday.getMonth(),previousSunday.getDate());};Date.prototype.getWeekInYear=function(minimalDaysInFirstWeek){if(isUndefined(this.minimalDaysInFirstWeek)){minimalDaysInFirstWeek=DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;}

+var previousSunday=this.getPreviousSunday();var startOfYear=newDateAtMidnight(this.getFullYear(),0,1);var numberOfSundays=previousSunday.isBefore(startOfYear)?0:1+Math.floor(previousSunday.getTimeSince(startOfYear)/ONE_WEEK);var numberOfDaysInFirstWeek=7-startOfYear.getDay();var weekInYear=numberOfSundays;if(numberOfDaysInFirstWeek<minimalDaysInFirstWeek){weekInYear--;}

+return weekInYear;};Date.prototype.getWeekInMonth=function(minimalDaysInFirstWeek){if(isUndefined(this.minimalDaysInFirstWeek)){minimalDaysInFirstWeek=DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;}

+var previousSunday=this.getPreviousSunday();var startOfMonth=newDateAtMidnight(this.getFullYear(),this.getMonth(),1);var numberOfSundays=previousSunday.isBefore(startOfMonth)?0:1+Math.floor(previousSunday.getTimeSince(startOfMonth)/ONE_WEEK);var numberOfDaysInFirstWeek=7-startOfMonth.getDay();var weekInMonth=numberOfSundays;if(numberOfDaysInFirstWeek>=minimalDaysInFirstWeek){weekInMonth++;}

+return weekInMonth;};Date.prototype.getDayInYear=function(){var startOfYear=newDateAtMidnight(this.getFullYear(),0,1);return 1+Math.floor(this.getTimeSince(startOfYear)/ONE_DAY);};SimpleDateFormat=function(formatString){this.formatString=formatString;};SimpleDateFormat.prototype.setMinimalDaysInFirstWeek=function(days){this.minimalDaysInFirstWeek=days;};SimpleDateFormat.prototype.getMinimalDaysInFirstWeek=function(){return isUndefined(this.minimalDaysInFirstWeek)?DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK:this.minimalDaysInFirstWeek;};var padWithZeroes=function(str,len){while(str.length<len){str="0"+str;}

+return str;};var formatText=function(data,numberOfLetters,minLength){return(numberOfLetters>=4)?data:data.substr(0,Math.max(minLength,numberOfLetters));};var formatNumber=function(data,numberOfLetters){var dataString=""+data;return padWithZeroes(dataString,numberOfLetters);};SimpleDateFormat.prototype.format=function(date){var formattedString="";var result;var searchString=this.formatString;while((result=regex.exec(searchString))){var quotedString=result[1];var patternLetters=result[2];var otherLetters=result[3];var otherCharacters=result[4];if(quotedString){if(quotedString=="''"){formattedString+="'";}else{formattedString+=quotedString.substring(1,quotedString.length-1);}}else if(otherLetters){}else if(otherCharacters){formattedString+=otherCharacters;}else if(patternLetters){var patternLetter=patternLetters.charAt(0);var numberOfLetters=patternLetters.length;var rawData="";switch(patternLetter){case"G":rawData="AD";break;case"y":rawData=date.getFullYear();break;case"M":rawData=date.getMonth();break;case"w":rawData=date.getWeekInYear(this.getMinimalDaysInFirstWeek());break;case"W":rawData=date.getWeekInMonth(this.getMinimalDaysInFirstWeek());break;case"D":rawData=date.getDayInYear();break;case"d":rawData=date.getDate();break;case"F":rawData=1+Math.floor((date.getDate()-1)/7);break;case"E":rawData=dayNames[date.getDay()];break;case"a":rawData=(date.getHours()>=12)?"PM":"AM";break;case"H":rawData=date.getHours();break;case"k":rawData=date.getHours()||24;break;case"K":rawData=date.getHours()%12;break;case"h":rawData=(date.getHours()%12)||12;break;case"m":rawData=date.getMinutes();break;case"s":rawData=date.getSeconds();break;case"S":rawData=date.getMilliseconds();break;case"Z":rawData=date.getTimezoneOffset();break;}

+switch(types[patternLetter]){case TEXT2:formattedString+=formatText(rawData,numberOfLetters,2);break;case TEXT3:formattedString+=formatText(rawData,numberOfLetters,3);break;case NUMBER:formattedString+=formatNumber(rawData,numberOfLetters);break;case YEAR:if(numberOfLetters<=3){var dataString=""+rawData;formattedString+=dataString.substr(2,2);}else{formattedString+=formatNumber(rawData,numberOfLetters);}

+break;case MONTH:if(numberOfLetters>=3){formattedString+=formatText(monthNames[rawData],numberOfLetters,numberOfLetters);}else{formattedString+=formatNumber(rawData+1,numberOfLetters);}

+break;case TIMEZONE:var isPositive=(rawData>0);var prefix=isPositive?"-":"+";var absData=Math.abs(rawData);var hours=""+Math.floor(absData/60);hours=padWithZeroes(hours,2);var minutes=""+(absData%60);minutes=padWithZeroes(minutes,2);formattedString+=prefix+hours+minutes;break;}}

+searchString=searchString.substr(result.index+result[0].length);}

+return formattedString;};})();log4javascript.SimpleDateFormat=SimpleDateFormat;function PatternLayout(pattern){if(pattern){this.pattern=pattern;}else{this.pattern=PatternLayout.DEFAULT_CONVERSION_PATTERN;}

+this.customFields=[];}

+PatternLayout.TTCC_CONVERSION_PATTERN="%r %p %c - %m%n";PatternLayout.DEFAULT_CONVERSION_PATTERN="%m%n";PatternLayout.ISO8601_DATEFORMAT="yyyy-MM-dd HH:mm:ss,SSS";PatternLayout.DATETIME_DATEFORMAT="dd MMM yyyy HH:mm:ss,SSS";PatternLayout.ABSOLUTETIME_DATEFORMAT="HH:mm:ss,SSS";PatternLayout.prototype=new Layout();PatternLayout.prototype.format=function(loggingEvent){var regex=/%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;var formattedString="";var result;var searchString=this.pattern;while((result=regex.exec(searchString))){var matchedString=result[0];var padding=result[1];var truncation=result[2];var conversionCharacter=result[3];var specifier=result[5];var text=result[6];if(text){formattedString+=""+text;}else{var replacement="";switch(conversionCharacter){case"a":case"m":var depth=0;if(specifier){depth=parseInt(specifier,10);if(isNaN(depth)){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character '"+conversionCharacter+"' - should be a number");depth=0;}}

+var messages=(conversionCharacter==="a")?loggingEvent.messages[0]:loggingEvent.messages;for(var i=0,len=messages.length;i<len;i++){if(i>0&&(replacement.charAt(replacement.length-1)!==" ")){replacement+=" ";}

+if(depth===0){replacement+=messages[i];}else{replacement+=formatObjectExpansion(messages[i],depth);}}

+break;case"c":var loggerName=loggingEvent.logger.name;if(specifier){var precision=parseInt(specifier,10);var loggerNameBits=loggingEvent.logger.name.split(".");if(precision>=loggerNameBits.length){replacement=loggerName;}else{replacement=loggerNameBits.slice(loggerNameBits.length-precision).join(".");}}else{replacement=loggerName;}

+break;case"d":var dateFormat=PatternLayout.ISO8601_DATEFORMAT;if(specifier){dateFormat=specifier;if(dateFormat=="ISO8601"){dateFormat=PatternLayout.ISO8601_DATEFORMAT;}else if(dateFormat=="ABSOLUTE"){dateFormat=PatternLayout.ABSOLUTETIME_DATEFORMAT;}else if(dateFormat=="DATE"){dateFormat=PatternLayout.DATETIME_DATEFORMAT;}}

+replacement=(new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);break;case"f":if(this.hasCustomFields()){var fieldIndex=0;if(specifier){fieldIndex=parseInt(specifier,10);if(isNaN(fieldIndex)){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - should be a number");}else if(fieldIndex===0){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - must be greater than zero");}else if(fieldIndex>this.customFields.length){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - there aren't that many custom fields");}else{fieldIndex=fieldIndex-1;}}

+var val=this.customFields[fieldIndex].value;if(typeof val=="function"){val=val(this,loggingEvent);}

+replacement=val;}

+break;case"n":replacement=newLine;break;case"p":replacement=loggingEvent.level.name;break;case"r":replacement=""+loggingEvent.timeStamp.getDifference(applicationStartDate);break;case"%":replacement="%";break;default:replacement=matchedString;break;}

+var l;if(truncation){l=parseInt(truncation.substr(1),10);var strLen=replacement.length;if(l<strLen){replacement=replacement.substring(strLen-l,strLen);}}

+if(padding){if(padding.charAt(0)=="-"){l=parseInt(padding.substr(1),10);while(replacement.length<l){replacement+=" ";}}else{l=parseInt(padding,10);while(replacement.length<l){replacement=" "+replacement;}}}

+formattedString+=replacement;}

+searchString=searchString.substr(result.index+result[0].length);}

+return formattedString;};PatternLayout.prototype.ignoresThrowable=function(){return true;};PatternLayout.prototype.toString=function(){return"PatternLayout";};log4javascript.PatternLayout=PatternLayout;function AlertAppender(){}

+AlertAppender.prototype=new Appender();AlertAppender.prototype.layout=new SimpleLayout();AlertAppender.prototype.append=function(loggingEvent){var formattedMessage=this.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();}

+alert(formattedMessage);};AlertAppender.prototype.toString=function(){return"AlertAppender";};log4javascript.AlertAppender=AlertAppender;function BrowserConsoleAppender(){}

+BrowserConsoleAppender.prototype=new log4javascript.Appender();BrowserConsoleAppender.prototype.layout=new NullLayout();BrowserConsoleAppender.prototype.threshold=Level.DEBUG;BrowserConsoleAppender.prototype.append=function(loggingEvent){var appender=this;var getFormattedMessage=function(){var layout=appender.getLayout();var formattedMessage=layout.format(loggingEvent);if(layout.ignoresThrowable()&&loggingEvent.exception){formattedMessage+=loggingEvent.getThrowableStrRep();}

+return formattedMessage;};if((typeof opera!="undefined")&&opera.postError){opera.postError(getFormattedMessage());}else if(window.console&&window.console.log){var formattedMesage=getFormattedMessage();if(window.console.debug&&Level.DEBUG.isGreaterOrEqual(loggingEvent.level)){window.console.debug(formattedMesage);}else if(window.console.info&&Level.INFO.equals(loggingEvent.level)){window.console.info(formattedMesage);}else if(window.console.warn&&Level.WARN.equals(loggingEvent.level)){window.console.warn(formattedMesage);}else if(window.console.error&&loggingEvent.level.isGreaterOrEqual(Level.ERROR)){window.console.error(formattedMesage);}else{window.console.log(formattedMesage);}}};BrowserConsoleAppender.prototype.group=function(name){if(window.console&&window.console.group){window.console.group(name);}};BrowserConsoleAppender.prototype.groupEnd=function(){if(window.console&&window.console.groupEnd){window.console.groupEnd();}};BrowserConsoleAppender.prototype.toString=function(){return"BrowserConsoleAppender";};log4javascript.BrowserConsoleAppender=BrowserConsoleAppender;var xmlHttpFactories=[function(){return new XMLHttpRequest();},function(){return new ActiveXObject("Msxml2.XMLHTTP");},function(){return new ActiveXObject("Microsoft.XMLHTTP");}];var getXmlHttp=function(errorHandler){var xmlHttp=null,factory;for(var i=0,len=xmlHttpFactories.length;i<len;i++){factory=xmlHttpFactories[i];try{xmlHttp=factory();getXmlHttp=factory;return xmlHttp;}catch(e){}}

+if(errorHandler){errorHandler();}else{handleError("getXmlHttp: unable to obtain XMLHttpRequest object");}};function isHttpRequestSuccessful(xmlHttp){return isUndefined(xmlHttp.status)||xmlHttp.status===0||(xmlHttp.status>=200&&xmlHttp.status<300)||xmlHttp.status==1223;}

+function AjaxAppender(url){var appender=this;var isSupported=true;if(!url){handleError("AjaxAppender: URL must be specified in constructor");isSupported=false;}

+var timed=this.defaults.timed;var waitForResponse=this.defaults.waitForResponse;var batchSize=this.defaults.batchSize;var timerInterval=this.defaults.timerInterval;var requestSuccessCallback=this.defaults.requestSuccessCallback;var failCallback=this.defaults.failCallback;var postVarName=this.defaults.postVarName;var sendAllOnUnload=this.defaults.sendAllOnUnload;var contentType=this.defaults.contentType;var sessionId=null;var queuedLoggingEvents=[];var queuedRequests=[];var headers=[];var sending=false;var initialized=false;function checkCanConfigure(configOptionName){if(initialized){handleError("AjaxAppender: configuration option '"+

+configOptionName+"' may not be set after the appender has been initialized");return false;}

+return true;}

+this.getSessionId=function(){return sessionId;};this.setSessionId=function(sessionIdParam){sessionId=extractStringFromParam(sessionIdParam,null);this.layout.setCustomField("sessionid",sessionId);};this.setLayout=function(layoutParam){if(checkCanConfigure("layout")){this.layout=layoutParam;if(sessionId!==null){this.setSessionId(sessionId);}}};this.isTimed=function(){return timed;};this.setTimed=function(timedParam){if(checkCanConfigure("timed")){timed=bool(timedParam);}};this.getTimerInterval=function(){return timerInterval;};this.setTimerInterval=function(timerIntervalParam){if(checkCanConfigure("timerInterval")){timerInterval=extractIntFromParam(timerIntervalParam,timerInterval);}};this.isWaitForResponse=function(){return waitForResponse;};this.setWaitForResponse=function(waitForResponseParam){if(checkCanConfigure("waitForResponse")){waitForResponse=bool(waitForResponseParam);}};this.getBatchSize=function(){return batchSize;};this.setBatchSize=function(batchSizeParam){if(checkCanConfigure("batchSize")){batchSize=extractIntFromParam(batchSizeParam,batchSize);}};this.isSendAllOnUnload=function(){return sendAllOnUnload;};this.setSendAllOnUnload=function(sendAllOnUnloadParam){if(checkCanConfigure("sendAllOnUnload")){sendAllOnUnload=extractBooleanFromParam(sendAllOnUnloadParam,sendAllOnUnload);}};this.setRequestSuccessCallback=function(requestSuccessCallbackParam){requestSuccessCallback=extractFunctionFromParam(requestSuccessCallbackParam,requestSuccessCallback);};this.setFailCallback=function(failCallbackParam){failCallback=extractFunctionFromParam(failCallbackParam,failCallback);};this.getPostVarName=function(){return postVarName;};this.setPostVarName=function(postVarNameParam){if(checkCanConfigure("postVarName")){postVarName=extractStringFromParam(postVarNameParam,postVarName);}};this.getHeaders=function(){return headers;};this.addHeader=function(name,value){if(name.toLowerCase()=="content-type"){contentType=value;}else{headers.push({name:name,value:value});}};function sendAll(){if(isSupported&&enabled){sending=true;var currentRequestBatch;if(waitForResponse){if(queuedRequests.length>0){currentRequestBatch=queuedRequests.shift();sendRequest(preparePostData(currentRequestBatch),sendAll);}else{sending=false;if(timed){scheduleSending();}}}else{while((currentRequestBatch=queuedRequests.shift())){sendRequest(preparePostData(currentRequestBatch));}

+sending=false;if(timed){scheduleSending();}}}}

+this.sendAll=sendAll;function sendAllRemaining(){var sendingAnything=false;if(isSupported&&enabled){var actualBatchSize=appender.getLayout().allowBatching()?batchSize:1;var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);if(queuedLoggingEvents.length>=actualBatchSize){queuedRequests.push(batchedLoggingEvents);batchedLoggingEvents=[];}}

+if(batchedLoggingEvents.length>0){queuedRequests.push(batchedLoggingEvents);}

+sendingAnything=(queuedRequests.length>0);waitForResponse=false;timed=false;sendAll();}

+return sendingAnything;}

+this.sendAllRemaining=sendAllRemaining;function preparePostData(batchedLoggingEvents){var formattedMessages=[];var currentLoggingEvent;var postData="";while((currentLoggingEvent=batchedLoggingEvents.shift())){var currentFormattedMessage=appender.getLayout().format(currentLoggingEvent);if(appender.getLayout().ignoresThrowable()){currentFormattedMessage+=currentLoggingEvent.getThrowableStrRep();}

+formattedMessages.push(currentFormattedMessage);}

+if(batchedLoggingEvents.length==1){postData=formattedMessages.join("");}else{postData=appender.getLayout().batchHeader+

+formattedMessages.join(appender.getLayout().batchSeparator)+

+appender.getLayout().batchFooter;}

+if(contentType==appender.defaults.contentType){postData=appender.getLayout().returnsPostData?postData:urlEncode(postVarName)+"="+urlEncode(postData);if(postData.length>0){postData+="&";}

+postData+="layout="+urlEncode(appender.getLayout().toString());}

+return postData;}

+function scheduleSending(){window.setTimeout(sendAll,timerInterval);}

+function xmlHttpErrorHandler(){var msg="AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}}

+function sendRequest(postData,successCallback){try{var xmlHttp=getXmlHttp(xmlHttpErrorHandler);if(isSupported){if(xmlHttp.overrideMimeType){xmlHttp.overrideMimeType(appender.getLayout().getContentType());}

+xmlHttp.onreadystatechange=function(){if(xmlHttp.readyState==4){if(isHttpRequestSuccessful(xmlHttp)){if(requestSuccessCallback){requestSuccessCallback(xmlHttp);}

+if(successCallback){successCallback(xmlHttp);}}else{var msg="AjaxAppender.append: XMLHttpRequest request to URL "+

+url+" returned status code "+xmlHttp.status;handleError(msg);if(failCallback){failCallback(msg);}}

+xmlHttp.onreadystatechange=emptyFunction;xmlHttp=null;}};xmlHttp.open("POST",url,true);try{for(var i=0,header;header=headers[i++];){xmlHttp.setRequestHeader(header.name,header.value);}

+xmlHttp.setRequestHeader("Content-Type",contentType);}catch(headerEx){var msg="AjaxAppender.append: your browser's XMLHttpRequest implementation"+" does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}

+return;}

+xmlHttp.send(postData);}}catch(ex){var errMsg="AjaxAppender.append: error sending log message to "+url;handleError(errMsg,ex);isSupported=false;if(failCallback){failCallback(errMsg+". Details: "+getExceptionStringRep(ex));}}}

+this.append=function(loggingEvent){if(isSupported){if(!initialized){init();}

+queuedLoggingEvents.push(loggingEvent);var actualBatchSize=this.getLayout().allowBatching()?batchSize:1;if(queuedLoggingEvents.length>=actualBatchSize){var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);}

+queuedRequests.push(batchedLoggingEvents);if(!timed&&(!waitForResponse||(waitForResponse&&!sending))){sendAll();}}}};function init(){initialized=true;if(sendAllOnUnload){var oldBeforeUnload=window.onbeforeunload;window.onbeforeunload=function(){if(oldBeforeUnload){oldBeforeUnload();}

+if(sendAllRemaining()){return"Sending log messages";}};}

+if(timed){scheduleSending();}}}

+AjaxAppender.prototype=new Appender();AjaxAppender.prototype.defaults={waitForResponse:false,timed:false,timerInterval:1000,batchSize:1,sendAllOnUnload:false,requestSuccessCallback:null,failCallback:null,postVarName:"data",contentType:"application/x-www-form-urlencoded"};AjaxAppender.prototype.layout=new HttpPostDataLayout();AjaxAppender.prototype.toString=function(){return"AjaxAppender";};log4javascript.AjaxAppender=AjaxAppender;function setCookie(name,value,days,path){var expires;path=path?"; path="+path:"";if(days){var date=new Date();date.setTime(date.getTime()+(days*24*60*60*1000));expires="; expires="+date.toGMTString();}else{expires="";}

+document.cookie=escape(name)+"="+escape(value)+expires+path;}

+function getCookie(name){var nameEquals=escape(name)+"=";var ca=document.cookie.split(";");for(var i=0,len=ca.length;i<len;i++){var c=ca[i];while(c.charAt(0)===" "){c=c.substring(1,c.length);}

+if(c.indexOf(nameEquals)===0){return unescape(c.substring(nameEquals.length,c.length));}}

+return null;}

+function getBaseUrl(){var scripts=document.getElementsByTagName("script");for(var i=0,len=scripts.length;i<len;++i){if(scripts[i].src.indexOf("log4javascript")!=-1){var lastSlash=scripts[i].src.lastIndexOf("/");return(lastSlash==-1)?"":scripts[i].src.substr(0,lastSlash+1);}}

+return null;}

+function isLoaded(win){try{return bool(win.loaded);}catch(ex){return false;}}

+var ConsoleAppender;(function(){var getConsoleHtmlLines=function(){return['<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">','<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">','<head>','<title>log4javascript</title>','<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />','<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->','<meta http-equiv="X-UA-Compatible" content="IE=7" />','<script type="text/javascript">var isIe = false, isIePre7 = false;</script>','<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->','<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->','<script type="text/javascript">','//<![CDATA[','var loggingEnabled=true;var logQueuedEventsTimer=null;var logEntries=[];var logEntriesAndSeparators=[];var logItems=[];var renderDelay=100;var unrenderedLogItemsExist=false;var rootGroup,currentGroup=null;var loaded=false;var currentLogItem=null;var logMainContainer;function copyProperties(obj,props){for(var i in props){obj[i]=props[i];}}','function LogItem(){}','LogItem.prototype={mainContainer:null,wrappedContainer:null,unwrappedContainer:null,group:null,appendToLog:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].appendToLog();}','this.group.update();},doRemove:function(doUpdate,removeFromGroup){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].remove();}','this.unwrappedElementContainer=null;this.wrappedElementContainer=null;this.mainElementContainer=null;}','if(this.group&&removeFromGroup){this.group.removeChild(this,doUpdate);}','if(this===currentLogItem){currentLogItem=null;}},remove:function(doUpdate,removeFromGroup){this.doRemove(doUpdate,removeFromGroup);},render:function(){},accept:function(visitor){visitor.visit(this);},getUnwrappedDomContainer:function(){return this.group.unwrappedElementContainer.contentDiv;},getWrappedDomContainer:function(){return this.group.wrappedElementContainer.contentDiv;},getMainDomContainer:function(){return this.group.mainElementContainer.contentDiv;}};LogItem.serializedItemKeys={LOG_ENTRY:0,GROUP_START:1,GROUP_END:2};function LogItemContainerElement(){}','LogItemContainerElement.prototype={appendToLog:function(){var insertBeforeFirst=(newestAtTop&&this.containerDomNode.hasChildNodes());if(insertBeforeFirst){this.containerDomNode.insertBefore(this.mainDiv,this.containerDomNode.firstChild);}else{this.containerDomNode.appendChild(this.mainDiv);}}};function SeparatorElementContainer(containerDomNode){this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="separator";this.mainDiv.innerHTML="&nbsp;";}','SeparatorElementContainer.prototype=new LogItemContainerElement();SeparatorElementContainer.prototype.remove=function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;};function Separator(){this.rendered=false;}','Separator.prototype=new LogItem();copyProperties(Separator.prototype,{render:function(){var containerDomNode=this.group.contentDiv;if(isIe){this.unwrappedElementContainer=new SeparatorElementContainer(this.getUnwrappedDomContainer());this.wrappedElementContainer=new SeparatorElementContainer(this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new SeparatorElementContainer(this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}','this.content=this.formattedMessage;this.rendered=true;}});function GroupElementContainer(group,containerDomNode,isRoot,isWrapped){this.group=group;this.containerDomNode=containerDomNode;this.isRoot=isRoot;this.isWrapped=isWrapped;this.expandable=false;if(this.isRoot){if(isIe){this.contentDiv=logMainContainer.appendChild(document.createElement("div"));this.contentDiv.id=this.isWrapped?"log_wrapped":"log_unwrapped";}else{this.contentDiv=logMainContainer;}}else{var groupElementContainer=this;this.mainDiv=document.createElement("div");this.mainDiv.className="group";this.headingDiv=this.mainDiv.appendChild(document.createElement("div"));this.headingDiv.className="groupheading";this.expander=this.headingDiv.appendChild(document.createElement("span"));this.expander.className="expander unselectable greyedout";this.expander.unselectable=true;var expanderText=this.group.expanded?"-":"+";this.expanderTextNode=this.expander.appendChild(document.createTextNode(expanderText));this.headingDiv.appendChild(document.createTextNode(" "+this.group.name));this.contentDiv=this.mainDiv.appendChild(document.createElement("div"));var contentCssClass=this.group.expanded?"expanded":"collapsed";this.contentDiv.className="groupcontent "+contentCssClass;this.expander.onclick=function(){if(groupElementContainer.group.expandable){groupElementContainer.group.toggleExpanded();}};}}','GroupElementContainer.prototype=new LogItemContainerElement();copyProperties(GroupElementContainer.prototype,{toggleExpanded:function(){if(!this.isRoot){var oldCssClass,newCssClass,expanderText;if(this.group.expanded){newCssClass="expanded";oldCssClass="collapsed";expanderText="-";}else{newCssClass="collapsed";oldCssClass="expanded";expanderText="+";}','replaceClass(this.contentDiv,newCssClass,oldCssClass);this.expanderTextNode.nodeValue=expanderText;}},remove:function(){if(!this.isRoot){this.headingDiv=null;this.expander.onclick=null;this.expander=null;this.expanderTextNode=null;this.contentDiv=null;this.containerDomNode=null;this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;}},reverseChildren:function(){var node=null;var childDomNodes=[];while((node=this.contentDiv.firstChild)){this.contentDiv.removeChild(node);childDomNodes.push(node);}','while((node=childDomNodes.pop())){this.contentDiv.appendChild(node);}},update:function(){if(!this.isRoot){if(this.group.expandable){removeClass(this.expander,"greyedout");}else{addClass(this.expander,"greyedout");}}},clear:function(){if(this.isRoot){this.contentDiv.innerHTML="";}}});function Group(name,isRoot,initiallyExpanded){this.name=name;this.group=null;this.isRoot=isRoot;this.initiallyExpanded=initiallyExpanded;this.elementContainers=[];this.children=[];this.expanded=initiallyExpanded;this.rendered=false;this.expandable=false;}','Group.prototype=new LogItem();copyProperties(Group.prototype,{addChild:function(logItem){this.children.push(logItem);logItem.group=this;},render:function(){if(isIe){var unwrappedDomContainer,wrappedDomContainer;if(this.isRoot){unwrappedDomContainer=logMainContainer;wrappedDomContainer=logMainContainer;}else{unwrappedDomContainer=this.getUnwrappedDomContainer();wrappedDomContainer=this.getWrappedDomContainer();}','this.unwrappedElementContainer=new GroupElementContainer(this,unwrappedDomContainer,this.isRoot,false);this.wrappedElementContainer=new GroupElementContainer(this,wrappedDomContainer,this.isRoot,true);this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{var mainDomContainer=this.isRoot?logMainContainer:this.getMainDomContainer();this.mainElementContainer=new GroupElementContainer(this,mainDomContainer,this.isRoot,false);this.elementContainers=[this.mainElementContainer];}','this.rendered=true;},toggleExpanded:function(){this.expanded=!this.expanded;for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].toggleExpanded();}},expand:function(){if(!this.expanded){this.toggleExpanded();}},accept:function(visitor){visitor.visitGroup(this);},reverseChildren:function(){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].reverseChildren();}}},update:function(){var previouslyExpandable=this.expandable;this.expandable=(this.children.length!==0);if(this.expandable!==previouslyExpandable){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].update();}}},flatten:function(){var visitor=new GroupFlattener();this.accept(visitor);return visitor.logEntriesAndSeparators;},removeChild:function(child,doUpdate){array_remove(this.children,child);child.group=null;if(doUpdate){this.update();}},remove:function(doUpdate,removeFromGroup){for(var i=0,len=this.children.length;i<len;i++){this.children[i].remove(false,false);}','this.children=[];this.update();if(this===currentGroup){currentGroup=this.group;}','this.doRemove(doUpdate,removeFromGroup);},serialize:function(items){items.push([LogItem.serializedItemKeys.GROUP_START,this.name]);for(var i=0,len=this.children.length;i<len;i++){this.children[i].serialize(items);}','if(this!==currentGroup){items.push([LogItem.serializedItemKeys.GROUP_END]);}},clear:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clear();}}});function LogEntryElementContainer(){}','LogEntryElementContainer.prototype=new LogItemContainerElement();copyProperties(LogEntryElementContainer.prototype,{remove:function(){this.doRemove();},doRemove:function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;this.contentElement=null;this.containerDomNode=null;},setContent:function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=content;}},setSearchMatch:function(isMatch){var oldCssClass=isMatch?"searchnonmatch":"searchmatch";var newCssClass=isMatch?"searchmatch":"searchnonmatch";replaceClass(this.mainDiv,newCssClass,oldCssClass);},clearSearch:function(){removeClass(this.mainDiv,"searchmatch");removeClass(this.mainDiv,"searchnonmatch");}});function LogEntryWrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.mainDiv.className="logentry wrapped "+this.logEntry.level;this.contentElement=this.mainDiv;}','LogEntryWrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryWrappedElementContainer.prototype.setContent=function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=wrappedContent;}};function LogEntryUnwrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry unwrapped "+this.logEntry.level;this.pre=this.mainDiv.appendChild(document.createElement("pre"));this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.pre.className="unwrapped";this.contentElement=this.pre;}','LogEntryUnwrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryUnwrappedElementContainer.prototype.remove=function(){this.doRemove();this.pre=null;};function LogEntryMainElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry nonielogentry "+this.logEntry.level;this.contentElement=this.mainDiv.appendChild(document.createElement("span"));this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));}','LogEntryMainElementContainer.prototype=new LogEntryElementContainer();function LogEntry(level,formattedMessage){this.level=level;this.formattedMessage=formattedMessage;this.rendered=false;}','LogEntry.prototype=new LogItem();copyProperties(LogEntry.prototype,{render:function(){var logEntry=this;var containerDomNode=this.group.contentDiv;if(isIe){this.formattedMessage=this.formattedMessage.replace(/\\r\\n/g,"\\r");this.unwrappedElementContainer=new LogEntryUnwrappedElementContainer(this,this.getUnwrappedDomContainer());this.wrappedElementContainer=new LogEntryWrappedElementContainer(this,this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new LogEntryMainElementContainer(this,this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}','this.content=this.formattedMessage;this.rendered=true;},setContent:function(content,wrappedContent){if(content!=this.content){if(isIe&&(content!==this.formattedMessage)){content=content.replace(/\\r\\n/g,"\\r");}','for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setContent(content,wrappedContent);}','this.content=content;}},getSearchMatches:function(){var matches=[];var i,len;if(isIe){var unwrappedEls=getElementsByClass(this.unwrappedElementContainer.mainDiv,"searchterm","span");var wrappedEls=getElementsByClass(this.wrappedElementContainer.mainDiv,"searchterm","span");for(i=0,len=unwrappedEls.length;i<len;i++){matches[i]=new Match(this.level,null,unwrappedEls[i],wrappedEls[i]);}}else{var els=getElementsByClass(this.mainElementContainer.mainDiv,"searchterm","span");for(i=0,len=els.length;i<len;i++){matches[i]=new Match(this.level,els[i]);}}','return matches;},setSearchMatch:function(isMatch){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setSearchMatch(isMatch);}},clearSearch:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clearSearch();}},accept:function(visitor){visitor.visitLogEntry(this);},serialize:function(items){items.push([LogItem.serializedItemKeys.LOG_ENTRY,this.level,this.formattedMessage]);}});function LogItemVisitor(){}','LogItemVisitor.prototype={visit:function(logItem){},visitParent:function(logItem){if(logItem.group){logItem.group.accept(this);}},visitChildren:function(logItem){for(var i=0,len=logItem.children.length;i<len;i++){logItem.children[i].accept(this);}},visitLogEntry:function(logEntry){this.visit(logEntry);},visitSeparator:function(separator){this.visit(separator);},visitGroup:function(group){this.visit(group);}};function GroupFlattener(){this.logEntriesAndSeparators=[];}','GroupFlattener.prototype=new LogItemVisitor();GroupFlattener.prototype.visitGroup=function(group){this.visitChildren(group);};GroupFlattener.prototype.visitLogEntry=function(logEntry){this.logEntriesAndSeparators.push(logEntry);};GroupFlattener.prototype.visitSeparator=function(separator){this.logEntriesAndSeparators.push(separator);};window.onload=function(){if(location.search){var queryBits=unescape(location.search).substr(1).split("&"),nameValueBits;for(var i=0,len=queryBits.length;i<len;i++){nameValueBits=queryBits[i].split("=");if(nameValueBits[0]=="log4javascript_domain"){document.domain=nameValueBits[1];break;}}}','logMainContainer=$("log");if(isIePre7){addClass(logMainContainer,"oldIe");}','rootGroup=new Group("root",true);rootGroup.render();currentGroup=rootGroup;setCommandInputWidth();setLogContainerHeight();toggleLoggingEnabled();toggleSearchEnabled();toggleSearchFilter();toggleSearchHighlight();applyFilters();checkAllLevels();toggleWrap();toggleNewestAtTop();toggleScrollToLatest();renderQueuedLogItems();loaded=true;$("command").value="";$("command").autocomplete="off";$("command").onkeydown=function(evt){evt=getEvent(evt);if(evt.keyCode==10||evt.keyCode==13){evalCommandLine();stopPropagation(evt);}else if(evt.keyCode==27){this.value="";this.focus();}else if(evt.keyCode==38&&commandHistory.length>0){currentCommandIndex=Math.max(0,currentCommandIndex-1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}else if(evt.keyCode==40&&commandHistory.length>0){currentCommandIndex=Math.min(commandHistory.length-1,currentCommandIndex+1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}};$("command").onkeypress=function(evt){evt=getEvent(evt);if(evt.keyCode==38&&commandHistory.length>0&&evt.preventDefault){evt.preventDefault();}};$("command").onkeyup=function(evt){evt=getEvent(evt);if(evt.keyCode==27&&evt.preventDefault){evt.preventDefault();this.focus();}};document.onkeydown=function keyEventHandler(evt){evt=getEvent(evt);switch(evt.keyCode){case 69:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){evalLastCommand();cancelKeyEvent(evt);return false;}','break;case 75:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusSearch();cancelKeyEvent(evt);return false;}','break;case 40:case 76:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusCommandLine();cancelKeyEvent(evt);return false;}','break;}};setTimeout(setLogContainerHeight,20);setShowCommandLine(showCommandLine);doSearch();};window.onunload=function(){if(mainWindowExists()){appender.unload();}','appender=null;};function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}','function setLoggingEnabled(enable){loggingEnabled=enable;}','var appender=null;function setAppender(appenderParam){appender=appenderParam;}','function setShowCloseButton(showCloseButton){$("closeButton").style.display=showCloseButton?"inline":"none";}','function setShowHideButton(showHideButton){$("hideButton").style.display=showHideButton?"inline":"none";}','var newestAtTop=false;function LogItemContentReverser(){}','LogItemContentReverser.prototype=new LogItemVisitor();LogItemContentReverser.prototype.visitGroup=function(group){group.reverseChildren();this.visitChildren(group);};function setNewestAtTop(isNewestAtTop){var oldNewestAtTop=newestAtTop;var i,iLen,j,jLen;newestAtTop=Boolean(isNewestAtTop);if(oldNewestAtTop!=newestAtTop){var visitor=new LogItemContentReverser();rootGroup.accept(visitor);if(currentSearch){var currentMatch=currentSearch.matches[currentMatchIndex];var matchIndex=0;var matches=[];var actOnLogEntry=function(logEntry){var logEntryMatches=logEntry.getSearchMatches();for(j=0,jLen=logEntryMatches.length;j<jLen;j++){matches[matchIndex]=logEntryMatches[j];if(currentMatch&&logEntryMatches[j].equals(currentMatch)){currentMatchIndex=matchIndex;}','matchIndex++;}};if(newestAtTop){for(i=logEntries.length-1;i>=0;i--){actOnLogEntry(logEntries[i]);}}else{for(i=0,iLen=logEntries.length;i<iLen;i++){actOnLogEntry(logEntries[i]);}}','currentSearch.matches=matches;if(currentMatch){currentMatch.setCurrent();}}else if(scrollToLatest){doScrollToLatest();}}','$("newestAtTop").checked=isNewestAtTop;}','function toggleNewestAtTop(){var isNewestAtTop=$("newestAtTop").checked;setNewestAtTop(isNewestAtTop);}','var scrollToLatest=true;function setScrollToLatest(isScrollToLatest){scrollToLatest=isScrollToLatest;if(scrollToLatest){doScrollToLatest();}','$("scrollToLatest").checked=isScrollToLatest;}','function toggleScrollToLatest(){var isScrollToLatest=$("scrollToLatest").checked;setScrollToLatest(isScrollToLatest);}','function doScrollToLatest(){var l=logMainContainer;if(typeof l.scrollTop!="undefined"){if(newestAtTop){l.scrollTop=0;}else{var latestLogEntry=l.lastChild;if(latestLogEntry){l.scrollTop=l.scrollHeight;}}}}','var closeIfOpenerCloses=true;function setCloseIfOpenerCloses(isCloseIfOpenerCloses){closeIfOpenerCloses=isCloseIfOpenerCloses;}','var maxMessages=null;function setMaxMessages(max){maxMessages=max;pruneLogEntries();}','var showCommandLine=false;function setShowCommandLine(isShowCommandLine){showCommandLine=isShowCommandLine;if(loaded){$("commandLine").style.display=showCommandLine?"block":"none";setCommandInputWidth();setLogContainerHeight();}}','function focusCommandLine(){if(loaded){$("command").focus();}}','function focusSearch(){if(loaded){$("searchBox").focus();}}','function getLogItems(){var items=[];for(var i=0,len=logItems.length;i<len;i++){logItems[i].serialize(items);}','return items;}','function setLogItems(items){var loggingReallyEnabled=loggingEnabled;loggingEnabled=true;for(var i=0,len=items.length;i<len;i++){switch(items[i][0]){case LogItem.serializedItemKeys.LOG_ENTRY:log(items[i][1],items[i][2]);break;case LogItem.serializedItemKeys.GROUP_START:group(items[i][1]);break;case LogItem.serializedItemKeys.GROUP_END:groupEnd();break;}}','loggingEnabled=loggingReallyEnabled;}','function log(logLevel,formattedMessage){if(loggingEnabled){var logEntry=new LogEntry(logLevel,formattedMessage);logEntries.push(logEntry);logEntriesAndSeparators.push(logEntry);logItems.push(logEntry);currentGroup.addChild(logEntry);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}','logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}','function renderQueuedLogItems(){logQueuedEventsTimer=null;var pruned=pruneLogEntries();var initiallyHasMatches=currentSearch?currentSearch.hasMatches():false;for(var i=0,len=logItems.length;i<len;i++){if(!logItems[i].rendered){logItems[i].render();logItems[i].appendToLog();if(currentSearch&&(logItems[i]instanceof LogEntry)){currentSearch.applyTo(logItems[i]);}}}','if(currentSearch){if(pruned){if(currentSearch.hasVisibleMatches()){if(currentMatchIndex===null){setCurrentMatchIndex(0);}','displayMatches();}else{displayNoMatches();}}else if(!initiallyHasMatches&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}}','if(scrollToLatest){doScrollToLatest();}','unrenderedLogItemsExist=false;}','function pruneLogEntries(){if((maxMessages!==null)&&(logEntriesAndSeparators.length>maxMessages)){var numberToDelete=logEntriesAndSeparators.length-maxMessages;var prunedLogEntries=logEntriesAndSeparators.slice(0,numberToDelete);if(currentSearch){currentSearch.removeMatches(prunedLogEntries);}','var group;for(var i=0;i<numberToDelete;i++){group=logEntriesAndSeparators[i].group;array_remove(logItems,logEntriesAndSeparators[i]);array_remove(logEntries,logEntriesAndSeparators[i]);logEntriesAndSeparators[i].remove(true,true);if(group.children.length===0&&group!==currentGroup&&group!==rootGroup){array_remove(logItems,group);group.remove(true,true);}}','logEntriesAndSeparators=array_removeFromStart(logEntriesAndSeparators,numberToDelete);return true;}','return false;}','function group(name,startExpanded){if(loggingEnabled){initiallyExpanded=(typeof startExpanded==="undefined")?true:Boolean(startExpanded);var newGroup=new Group(name,false,initiallyExpanded);currentGroup.addChild(newGroup);currentGroup=newGroup;logItems.push(newGroup);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}','logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}','function groupEnd(){currentGroup=(currentGroup===rootGroup)?rootGroup:currentGroup.group;}','function mainPageReloaded(){currentGroup=rootGroup;var separator=new Separator();logEntriesAndSeparators.push(separator);logItems.push(separator);currentGroup.addChild(separator);}','function closeWindow(){if(appender&&mainWindowExists()){appender.close(true);}else{window.close();}}','function hide(){if(appender&&mainWindowExists()){appender.hide();}}','var mainWindow=window;var windowId="log4javascriptConsoleWindow_"+new Date().getTime()+"_"+(""+Math.random()).substr(2);function setMainWindow(win){mainWindow=win;mainWindow[windowId]=window;if(opener&&closeIfOpenerCloses){pollOpener();}}','function pollOpener(){if(closeIfOpenerCloses){if(mainWindowExists()){setTimeout(pollOpener,500);}else{closeWindow();}}}','function mainWindowExists(){try{return(mainWindow&&!mainWindow.closed&&mainWindow[windowId]==window);}catch(ex){}','return false;}','var logLevels=["TRACE","DEBUG","INFO","WARN","ERROR","FATAL"];function getCheckBox(logLevel){return $("switch_"+logLevel);}','function getIeWrappedLogContainer(){return $("log_wrapped");}','function getIeUnwrappedLogContainer(){return $("log_unwrapped");}','function applyFilters(){for(var i=0;i<logLevels.length;i++){if(getCheckBox(logLevels[i]).checked){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}','updateSearchFromFilters();}','function toggleAllLevels(){var turnOn=$("switch_ALL").checked;for(var i=0;i<logLevels.length;i++){getCheckBox(logLevels[i]).checked=turnOn;if(turnOn){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}}','function checkAllLevels(){for(var i=0;i<logLevels.length;i++){if(!getCheckBox(logLevels[i]).checked){getCheckBox("ALL").checked=false;return;}}','getCheckBox("ALL").checked=true;}','function clearLog(){rootGroup.clear();currentGroup=rootGroup;logEntries=[];logItems=[];logEntriesAndSeparators=[];doSearch();}','function toggleWrap(){var enable=$("wrap").checked;if(enable){addClass(logMainContainer,"wrap");}else{removeClass(logMainContainer,"wrap");}','refreshCurrentMatch();}','var searchTimer=null;function scheduleSearch(){try{clearTimeout(searchTimer);}catch(ex){}','searchTimer=setTimeout(doSearch,500);}','function Search(searchTerm,isRegex,searchRegex,isCaseSensitive){this.searchTerm=searchTerm;this.isRegex=isRegex;this.searchRegex=searchRegex;this.isCaseSensitive=isCaseSensitive;this.matches=[];}','Search.prototype={hasMatches:function(){return this.matches.length>0;},hasVisibleMatches:function(){if(this.hasMatches()){for(var i=0;i<this.matches.length;i++){if(this.matches[i].isVisible()){return true;}}}','return false;},match:function(logEntry){var entryText=String(logEntry.formattedMessage);var matchesSearch=false;if(this.isRegex){matchesSearch=this.searchRegex.test(entryText);}else if(this.isCaseSensitive){matchesSearch=(entryText.indexOf(this.searchTerm)>-1);}else{matchesSearch=(entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase())>-1);}','return matchesSearch;},getNextVisibleMatchIndex:function(){for(var i=currentMatchIndex+1;i<this.matches.length;i++){if(this.matches[i].isVisible()){return i;}}','for(i=0;i<=currentMatchIndex;i++){if(this.matches[i].isVisible()){return i;}}','return-1;},getPreviousVisibleMatchIndex:function(){for(var i=currentMatchIndex-1;i>=0;i--){if(this.matches[i].isVisible()){return i;}}','for(var i=this.matches.length-1;i>=currentMatchIndex;i--){if(this.matches[i].isVisible()){return i;}}','return-1;},applyTo:function(logEntry){var doesMatch=this.match(logEntry);if(doesMatch){logEntry.group.expand();logEntry.setSearchMatch(true);var logEntryContent;var wrappedLogEntryContent;var searchTermReplacementStartTag="<span class=\\\"searchterm\\\">";var searchTermReplacementEndTag="<"+"/span>";var preTagName=isIe?"pre":"span";var preStartTag="<"+preTagName+" class=\\\"pre\\\">";var preEndTag="<"+"/"+preTagName+">";var startIndex=0;var searchIndex,matchedText,textBeforeMatch;if(this.isRegex){var flags=this.isCaseSensitive?"g":"gi";var capturingRegex=new RegExp("("+this.searchRegex.source+")",flags);var rnd=(""+Math.random()).substr(2);var startToken="%%s"+rnd+"%%";var endToken="%%e"+rnd+"%%";logEntryContent=logEntry.formattedMessage.replace(capturingRegex,startToken+"$1"+endToken);logEntryContent=escapeHtml(logEntryContent);var result;var searchString=logEntryContent;logEntryContent="";wrappedLogEntryContent="";while((searchIndex=searchString.indexOf(startToken,startIndex))>-1){var endTokenIndex=searchString.indexOf(endToken,searchIndex);matchedText=searchString.substring(searchIndex+startToken.length,endTokenIndex);textBeforeMatch=searchString.substring(startIndex,searchIndex);logEntryContent+=preStartTag+textBeforeMatch+preEndTag;logEntryContent+=searchTermReplacementStartTag+preStartTag+matchedText+','preEndTag+searchTermReplacementEndTag;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+','matchedText+searchTermReplacementEndTag;}','startIndex=endTokenIndex+endToken.length;}','logEntryContent+=preStartTag+searchString.substr(startIndex)+preEndTag;if(isIe){wrappedLogEntryContent+=searchString.substr(startIndex);}}else{logEntryContent="";wrappedLogEntryContent="";var searchTermReplacementLength=searchTermReplacementStartTag.length+','this.searchTerm.length+searchTermReplacementEndTag.length;var searchTermLength=this.searchTerm.length;var searchTermLowerCase=this.searchTerm.toLowerCase();var logTextLowerCase=logEntry.formattedMessage.toLowerCase();while((searchIndex=logTextLowerCase.indexOf(searchTermLowerCase,startIndex))>-1){matchedText=escapeHtml(logEntry.formattedMessage.substr(searchIndex,this.searchTerm.length));textBeforeMatch=escapeHtml(logEntry.formattedMessage.substring(startIndex,searchIndex));var searchTermReplacement=searchTermReplacementStartTag+','preStartTag+matchedText+preEndTag+searchTermReplacementEndTag;logEntryContent+=preStartTag+textBeforeMatch+preEndTag+searchTermReplacement;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+','matchedText+searchTermReplacementEndTag;}','startIndex=searchIndex+searchTermLength;}','var textAfterLastMatch=escapeHtml(logEntry.formattedMessage.substr(startIndex));logEntryContent+=preStartTag+textAfterLastMatch+preEndTag;if(isIe){wrappedLogEntryContent+=textAfterLastMatch;}}','logEntry.setContent(logEntryContent,wrappedLogEntryContent);var logEntryMatches=logEntry.getSearchMatches();this.matches=this.matches.concat(logEntryMatches);}else{logEntry.setSearchMatch(false);logEntry.setContent(logEntry.formattedMessage,logEntry.formattedMessage);}','return doesMatch;},removeMatches:function(logEntries){var matchesToRemoveCount=0;var currentMatchRemoved=false;var matchesToRemove=[];var i,iLen,j,jLen;for(i=0,iLen=this.matches.length;i<iLen;i++){for(j=0,jLen=logEntries.length;j<jLen;j++){if(this.matches[i].belongsTo(logEntries[j])){matchesToRemove.push(this.matches[i]);if(i===currentMatchIndex){currentMatchRemoved=true;}}}}','var newMatch=currentMatchRemoved?null:this.matches[currentMatchIndex];if(currentMatchRemoved){for(i=currentMatchIndex,iLen=this.matches.length;i<iLen;i++){if(this.matches[i].isVisible()&&!array_contains(matchesToRemove,this.matches[i])){newMatch=this.matches[i];break;}}}','for(i=0,iLen=matchesToRemove.length;i<iLen;i++){array_remove(this.matches,matchesToRemove[i]);matchesToRemove[i].remove();}','if(this.hasVisibleMatches()){if(newMatch===null){setCurrentMatchIndex(0);}else{var newMatchIndex=0;for(i=0,iLen=this.matches.length;i<iLen;i++){if(newMatch===this.matches[i]){newMatchIndex=i;break;}}','setCurrentMatchIndex(newMatchIndex);}}else{currentMatchIndex=null;displayNoMatches();}}};function getPageOffsetTop(el,container){var currentEl=el;var y=0;while(currentEl&&currentEl!=container){y+=currentEl.offsetTop;currentEl=currentEl.offsetParent;}','return y;}','function scrollIntoView(el){var logContainer=logMainContainer;if(!$("wrap").checked){var logContainerLeft=logContainer.scrollLeft;var logContainerRight=logContainerLeft+logContainer.offsetWidth;var elLeft=el.offsetLeft;var elRight=elLeft+el.offsetWidth;if(elLeft<logContainerLeft||elRight>logContainerRight){logContainer.scrollLeft=elLeft-(logContainer.offsetWidth-el.offsetWidth)/2;}}','var logContainerTop=logContainer.scrollTop;var logContainerBottom=logContainerTop+logContainer.offsetHeight;var elTop=getPageOffsetTop(el)-getToolBarsHeight();var elBottom=elTop+el.offsetHeight;if(elTop<logContainerTop||elBottom>logContainerBottom){logContainer.scrollTop=elTop-(logContainer.offsetHeight-el.offsetHeight)/2;}}','function Match(logEntryLevel,spanInMainDiv,spanInUnwrappedPre,spanInWrappedDiv){this.logEntryLevel=logEntryLevel;this.spanInMainDiv=spanInMainDiv;if(isIe){this.spanInUnwrappedPre=spanInUnwrappedPre;this.spanInWrappedDiv=spanInWrappedDiv;}','this.mainSpan=isIe?spanInUnwrappedPre:spanInMainDiv;}','Match.prototype={equals:function(match){return this.mainSpan===match.mainSpan;},setCurrent:function(){if(isIe){addClass(this.spanInUnwrappedPre,"currentmatch");addClass(this.spanInWrappedDiv,"currentmatch");var elementToScroll=$("wrap").checked?this.spanInWrappedDiv:this.spanInUnwrappedPre;scrollIntoView(elementToScroll);}else{addClass(this.spanInMainDiv,"currentmatch");scrollIntoView(this.spanInMainDiv);}},belongsTo:function(logEntry){if(isIe){return isDescendant(this.spanInUnwrappedPre,logEntry.unwrappedPre);}else{return isDescendant(this.spanInMainDiv,logEntry.mainDiv);}},setNotCurrent:function(){if(isIe){removeClass(this.spanInUnwrappedPre,"currentmatch");removeClass(this.spanInWrappedDiv,"currentmatch");}else{removeClass(this.spanInMainDiv,"currentmatch");}},isOrphan:function(){return isOrphan(this.mainSpan);},isVisible:function(){return getCheckBox(this.logEntryLevel).checked;},remove:function(){if(isIe){this.spanInUnwrappedPre=null;this.spanInWrappedDiv=null;}else{this.spanInMainDiv=null;}}};var currentSearch=null;var currentMatchIndex=null;function doSearch(){var searchBox=$("searchBox");var searchTerm=searchBox.value;var isRegex=$("searchRegex").checked;var isCaseSensitive=$("searchCaseSensitive").checked;var i;if(searchTerm===""){$("searchReset").disabled=true;$("searchNav").style.display="none";removeClass(document.body,"searching");removeClass(searchBox,"hasmatches");removeClass(searchBox,"nomatches");for(i=0;i<logEntries.length;i++){logEntries[i].clearSearch();logEntries[i].setContent(logEntries[i].formattedMessage,logEntries[i].formattedMessage);}','currentSearch=null;setLogContainerHeight();}else{$("searchReset").disabled=false;$("searchNav").style.display="block";var searchRegex;var regexValid;if(isRegex){try{searchRegex=isCaseSensitive?new RegExp(searchTerm,"g"):new RegExp(searchTerm,"gi");regexValid=true;replaceClass(searchBox,"validregex","invalidregex");searchBox.title="Valid regex";}catch(ex){regexValid=false;replaceClass(searchBox,"invalidregex","validregex");searchBox.title="Invalid regex: "+(ex.message?ex.message:(ex.description?ex.description:"unknown error"));return;}}else{searchBox.title="";removeClass(searchBox,"validregex");removeClass(searchBox,"invalidregex");}','addClass(document.body,"searching");currentSearch=new Search(searchTerm,isRegex,searchRegex,isCaseSensitive);for(i=0;i<logEntries.length;i++){currentSearch.applyTo(logEntries[i]);}','setLogContainerHeight();if(currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}else{displayNoMatches();}}}','function updateSearchFromFilters(){if(currentSearch){if(currentSearch.hasMatches()){if(currentMatchIndex===null){currentMatchIndex=0;}','var currentMatch=currentSearch.matches[currentMatchIndex];if(currentMatch.isVisible()){displayMatches();setCurrentMatchIndex(currentMatchIndex);}else{currentMatch.setNotCurrent();var nextVisibleMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextVisibleMatchIndex>-1){setCurrentMatchIndex(nextVisibleMatchIndex);displayMatches();}else{displayNoMatches();}}}else{displayNoMatches();}}}','function refreshCurrentMatch(){if(currentSearch&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(currentMatchIndex);}}','function displayMatches(){replaceClass($("searchBox"),"hasmatches","nomatches");$("searchBox").title=""+currentSearch.matches.length+" matches found";$("searchNav").style.display="block";setLogContainerHeight();}','function displayNoMatches(){replaceClass($("searchBox"),"nomatches","hasmatches");$("searchBox").title="No matches found";$("searchNav").style.display="none";setLogContainerHeight();}','function toggleSearchEnabled(enable){enable=(typeof enable=="undefined")?!$("searchDisable").checked:enable;$("searchBox").disabled=!enable;$("searchReset").disabled=!enable;$("searchRegex").disabled=!enable;$("searchNext").disabled=!enable;$("searchPrevious").disabled=!enable;$("searchCaseSensitive").disabled=!enable;$("searchNav").style.display=(enable&&($("searchBox").value!=="")&&currentSearch&&currentSearch.hasVisibleMatches())?"block":"none";if(enable){removeClass($("search"),"greyedout");addClass(document.body,"searching");if($("searchHighlight").checked){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}','if($("searchFilter").checked){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}','$("searchDisable").checked=!enable;}else{addClass($("search"),"greyedout");removeClass(document.body,"searching");removeClass(logMainContainer,"searchhighlight");removeClass(logMainContainer,"searchfilter");}','setLogContainerHeight();}','function toggleSearchFilter(){var enable=$("searchFilter").checked;if(enable){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}','refreshCurrentMatch();}','function toggleSearchHighlight(){var enable=$("searchHighlight").checked;if(enable){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}}','function clearSearch(){$("searchBox").value="";doSearch();}','function searchNext(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var nextMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextMatchIndex>currentMatchIndex||confirm("Reached the end of the page. Start from the top?")){setCurrentMatchIndex(nextMatchIndex);}}}','function searchPrevious(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var previousMatchIndex=currentSearch.getPreviousVisibleMatchIndex();if(previousMatchIndex<currentMatchIndex||confirm("Reached the start of the page. Continue from the bottom?")){setCurrentMatchIndex(previousMatchIndex);}}}','function setCurrentMatchIndex(index){currentMatchIndex=index;currentSearch.matches[currentMatchIndex].setCurrent();}','function addClass(el,cssClass){if(!hasClass(el,cssClass)){if(el.className){el.className+=" "+cssClass;}else{el.className=cssClass;}}}','function hasClass(el,cssClass){if(el.className){var classNames=el.className.split(" ");return array_contains(classNames,cssClass);}','return false;}','function removeClass(el,cssClass){if(hasClass(el,cssClass)){var existingClasses=el.className.split(" ");var newClasses=[];for(var i=0,len=existingClasses.length;i<len;i++){if(existingClasses[i]!=cssClass){newClasses[newClasses.length]=existingClasses[i];}}','el.className=newClasses.join(" ");}}','function replaceClass(el,newCssClass,oldCssClass){removeClass(el,oldCssClass);addClass(el,newCssClass);}','function getElementsByClass(el,cssClass,tagName){var elements=el.getElementsByTagName(tagName);var matches=[];for(var i=0,len=elements.length;i<len;i++){if(hasClass(elements[i],cssClass)){matches.push(elements[i]);}}','return matches;}','function $(id){return document.getElementById(id);}','function isDescendant(node,ancestorNode){while(node!=null){if(node===ancestorNode){return true;}','node=node.parentNode;}','return false;}','function isOrphan(node){var currentNode=node;while(currentNode){if(currentNode==document.body){return false;}','currentNode=currentNode.parentNode;}','return true;}','function escapeHtml(str){return str.replace(/&/g,"&amp;").replace(/[<]/g,"&lt;").replace(/>/g,"&gt;");}','function getWindowWidth(){if(window.innerWidth){return window.innerWidth;}else if(document.documentElement&&document.documentElement.clientWidth){return document.documentElement.clientWidth;}else if(document.body){return document.body.clientWidth;}','return 0;}','function getWindowHeight(){if(window.innerHeight){return window.innerHeight;}else if(document.documentElement&&document.documentElement.clientHeight){return document.documentElement.clientHeight;}else if(document.body){return document.body.clientHeight;}','return 0;}','function getToolBarsHeight(){return $("switches").offsetHeight;}','function getChromeHeight(){var height=getToolBarsHeight();if(showCommandLine){height+=$("commandLine").offsetHeight;}','return height;}','function setLogContainerHeight(){if(logMainContainer){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";logMainContainer.style.height=""+','Math.max(0,windowHeight-getChromeHeight())+"px";}}','function setCommandInputWidth(){if(showCommandLine){$("command").style.width=""+Math.max(0,$("commandLineContainer").offsetWidth-','($("evaluateButton").offsetWidth+13))+"px";}}','window.onresize=function(){setCommandInputWidth();setLogContainerHeight();};if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}','return this.length;};}','if(!Array.prototype.pop){Array.prototype.pop=function(){if(this.length>0){var val=this[this.length-1];this.length=this.length-1;return val;}};}','if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}','this.length=this.length-1;return firstItem;}};}','if(!Array.prototype.splice){Array.prototype.splice=function(startIndex,deleteCount){var itemsAfterDeleted=this.slice(startIndex+deleteCount);var itemsDeleted=this.slice(startIndex,startIndex+deleteCount);this.length=startIndex;var argumentsArray=[];for(var i=0,len=arguments.length;i<len;i++){argumentsArray[i]=arguments[i];}','var itemsToAppend=(argumentsArray.length>2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i<len;i++){this.push(itemsToAppend[i]);}','return itemsDeleted;};}','function array_remove(arr,val){var index=-1;for(var i=0,len=arr.length;i<len;i++){if(arr[i]===val){index=i;break;}}','if(index>=0){arr.splice(index,1);return index;}else{return false;}}','function array_removeFromStart(array,numberToRemove){if(Array.prototype.splice){array.splice(0,numberToRemove);}else{for(var i=numberToRemove,len=array.length;i<len;i++){array[i-numberToRemove]=array[i];}','array.length=array.length-numberToRemove;}','return array;}','function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}','return false;}','function getErrorMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}','return""+ex;}','function moveCaretToEnd(input){if(input.setSelectionRange){input.focus();var length=input.value.length;input.setSelectionRange(length,length);}else if(input.createTextRange){var range=input.createTextRange();range.collapse(false);range.select();}','input.focus();}','function stopPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}}','function getEvent(evt){return evt?evt:event;}','function getTarget(evt){return evt.target?evt.target:evt.srcElement;}','function getRelatedTarget(evt){if(evt.relatedTarget){return evt.relatedTarget;}else if(evt.srcElement){switch(evt.type){case"mouseover":return evt.fromElement;case"mouseout":return evt.toElement;default:return evt.srcElement;}}}','function cancelKeyEvent(evt){evt.returnValue=false;stopPropagation(evt);}','function evalCommandLine(){var expr=$("command").value;evalCommand(expr);$("command").value="";}','function evalLastCommand(){if(lastCommand!=null){evalCommand(lastCommand);}}','var lastCommand=null;var commandHistory=[];var currentCommandIndex=0;function evalCommand(expr){if(appender){appender.evalCommandAndAppend(expr);}else{var prefix=">>> "+expr+"\\r\\n";try{log("INFO",prefix+eval(expr));}catch(ex){log("ERROR",prefix+"Error: "+getErrorMessage(ex));}}','if(expr!=commandHistory[commandHistory.length-1]){commandHistory.push(expr);if(appender){appender.storeCommandHistory(commandHistory);}}','currentCommandIndex=(expr==commandHistory[currentCommandIndex])?currentCommandIndex+1:commandHistory.length;lastCommand=expr;}','//]]>','</script>','<style type="text/css">','body{background-color:white;color:black;padding:0;margin:0;font-family:tahoma,verdana,arial,helvetica,sans-serif;overflow:hidden}div#switchesContainer input{margin-bottom:0}div.toolbar{border-top:solid #ffffff 1px;border-bottom:solid #aca899 1px;background-color:#f1efe7;padding:3px 5px;font-size:68.75%}div.toolbar,div#search input{font-family:tahoma,verdana,arial,helvetica,sans-serif}div.toolbar input.button{padding:0 5px;font-size:100%}div.toolbar input.hidden{display:none}div#switches input#clearButton{margin-left:20px}div#levels label{font-weight:bold}div#levels label,div#options label{margin-right:5px}div#levels label#wrapLabel{font-weight:normal}div#search label{margin-right:10px}div#search label.searchboxlabel{margin-right:0}div#search input{font-size:100%}div#search input.validregex{color:green}div#search input.invalidregex{color:red}div#search input.nomatches{color:white;background-color:#ff6666}div#search input.nomatches{color:white;background-color:#ff6666}div#searchNav{display:none}div#commandLine{display:none}div#commandLine input#command{font-size:100%;font-family:Courier New,Courier}div#commandLine input#evaluateButton{}*.greyedout{color:gray !important;border-color:gray !important}*.greyedout *.alwaysenabled{color:black}*.unselectable{-khtml-user-select:none;-moz-user-select:none;user-select:none}div#log{font-family:Courier New,Courier;font-size:75%;width:100%;overflow:auto;clear:both;position:relative}div.group{border-color:#cccccc;border-style:solid;border-width:1px 0 1px 1px;overflow:visible}div.oldIe div.group,div.oldIe div.group *,div.oldIe *.logentry{height:1%}div.group div.groupheading span.expander{border:solid black 1px;font-family:Courier New,Courier;font-size:0.833em;background-color:#eeeeee;position:relative;top:-1px;color:black;padding:0 2px;cursor:pointer;cursor:hand;height:1%}div.group div.groupcontent{margin-left:10px;padding-bottom:2px;overflow:visible}div.group div.expanded{display:block}div.group div.collapsed{display:none}*.logentry{overflow:visible;display:none;white-space:pre}span.pre{white-space:pre}pre.unwrapped{display:inline !important}pre.unwrapped pre.pre,div.wrapped pre.pre{display:inline}div.wrapped pre.pre{white-space:normal}div.wrapped{display:none}body.searching *.logentry span.currentmatch{color:white !important;background-color:green !important}body.searching div.searchhighlight *.logentry span.searchterm{color:black;background-color:yellow}div.wrap *.logentry{white-space:normal !important;border-width:0 0 1px 0;border-color:#dddddd;border-style:dotted}div.wrap #log_wrapped,#log_unwrapped{display:block}div.wrap #log_unwrapped,#log_wrapped{display:none}div.wrap *.logentry span.pre{overflow:visible;white-space:normal}div.wrap *.logentry pre.unwrapped{display:none}div.wrap *.logentry span.wrapped{display:inline}div.searchfilter *.searchnonmatch{display:none !important}div#log *.TRACE,label#label_TRACE{color:#666666}div#log *.DEBUG,label#label_DEBUG{color:green}div#log *.INFO,label#label_INFO{color:#000099}div#log *.WARN,label#label_WARN{color:#999900}div#log *.ERROR,label#label_ERROR{color:red}div#log *.FATAL,label#label_FATAL{color:#660066}div.TRACE#log *.TRACE,div.DEBUG#log *.DEBUG,div.INFO#log *.INFO,div.WARN#log *.WARN,div.ERROR#log *.ERROR,div.FATAL#log *.FATAL{display:block}div#log div.separator{background-color:#cccccc;margin:5px 0;line-height:1px}','</style>','</head>','<body id="body">','<div id="switchesContainer">','<div id="switches">','<div id="levels" class="toolbar">','Filters:','<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>','<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>','<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>','<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>','<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>','<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>','<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>','</div>','<div id="search" class="toolbar">','<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />','<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />','<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>','<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>','<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>','<div id="searchNav">','<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />','<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />','<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>','<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>','</div>','</div>','<div id="options" class="toolbar">','Options:','<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>','<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>','<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>','<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>','<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />','<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />','<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />','</div>','</div>','</div>','<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>','<div id="commandLine" class="toolbar">','<div id="commandLineContainer">','<input type="text" id="command" title="Enter a JavaScript command here and hit return or press \'Evaluate\'" />','<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />','</div>','</div>','</body>','</html>',''];};var defaultCommandLineFunctions=[];ConsoleAppender=function(){};var consoleAppenderIdCounter=1;ConsoleAppender.prototype=new Appender();ConsoleAppender.prototype.create=function(inPage,container,lazyInit,initiallyMinimized,useDocumentWrite,width,height,focusConsoleWindow){var appender=this;var initialized=false;var consoleWindowCreated=false;var consoleWindowLoaded=false;var consoleClosed=false;var queuedLoggingEvents=[];var isSupported=true;var consoleAppenderId=consoleAppenderIdCounter++;initiallyMinimized=extractBooleanFromParam(initiallyMinimized,this.defaults.initiallyMinimized);lazyInit=extractBooleanFromParam(lazyInit,this.defaults.lazyInit);useDocumentWrite=extractBooleanFromParam(useDocumentWrite,this.defaults.useDocumentWrite);var newestMessageAtTop=this.defaults.newestMessageAtTop;var scrollToLatestMessage=this.defaults.scrollToLatestMessage;width=width?width:this.defaults.width;height=height?height:this.defaults.height;var maxMessages=this.defaults.maxMessages;var showCommandLine=this.defaults.showCommandLine;var commandLineObjectExpansionDepth=this.defaults.commandLineObjectExpansionDepth;var showHideButton=this.defaults.showHideButton;var showCloseButton=this.defaults.showCloseButton;var showLogEntryDeleteButtons=this.defaults.showLogEntryDeleteButtons;this.setLayout(this.defaults.layout);var init,createWindow,safeToAppend,getConsoleWindow,open;var appenderName=inPage?"InPageAppender":"PopUpAppender";var checkCanConfigure=function(configOptionName){if(consoleWindowCreated){handleError(appenderName+": configuration option '"+configOptionName+"' may not be set after the appender has been initialized");return false;}

+return true;};var consoleWindowExists=function(){return(consoleWindowLoaded&&isSupported&&!consoleClosed);};this.isNewestMessageAtTop=function(){return newestMessageAtTop;};this.setNewestMessageAtTop=function(newestMessageAtTopParam){newestMessageAtTop=bool(newestMessageAtTopParam);if(consoleWindowExists()){getConsoleWindow().setNewestAtTop(newestMessageAtTop);}};this.isScrollToLatestMessage=function(){return scrollToLatestMessage;};this.setScrollToLatestMessage=function(scrollToLatestMessageParam){scrollToLatestMessage=bool(scrollToLatestMessageParam);if(consoleWindowExists()){getConsoleWindow().setScrollToLatest(scrollToLatestMessage);}};this.getWidth=function(){return width;};this.setWidth=function(widthParam){if(checkCanConfigure("width")){width=extractStringFromParam(widthParam,width);}};this.getHeight=function(){return height;};this.setHeight=function(heightParam){if(checkCanConfigure("height")){height=extractStringFromParam(heightParam,height);}};this.getMaxMessages=function(){return maxMessages;};this.setMaxMessages=function(maxMessagesParam){maxMessages=extractIntFromParam(maxMessagesParam,maxMessages);if(consoleWindowExists()){getConsoleWindow().setMaxMessages(maxMessages);}};this.isShowCommandLine=function(){return showCommandLine;};this.setShowCommandLine=function(showCommandLineParam){showCommandLine=bool(showCommandLineParam);if(consoleWindowExists()){getConsoleWindow().setShowCommandLine(showCommandLine);}};this.isShowHideButton=function(){return showHideButton;};this.setShowHideButton=function(showHideButtonParam){showHideButton=bool(showHideButtonParam);if(consoleWindowExists()){getConsoleWindow().setShowHideButton(showHideButton);}};this.isShowCloseButton=function(){return showCloseButton;};this.setShowCloseButton=function(showCloseButtonParam){showCloseButton=bool(showCloseButtonParam);if(consoleWindowExists()){getConsoleWindow().setShowCloseButton(showCloseButton);}};this.getCommandLineObjectExpansionDepth=function(){return commandLineObjectExpansionDepth;};this.setCommandLineObjectExpansionDepth=function(commandLineObjectExpansionDepthParam){commandLineObjectExpansionDepth=extractIntFromParam(commandLineObjectExpansionDepthParam,commandLineObjectExpansionDepth);};var minimized=initiallyMinimized;this.isInitiallyMinimized=function(){return initiallyMinimized;};this.setInitiallyMinimized=function(initiallyMinimizedParam){if(checkCanConfigure("initiallyMinimized")){initiallyMinimized=bool(initiallyMinimizedParam);minimized=initiallyMinimized;}};this.isUseDocumentWrite=function(){return useDocumentWrite;};this.setUseDocumentWrite=function(useDocumentWriteParam){if(checkCanConfigure("useDocumentWrite")){useDocumentWrite=bool(useDocumentWriteParam);}};function QueuedLoggingEvent(loggingEvent,formattedMessage){this.loggingEvent=loggingEvent;this.levelName=loggingEvent.level.name;this.formattedMessage=formattedMessage;}

+QueuedLoggingEvent.prototype.append=function(){getConsoleWindow().log(this.levelName,this.formattedMessage);};function QueuedGroup(name,initiallyExpanded){this.name=name;this.initiallyExpanded=initiallyExpanded;}

+QueuedGroup.prototype.append=function(){getConsoleWindow().group(this.name,this.initiallyExpanded);};function QueuedGroupEnd(){}

+QueuedGroupEnd.prototype.append=function(){getConsoleWindow().groupEnd();};var checkAndAppend=function(){safeToAppend();if(!initialized){init();}else if(consoleClosed&&reopenWhenClosed){createWindow();}

+if(safeToAppend()){appendQueuedLoggingEvents();}};this.append=function(loggingEvent){if(isSupported){var formattedMessage=appender.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();}

+queuedLoggingEvents.push(new QueuedLoggingEvent(loggingEvent,formattedMessage));checkAndAppend();}};this.group=function(name,initiallyExpanded){if(isSupported){queuedLoggingEvents.push(new QueuedGroup(name,initiallyExpanded));checkAndAppend();}};this.groupEnd=function(){if(isSupported){queuedLoggingEvents.push(new QueuedGroupEnd());checkAndAppend();}};var appendQueuedLoggingEvents=function(){var currentLoggingEvent;while(queuedLoggingEvents.length>0){queuedLoggingEvents.shift().append();}

+if(focusConsoleWindow){getConsoleWindow().focus();}};this.setAddedToLogger=function(logger){this.loggers.push(logger);if(enabled&&!lazyInit){init();}};this.clear=function(){if(consoleWindowExists()){getConsoleWindow().clearLog();}

+queuedLoggingEvents.length=0;};this.focus=function(){if(consoleWindowExists()){getConsoleWindow().focus();}};this.focusCommandLine=function(){if(consoleWindowExists()){getConsoleWindow().focusCommandLine();}};this.focusSearch=function(){if(consoleWindowExists()){getConsoleWindow().focusSearch();}};var commandWindow=window;this.getCommandWindow=function(){return commandWindow;};this.setCommandWindow=function(commandWindowParam){commandWindow=commandWindowParam;};this.executeLastCommand=function(){if(consoleWindowExists()){getConsoleWindow().evalLastCommand();}};var commandLayout=new PatternLayout("%m");this.getCommandLayout=function(){return commandLayout;};this.setCommandLayout=function(commandLayoutParam){commandLayout=commandLayoutParam;};this.evalCommandAndAppend=function(expr){var commandReturnValue={appendResult:true,isError:false};var commandOutput="";try{var result,i;if(!commandWindow.eval&&commandWindow.execScript){commandWindow.execScript("null");}

+var commandLineFunctionsHash={};for(i=0,len=commandLineFunctions.length;i<len;i++){commandLineFunctionsHash[commandLineFunctions[i][0]]=commandLineFunctions[i][1];}

+var objectsToRestore=[];var addObjectToRestore=function(name){objectsToRestore.push([name,commandWindow[name]]);};addObjectToRestore("appender");commandWindow.appender=appender;addObjectToRestore("commandReturnValue");commandWindow.commandReturnValue=commandReturnValue;addObjectToRestore("commandLineFunctionsHash");commandWindow.commandLineFunctionsHash=commandLineFunctionsHash;var addFunctionToWindow=function(name){addObjectToRestore(name);commandWindow[name]=function(){return this.commandLineFunctionsHash[name](appender,arguments,commandReturnValue);};};for(i=0,len=commandLineFunctions.length;i<len;i++){addFunctionToWindow(commandLineFunctions[i][0]);}

+if(commandWindow===window&&commandWindow.execScript){addObjectToRestore("evalExpr");addObjectToRestore("result");window.evalExpr=expr;commandWindow.execScript("window.result=eval(window.evalExpr);");result=window.result;}else{result=commandWindow.eval(expr);}

+commandOutput=isUndefined(result)?result:formatObjectExpansion(result,commandLineObjectExpansionDepth);for(i=0,len=objectsToRestore.length;i<len;i++){commandWindow[objectsToRestore[i][0]]=objectsToRestore[i][1];}}catch(ex){commandOutput="Error evaluating command: "+getExceptionStringRep(ex);commandReturnValue.isError=true;}

+if(commandReturnValue.appendResult){var message=">>> "+expr;if(!isUndefined(commandOutput)){message+=newLine+commandOutput;}

+var level=commandReturnValue.isError?Level.ERROR:Level.INFO;var loggingEvent=new LoggingEvent(null,new Date(),level,[message],null);var mainLayout=this.getLayout();this.setLayout(commandLayout);this.append(loggingEvent);this.setLayout(mainLayout);}};var commandLineFunctions=defaultCommandLineFunctions.concat([]);this.addCommandLineFunction=function(functionName,commandLineFunction){commandLineFunctions.push([functionName,commandLineFunction]);};var commandHistoryCookieName="log4javascriptCommandHistory";this.storeCommandHistory=function(commandHistory){setCookie(commandHistoryCookieName,commandHistory.join(","));};var writeHtml=function(doc){var lines=getConsoleHtmlLines();doc.open();for(var i=0,len=lines.length;i<len;i++){doc.writeln(lines[i]);}

+doc.close();};this.setEventTypes(["load","unload"]);var consoleWindowLoadHandler=function(){var win=getConsoleWindow();win.setAppender(appender);win.setNewestAtTop(newestMessageAtTop);win.setScrollToLatest(scrollToLatestMessage);win.setMaxMessages(maxMessages);win.setShowCommandLine(showCommandLine);win.setShowHideButton(showHideButton);win.setShowCloseButton(showCloseButton);win.setMainWindow(window);var storedValue=getCookie(commandHistoryCookieName);if(storedValue){win.commandHistory=storedValue.split(",");win.currentCommandIndex=win.commandHistory.length;}

+appender.dispatchEvent("load",{"win":win});};this.unload=function(){logLog.debug("unload "+this+", caller: "+this.unload.caller);if(!consoleClosed){logLog.debug("really doing unload "+this);consoleClosed=true;consoleWindowLoaded=false;consoleWindowCreated=false;appender.dispatchEvent("unload",{});}};var pollConsoleWindow=function(windowTest,interval,successCallback,errorMessage){function doPoll(){try{if(consoleClosed){clearInterval(poll);}

+if(windowTest(getConsoleWindow())){clearInterval(poll);successCallback();}}catch(ex){clearInterval(poll);isSupported=false;handleError(errorMessage,ex);}}

+var poll=setInterval(doPoll,interval);};var getConsoleUrl=function(){var documentDomainSet=(document.domain!=location.hostname);return useDocumentWrite?"":getBaseUrl()+"console.html"+

+(documentDomainSet?"?log4javascript_domain="+escape(document.domain):"");};if(inPage){var containerElement=null;var cssProperties=[];this.addCssProperty=function(name,value){if(checkCanConfigure("cssProperties")){cssProperties.push([name,value]);}};var windowCreationStarted=false;var iframeContainerDiv;var iframeId=uniqueId+"_InPageAppender_"+consoleAppenderId;this.hide=function(){if(initialized&&consoleWindowCreated){if(consoleWindowExists()){getConsoleWindow().$("command").blur();}

+iframeContainerDiv.style.display="none";minimized=true;}};this.show=function(){if(initialized){if(consoleWindowCreated){iframeContainerDiv.style.display="block";this.setShowCommandLine(showCommandLine);minimized=false;}else if(!windowCreationStarted){createWindow(true);}}};this.isVisible=function(){return!minimized&&!consoleClosed;};this.close=function(fromButton){if(!consoleClosed&&(!fromButton||confirm("This will permanently remove the console from the page. No more messages will be logged. Do you wish to continue?"))){iframeContainerDiv.parentNode.removeChild(iframeContainerDiv);this.unload();}};open=function(){var initErrorMessage="InPageAppender.open: unable to create console iframe";function finalInit(){try{if(!initiallyMinimized){appender.show();}

+consoleWindowLoadHandler();consoleWindowLoaded=true;appendQueuedLoggingEvents();}catch(ex){isSupported=false;handleError(initErrorMessage,ex);}}

+function writeToDocument(){try{var windowTest=function(win){return isLoaded(win);};if(useDocumentWrite){writeHtml(getConsoleWindow().document);}

+if(windowTest(getConsoleWindow())){finalInit();}else{pollConsoleWindow(windowTest,100,finalInit,initErrorMessage);}}catch(ex){isSupported=false;handleError(initErrorMessage,ex);}}

+minimized=false;iframeContainerDiv=containerElement.appendChild(document.createElement("div"));iframeContainerDiv.style.width=width;iframeContainerDiv.style.height=height;iframeContainerDiv.style.border="solid gray 1px";for(var i=0,len=cssProperties.length;i<len;i++){iframeContainerDiv.style[cssProperties[i][0]]=cssProperties[i][1];}

+var iframeSrc=useDocumentWrite?"":" src='"+getConsoleUrl()+"'";iframeContainerDiv.innerHTML="<iframe id='"+iframeId+"' name='"+iframeId+"' width='100%' height='100%' frameborder='0'"+iframeSrc+" scrolling='no'></iframe>";consoleClosed=false;var iframeDocumentExistsTest=function(win){try{return bool(win)&&bool(win.document);}catch(ex){return false;}};if(iframeDocumentExistsTest(getConsoleWindow())){writeToDocument();}else{pollConsoleWindow(iframeDocumentExistsTest,100,writeToDocument,initErrorMessage);}

+consoleWindowCreated=true;};createWindow=function(show){if(show||!initiallyMinimized){var pageLoadHandler=function(){if(!container){containerElement=document.createElement("div");containerElement.style.position="fixed";containerElement.style.left="0";containerElement.style.right="0";containerElement.style.bottom="0";document.body.appendChild(containerElement);appender.addCssProperty("borderWidth","1px 0 0 0");appender.addCssProperty("zIndex",1000000);open();}else{try{var el=document.getElementById(container);if(el.nodeType==1){containerElement=el;}

+open();}catch(ex){handleError("InPageAppender.init: invalid container element '"+container+"' supplied",ex);}}};if(pageLoaded&&container&&container.appendChild){containerElement=container;open();}else if(pageLoaded){pageLoadHandler();}else{log4javascript.addEventListener("load",pageLoadHandler);}

+windowCreationStarted=true;}};init=function(){createWindow();initialized=true;};getConsoleWindow=function(){var iframe=window.frames[iframeId];if(iframe){return iframe;}};safeToAppend=function(){if(isSupported&&!consoleClosed){if(consoleWindowCreated&&!consoleWindowLoaded&&getConsoleWindow()&&isLoaded(getConsoleWindow())){consoleWindowLoaded=true;}

+return consoleWindowLoaded;}

+return false;};}else{var useOldPopUp=appender.defaults.useOldPopUp;var complainAboutPopUpBlocking=appender.defaults.complainAboutPopUpBlocking;var reopenWhenClosed=this.defaults.reopenWhenClosed;this.isUseOldPopUp=function(){return useOldPopUp;};this.setUseOldPopUp=function(useOldPopUpParam){if(checkCanConfigure("useOldPopUp")){useOldPopUp=bool(useOldPopUpParam);}};this.isComplainAboutPopUpBlocking=function(){return complainAboutPopUpBlocking;};this.setComplainAboutPopUpBlocking=function(complainAboutPopUpBlockingParam){if(checkCanConfigure("complainAboutPopUpBlocking")){complainAboutPopUpBlocking=bool(complainAboutPopUpBlockingParam);}};this.isFocusPopUp=function(){return focusConsoleWindow;};this.setFocusPopUp=function(focusPopUpParam){focusConsoleWindow=bool(focusPopUpParam);};this.isReopenWhenClosed=function(){return reopenWhenClosed;};this.setReopenWhenClosed=function(reopenWhenClosedParam){reopenWhenClosed=bool(reopenWhenClosedParam);};this.close=function(){logLog.debug("close "+this);try{popUp.close();this.unload();}catch(ex){}};this.hide=function(){logLog.debug("hide "+this);if(consoleWindowExists()){this.close();}};this.show=function(){logLog.debug("show "+this);if(!consoleWindowCreated){open();}};this.isVisible=function(){return safeToAppend();};var popUp;open=function(){var windowProperties="width="+width+",height="+height+",status,resizable";var frameInfo="";try{var frameEl=window.frameElement;if(frameEl){frameInfo="_"+frameEl.tagName+"_"+(frameEl.name||frameEl.id||"");}}catch(e){frameInfo="_inaccessibleParentFrame";}

+var windowName="PopUp_"+location.host.replace(/[^a-z0-9]/gi,"_")+"_"+consoleAppenderId+frameInfo;if(!useOldPopUp||!useDocumentWrite){windowName=windowName+"_"+uniqueId;}

+var checkPopUpClosed=function(win){if(consoleClosed){return true;}else{try{return bool(win)&&win.closed;}catch(ex){}}

+return false;};var popUpClosedCallback=function(){if(!consoleClosed){appender.unload();}};function finalInit(){getConsoleWindow().setCloseIfOpenerCloses(!useOldPopUp||!useDocumentWrite);consoleWindowLoadHandler();consoleWindowLoaded=true;appendQueuedLoggingEvents();pollConsoleWindow(checkPopUpClosed,500,popUpClosedCallback,"PopUpAppender.checkPopUpClosed: error checking pop-up window");}

+try{popUp=window.open(getConsoleUrl(),windowName,windowProperties);consoleClosed=false;consoleWindowCreated=true;if(popUp&&popUp.document){if(useDocumentWrite&&useOldPopUp&&isLoaded(popUp)){popUp.mainPageReloaded();finalInit();}else{if(useDocumentWrite){writeHtml(popUp.document);}

+var popUpLoadedTest=function(win){return bool(win)&&isLoaded(win);};if(isLoaded(popUp)){finalInit();}else{pollConsoleWindow(popUpLoadedTest,100,finalInit,"PopUpAppender.init: unable to create console window");}}}else{isSupported=false;logLog.warn("PopUpAppender.init: pop-ups blocked, please unblock to use PopUpAppender");if(complainAboutPopUpBlocking){handleError("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");}}}catch(ex){handleError("PopUpAppender.init: error creating pop-up",ex);}};createWindow=function(){if(!initiallyMinimized){open();}};init=function(){createWindow();initialized=true;};getConsoleWindow=function(){return popUp;};safeToAppend=function(){if(isSupported&&!isUndefined(popUp)&&!consoleClosed){if(popUp.closed||(consoleWindowLoaded&&isUndefined(popUp.closed))){appender.unload();logLog.debug("PopUpAppender: pop-up closed");return false;}

+if(!consoleWindowLoaded&&isLoaded(popUp)){consoleWindowLoaded=true;}}

+return isSupported&&consoleWindowLoaded&&!consoleClosed;};}

+this.getConsoleWindow=getConsoleWindow;};ConsoleAppender.addGlobalCommandLineFunction=function(functionName,commandLineFunction){defaultCommandLineFunctions.push([functionName,commandLineFunction]);};function PopUpAppender(lazyInit,initiallyMinimized,useDocumentWrite,width,height){this.create(false,null,lazyInit,initiallyMinimized,useDocumentWrite,width,height,this.defaults.focusPopUp);}

+PopUpAppender.prototype=new ConsoleAppender();PopUpAppender.prototype.defaults={layout:new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),initiallyMinimized:false,focusPopUp:false,lazyInit:true,useOldPopUp:true,complainAboutPopUpBlocking:true,newestMessageAtTop:false,scrollToLatestMessage:true,width:"600",height:"400",reopenWhenClosed:false,maxMessages:null,showCommandLine:true,commandLineObjectExpansionDepth:1,showHideButton:false,showCloseButton:true,showLogEntryDeleteButtons:true,useDocumentWrite:true};PopUpAppender.prototype.toString=function(){return"PopUpAppender";};log4javascript.PopUpAppender=PopUpAppender;function InPageAppender(container,lazyInit,initiallyMinimized,useDocumentWrite,width,height){this.create(true,container,lazyInit,initiallyMinimized,useDocumentWrite,width,height,false);}

+InPageAppender.prototype=new ConsoleAppender();InPageAppender.prototype.defaults={layout:new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),initiallyMinimized:false,lazyInit:true,newestMessageAtTop:false,scrollToLatestMessage:true,width:"100%",height:"220px",maxMessages:null,showCommandLine:true,commandLineObjectExpansionDepth:1,showHideButton:false,showCloseButton:false,showLogEntryDeleteButtons:true,useDocumentWrite:true};InPageAppender.prototype.toString=function(){return"InPageAppender";};log4javascript.InPageAppender=InPageAppender;log4javascript.InlineAppender=InPageAppender;})();function padWithSpaces(str,len){if(str.length<len){var spaces=[];var numberOfSpaces=Math.max(0,len-str.length);for(var i=0;i<numberOfSpaces;i++){spaces[i]=" ";}

+str+=spaces.join("");}

+return str;}

+(function(){function dir(obj){var maxLen=0;for(var p in obj){maxLen=Math.max(toStr(p).length,maxLen);}

+var propList=[];for(p in obj){var propNameStr="  "+padWithSpaces(toStr(p),maxLen+2);var propVal;try{propVal=splitIntoLines(toStr(obj[p])).join(padWithSpaces(newLine,maxLen+6));}catch(ex){propVal="[Error obtaining property. Details: "+getExceptionMessage(ex)+"]";}

+propList.push(propNameStr+propVal);}

+return propList.join(newLine);}

+var nodeTypes={ELEMENT_NODE:1,ATTRIBUTE_NODE:2,TEXT_NODE:3,CDATA_SECTION_NODE:4,ENTITY_REFERENCE_NODE:5,ENTITY_NODE:6,PROCESSING_INSTRUCTION_NODE:7,COMMENT_NODE:8,DOCUMENT_NODE:9,DOCUMENT_TYPE_NODE:10,DOCUMENT_FRAGMENT_NODE:11,NOTATION_NODE:12};var preFormattedElements=["script","pre"];var emptyElements=["br","img","hr","param","link","area","input","col","base","meta"];var indentationUnit="  ";function getXhtml(rootNode,includeRootNode,indentation,startNewLine,preformatted){includeRootNode=(typeof includeRootNode=="undefined")?true:!!includeRootNode;if(typeof indentation!="string"){indentation="";}

+startNewLine=!!startNewLine;preformatted=!!preformatted;var xhtml;function isWhitespace(node){return((node.nodeType==nodeTypes.TEXT_NODE)&&/^[ \t\r\n]*$/.test(node.nodeValue));}

+function fixAttributeValue(attrValue){return attrValue.toString().replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/"/g,"&quot;");}

+function getStyleAttributeValue(el){var stylePairs=el.style.cssText.split(";");var styleValue="";var isFirst=true;for(var j=0,len=stylePairs.length;j<len;j++){var nameValueBits=stylePairs[j].split(":");var props=[];if(!/^\s*$/.test(nameValueBits[0])){props.push(trim(nameValueBits[0]).toLowerCase()+":"+trim(nameValueBits[1]));}

+styleValue=props.join(";");}

+return styleValue;}

+function getNamespace(el){if(el.prefix){return el.prefix;}else if(el.outerHTML){var regex=new RegExp("<([^:]+):"+el.tagName+"[^>]*>","i");if(regex.test(el.outerHTML)){return RegExp.$1.toLowerCase();}}

+return"";}

+var lt="<";var gt=">";if(includeRootNode&&rootNode.nodeType!=nodeTypes.DOCUMENT_FRAGMENT_NODE){switch(rootNode.nodeType){case nodeTypes.ELEMENT_NODE:var tagName=rootNode.tagName.toLowerCase();xhtml=startNewLine?newLine+indentation:"";xhtml+=lt;var prefix=getNamespace(rootNode);var hasPrefix=!!prefix;if(hasPrefix){xhtml+=prefix+":";}

+xhtml+=tagName;for(i=0,len=rootNode.attributes.length;i<len;i++){var currentAttr=rootNode.attributes[i];if(!currentAttr.specified||currentAttr.nodeValue===null||currentAttr.nodeName.toLowerCase()==="style"||typeof currentAttr.nodeValue!=="string"||currentAttr.nodeName.indexOf("_moz")===0){continue;}

+xhtml+=" "+currentAttr.nodeName.toLowerCase()+"=\"";xhtml+=fixAttributeValue(currentAttr.nodeValue);xhtml+="\"";}

+if(rootNode.style.cssText){var styleValue=getStyleAttributeValue(rootNode);if(styleValue!==""){xhtml+=" style=\""+getStyleAttributeValue(rootNode)+"\"";}}

+if(array_contains(emptyElements,tagName)||(hasPrefix&&!rootNode.hasChildNodes())){xhtml+="/"+gt;}else{xhtml+=gt;var childStartNewLine=!(rootNode.childNodes.length===1&&rootNode.childNodes[0].nodeType===nodeTypes.TEXT_NODE);var childPreformatted=array_contains(preFormattedElements,tagName);for(var i=0,len=rootNode.childNodes.length;i<len;i++){xhtml+=getXhtml(rootNode.childNodes[i],true,indentation+indentationUnit,childStartNewLine,childPreformatted);}

+var endTag=lt+"/"+tagName+gt;xhtml+=childStartNewLine?newLine+indentation+endTag:endTag;}

+return xhtml;case nodeTypes.TEXT_NODE:if(isWhitespace(rootNode)){xhtml="";}else{if(preformatted){xhtml=rootNode.nodeValue;}else{var lines=splitIntoLines(trim(rootNode.nodeValue));var trimmedLines=[];for(var i=0,len=lines.length;i<len;i++){trimmedLines[i]=trim(lines[i]);}

+xhtml=trimmedLines.join(newLine+indentation);}

+if(startNewLine){xhtml=newLine+indentation+xhtml;}}

+return xhtml;case nodeTypes.CDATA_SECTION_NODE:return"<![CDA"+"TA["+rootNode.nodeValue+"]"+"]>"+newLine;case nodeTypes.DOCUMENT_NODE:xhtml="";for(var i=0,len=rootNode.childNodes.length;i<len;i++){xhtml+=getXhtml(rootNode.childNodes[i],true,indentation);}

+return xhtml;default:return"";}}else{xhtml="";for(var i=0,len=rootNode.childNodes.length;i<len;i++){xhtml+=getXhtml(rootNode.childNodes[i],true,indentation+indentationUnit);}

+return xhtml;}}

+function createCommandLineFunctions(){ConsoleAppender.addGlobalCommandLineFunction("$",function(appender,args,returnValue){return document.getElementById(args[0]);});ConsoleAppender.addGlobalCommandLineFunction("dir",function(appender,args,returnValue){var lines=[];for(var i=0,len=args.length;i<len;i++){lines[i]=dir(args[i]);}

+return lines.join(newLine+newLine);});ConsoleAppender.addGlobalCommandLineFunction("dirxml",function(appender,args,returnValue){var lines=[];for(var i=0,len=args.length;i<len;i++){var win=appender.getCommandWindow();lines[i]=getXhtml(args[i]);}

+return lines.join(newLine+newLine);});ConsoleAppender.addGlobalCommandLineFunction("cd",function(appender,args,returnValue){var win,message;if(args.length===0||args[0]===""){win=window;message="Command line set to run in main window";}else{if(args[0].window==args[0]){win=args[0];message="Command line set to run in frame '"+args[0].name+"'";}else{win=window.frames[args[0]];if(win){message="Command line set to run in frame '"+args[0]+"'";}else{returnValue.isError=true;message="Frame '"+args[0]+"' does not exist";win=appender.getCommandWindow();}}}

+appender.setCommandWindow(win);return message;});ConsoleAppender.addGlobalCommandLineFunction("clear",function(appender,args,returnValue){returnValue.appendResult=false;appender.clear();});ConsoleAppender.addGlobalCommandLineFunction("keys",function(appender,args,returnValue){var keys=[];for(var k in args[0]){keys.push(k);}

+return keys;});ConsoleAppender.addGlobalCommandLineFunction("values",function(appender,args,returnValue){var values=[];for(var k in args[0]){try{values.push(args[0][k]);}catch(ex){logLog.warn("values(): Unable to obtain value for key "+k+". Details: "+getExceptionMessage(ex));}}

+return values;});ConsoleAppender.addGlobalCommandLineFunction("expansionDepth",function(appender,args,returnValue){var expansionDepth=parseInt(args[0],10);if(isNaN(expansionDepth)||expansionDepth<0){returnValue.isError=true;return""+args[0]+" is not a valid expansion depth";}else{appender.setCommandLineObjectExpansionDepth(expansionDepth);return"Object expansion depth set to "+expansionDepth;}});}

+function init(){createCommandLineFunctions();}

+init();})();log4javascript.setDocumentReady=function(){pageLoaded=true;log4javascript.dispatchEvent("load",{});};if(window.addEventListener){window.addEventListener("load",log4javascript.setDocumentReady,false);}else if(window.attachEvent){window.attachEvent("onload",log4javascript.setDocumentReady);}else{var oldOnload=window.onload;if(typeof window.onload!="function"){window.onload=log4javascript.setDocumentReady;}else{window.onload=function(evt){if(oldOnload){oldOnload(evt);}

+log4javascript.setDocumentReady();};}}

+window.log4javascript=log4javascript;return log4javascript;})();

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_lite.js b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_lite.js
new file mode 100644
index 0000000..b04ce8e
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_lite.js
@@ -0,0 +1,55 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}

+this.length--;return firstItem;}};}

+var log4javascript;(function(){var newLine="\r\n";function Log4JavaScript(){}

+log4javascript=new Log4JavaScript();log4javascript.version="1.4.6";log4javascript.edition="log4javascript_lite";function getExceptionMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}else{return String(ex);}}

+function getUrlFileName(url){var lastSlashIndex=Math.max(url.lastIndexOf("/"),url.lastIndexOf("\\"));return url.substr(lastSlashIndex+1);}

+function getExceptionStringRep(ex){if(ex){var exStr="Exception: "+getExceptionMessage(ex);try{if(ex.lineNumber){exStr+=" on line number "+ex.lineNumber;}

+if(ex.fileName){exStr+=" in file "+getUrlFileName(ex.fileName);}}catch(localEx){}

+if(showStackTraces&&ex.stack){exStr+=newLine+"Stack trace:"+newLine+ex.stack;}

+return exStr;}

+return null;}

+function isError(err){return(err instanceof Error);}

+function bool(obj){return Boolean(obj);}

+var enabled=(typeof log4javascript_disabled!="undefined")&&log4javascript_disabled?false:true;log4javascript.setEnabled=function(enable){enabled=bool(enable);};log4javascript.isEnabled=function(){return enabled;};var showStackTraces=false;log4javascript.setShowStackTraces=function(show){showStackTraces=bool(show);};var Level=function(level,name){this.level=level;this.name=name;};Level.prototype={toString:function(){return this.name;},equals:function(level){return this.level==level.level;},isGreaterOrEqual:function(level){return this.level>=level.level;}};Level.ALL=new Level(Number.MIN_VALUE,"ALL");Level.TRACE=new Level(10000,"TRACE");Level.DEBUG=new Level(20000,"DEBUG");Level.INFO=new Level(30000,"INFO");Level.WARN=new Level(40000,"WARN");Level.ERROR=new Level(50000,"ERROR");Level.FATAL=new Level(60000,"FATAL");Level.OFF=new Level(Number.MAX_VALUE,"OFF");log4javascript.Level=Level;function Appender(){var getConsoleHtmlLines=function(){return['<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">','<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">','<head>','<title>log4javascript</title>','<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />','<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->','<meta http-equiv="X-UA-Compatible" content="IE=7" />','<script type="text/javascript">','//<![CDATA[','var loggingEnabled=true;var messagesBeforeDocLoaded=[];function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}','function setLoggingEnabled(enable){loggingEnabled=enable;}','function scrollToLatestEntry(){var l=getLogContainer();if(typeof l.scrollTop!="undefined"){var latestLogEntry=l.lastChild;if(latestLogEntry){l.scrollTop=l.scrollHeight;}}}','function log(logLevel,formattedMessage){if(loggingEnabled){if(loaded){doLog(logLevel,formattedMessage);}else{messagesBeforeDocLoaded.push([logLevel,formattedMessage]);}}}','function doLog(logLevel,formattedMessage){var logEntry=document.createElement("div");logEntry.appendChild(document.createTextNode(formattedMessage));logEntry.className="logentry "+logLevel.name;getLogContainer().appendChild(logEntry);scrollToLatestEntry();}','function mainPageReloaded(){var separator=document.createElement("div");separator.className="separator";separator.innerHTML="&nbsp;";getLogContainer().appendChild(separator);}','var loaded=false;var logLevels=["DEBUG","INFO","WARN","ERROR","FATAL"];window.onload=function(){setLogContainerHeight();toggleLoggingEnabled();for(var i=0;i<messagesBeforeDocLoaded.length;i++){doLog(messagesBeforeDocLoaded[i][0],messagesBeforeDocLoaded[i][1]);}','messagesBeforeDocLoaded=[];loaded=true;setTimeout(setLogContainerHeight,20);};function getLogContainer(){return $("log");}','function clearLog(){getLogContainer().innerHTML="";}','function $(id){return document.getElementById(id);}','function getWindowHeight(){if(window.innerHeight){return window.innerHeight;}else if(document.documentElement&&document.documentElement.clientHeight){return document.documentElement.clientHeight;}else if(document.body){return document.body.clientHeight;}','return 0;}','function getChromeHeight(){return $("toolbar").offsetHeight;}','function setLogContainerHeight(){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";getLogContainer().style.height=""+','Math.max(0,windowHeight-getChromeHeight())+"px";}','window.onresize=function(){setLogContainerHeight();};','//]]>','</script>','<style type="text/css">','body{background-color:white;color:black;padding:0;margin:0;font-family:tahoma,verdana,arial,helvetica,sans-serif;overflow:hidden}div#toolbar{border-top:solid #ffffff 1px;border-bottom:solid #aca899 1px;background-color:#f1efe7;padding:3px 5px;font-size:68.75%}div#toolbar input.button{padding:0 5px;font-size:100%}div#log{font-family:Courier New,Courier;font-size:75%;width:100%;overflow:auto;clear:both}*.logentry{overflow:visible;white-space:pre}*.TRACE{color:#666666}*.DEBUG{color:green}*.INFO{color:#000099}*.WARN{color:#999900}*.ERROR{color:red}*.FATAL{color:#660066}div#log div.separator{background-color:#cccccc;margin:5px 0;line-height:1px}','</style>','</head>','<body id="body">','<div id="toolbar">','Options:','<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" class="stateful" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Enable logging</label>','<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="stateful button" title="Clear all log messages"  />','<input type="button" id="closeButton" value="Close" onclick="window.close()" class="stateful button" title="Close the window" />','</div>','<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>','</body>','</html>'];};var popUp=null;var popUpsBlocked=false;var popUpClosed=false;var popUpLoaded=false;var complainAboutPopUpBlocking=true;var initialized=false;var isSupported=true;var width=600;var height=400;var focusPopUp=false;var queuedLoggingEvents=new Array();function isLoaded(win){try{return bool(win.loaded);}catch(ex){return false;}}

+function finalInit(){popUpLoaded=true;appendQueuedLoggingEvents();}

+function writeHtml(doc){var lines=getConsoleHtmlLines();doc.open();for(var i=0,len=lines.length;i<len;i++){doc.writeln(lines[i]);}

+doc.close();}

+function pollConsoleWindow(){function pollConsoleWindowLoaded(){if(popUpLoaded){clearInterval(poll);}else if(bool(popUp)&&isLoaded(popUp)){clearInterval(poll);finalInit();}}

+var poll=setInterval(pollConsoleWindowLoaded,100);}

+function init(){var windowProperties="width="+width+",height="+height+",status,resizable";var windowName="log4javascriptLitePopUp"+location.host.replace(/[^a-z0-9]/gi,"_");popUp=window.open("",windowName,windowProperties);popUpClosed=false;if(popUp){if(isLoaded(popUp)){popUp.mainPageReloaded();finalInit();}else{writeHtml(popUp.document);if(isLoaded(popUp)){finalInit();}else{pollConsoleWindow();}}}else{isSupported=false;if(complainAboutPopUpBlocking){alert("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");}}

+initialized=true;}

+function safeToAppend(){if(!popUpsBlocked&&!popUpClosed){if(popUp.closed){popUpClosed=true;return false;}

+if(!popUpLoaded&&popUp.loaded){popUpLoaded=true;}}

+return!popUpsBlocked&&popUpLoaded&&!popUpClosed;}

+function padWithZeroes(num,len){var str=""+num;while(str.length<len){str="0"+str;}

+return str;}

+function padWithSpaces(str,len){while(str.length<len){str+=" ";}

+return str;}

+this.append=function(loggingEvent){if(!initialized){init();}

+queuedLoggingEvents.push(loggingEvent);if(safeToAppend()){appendQueuedLoggingEvents();}};function appendQueuedLoggingEvents(){if(safeToAppend()){while(queuedLoggingEvents.length>0){var currentLoggingEvent=queuedLoggingEvents.shift();var date=currentLoggingEvent.timeStamp;var formattedDate=padWithZeroes(date.getHours(),2)+":"+

+padWithZeroes(date.getMinutes(),2)+":"+padWithZeroes(date.getSeconds(),2);var formattedMessage=formattedDate+" "+padWithSpaces(currentLoggingEvent.level.name,5)+" - "+currentLoggingEvent.getCombinedMessages();var throwableStringRep=currentLoggingEvent.getThrowableStrRep();if(throwableStringRep){formattedMessage+=newLine+throwableStringRep;}

+popUp.log(currentLoggingEvent.level,formattedMessage);}

+if(focusPopUp){popUp.focus();}}}}

+log4javascript.Appender=Appender;function Logger(){var appender=new Appender();var loggerLevel=Level.ALL;this.log=function(level,params){if(enabled&&level.isGreaterOrEqual(this.getLevel())){var exception;var finalParamIndex=params.length-1;var lastParam=params[params.length-1];if(params.length>1&&isError(lastParam)){exception=lastParam;finalParamIndex--;}

+var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];}

+var loggingEvent=new LoggingEvent(this,new Date(),level,messages,exception);appender.append(loggingEvent);}};this.setLevel=function(level){loggerLevel=level;};this.getLevel=function(){return loggerLevel;};}

+Logger.prototype={trace:function(){this.log(Level.TRACE,arguments);},debug:function(){this.log(Level.DEBUG,arguments);},info:function(){this.log(Level.INFO,arguments);},warn:function(){this.log(Level.WARN,arguments);},error:function(){this.log(Level.ERROR,arguments);},fatal:function(){this.log(Level.FATAL,arguments);},isEnabledFor:function(level){return level.isGreaterOrEqual(this.getLevel());},isTraceEnabled:function(){return this.isEnabledFor(Level.TRACE);},isDebugEnabled:function(){return this.isEnabledFor(Level.DEBUG);},isInfoEnabled:function(){return this.isEnabledFor(Level.INFO);},isWarnEnabled:function(){return this.isEnabledFor(Level.WARN);},isErrorEnabled:function(){return this.isEnabledFor(Level.ERROR);},isFatalEnabled:function(){return this.isEnabledFor(Level.FATAL);}};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=new Logger();}

+return defaultLogger;};log4javascript.getLogger=log4javascript.getDefaultLogger;var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger();nullLogger.setLevel(Level.OFF);}

+return nullLogger;};var LoggingEvent=function(logger,timeStamp,level,messages,exception){this.logger=logger;this.timeStamp=timeStamp;this.level=level;this.messages=messages;this.exception=exception;};LoggingEvent.prototype={getThrowableStrRep:function(){return this.exception?getExceptionStringRep(this.exception):"";},getCombinedMessages:function(){return(this.messages.length===1)?this.messages[0]:this.messages.join(newLine);}};log4javascript.LoggingEvent=LoggingEvent;window.log4javascript=log4javascript;})();

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_lite_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_lite_uncompressed.js
new file mode 100644
index 0000000..12e97d8
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_lite_uncompressed.js
@@ -0,0 +1,620 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+if (!Array.prototype.shift) {

+	Array.prototype.shift = function() {

+		if (this.length > 0) {

+			var firstItem = this[0];

+			for (var i = 0, len = this.length - 1; i < len; i++) {

+				this[i] = this[i + 1];

+			}

+			this.length--;

+			return firstItem;

+		}

+	};

+}

+

+var log4javascript;

+

+(function() {

+	var newLine = "\r\n";

+	function Log4JavaScript() {}

+	log4javascript = new Log4JavaScript();

+	log4javascript.version = "1.4.6";

+	log4javascript.edition = "log4javascript_lite";

+

+	function getExceptionMessage(ex) {

+		if (ex.message) {

+			return ex.message;

+		} else if (ex.description) {

+			return ex.description;

+		} else {

+			return String(ex);

+		}

+	}

+

+	// Gets the portion of the URL after the last slash

+	function getUrlFileName(url) {

+		var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\"));

+		return url.substr(lastSlashIndex + 1);

+	}

+

+	// Returns a nicely formatted representation of an error

+	function getExceptionStringRep(ex) {

+		if (ex) {

+			var exStr = "Exception: " + getExceptionMessage(ex);

+			try {

+				if (ex.lineNumber) {

+					exStr += " on line number " + ex.lineNumber;

+				}

+				if (ex.fileName) {

+					exStr += " in file " + getUrlFileName(ex.fileName);

+				}

+			} catch (localEx) {

+			}

+			if (showStackTraces && ex.stack) {

+				exStr += newLine + "Stack trace:" + newLine + ex.stack;

+			}

+			return exStr;

+		}

+		return null;

+	}

+

+	function isError(err) {

+		return (err instanceof Error);

+	}

+

+	function bool(obj) {

+		return Boolean(obj);

+	}

+

+	var enabled = (typeof log4javascript_disabled != "undefined") &&

+		log4javascript_disabled ? false : true;

+

+	log4javascript.setEnabled = function(enable) {

+		enabled = bool(enable);

+	};

+

+	log4javascript.isEnabled = function() {

+		return enabled;

+	};

+

+	var showStackTraces = false;

+

+	log4javascript.setShowStackTraces = function(show) {

+		showStackTraces = bool(show);

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Levels

+

+	var Level = function(level, name) {

+		this.level = level;

+		this.name = name;

+	};

+

+	Level.prototype = {

+		toString: function() {

+			return this.name;

+		},

+		equals: function(level) {

+			return this.level == level.level;

+		},

+		isGreaterOrEqual: function(level) {

+			return this.level >= level.level;

+		}

+	};

+

+	Level.ALL = new Level(Number.MIN_VALUE, "ALL");

+	Level.TRACE = new Level(10000, "TRACE");

+	Level.DEBUG = new Level(20000, "DEBUG");

+	Level.INFO = new Level(30000, "INFO");

+	Level.WARN = new Level(40000, "WARN");

+	Level.ERROR = new Level(50000, "ERROR");

+	Level.FATAL = new Level(60000, "FATAL");

+	Level.OFF = new Level(Number.MAX_VALUE, "OFF");

+

+	log4javascript.Level = Level;

+

+	/* ---------------------------------------------------------------------- */

+	// Appenders

+

+	function Appender() {

+		var getConsoleHtmlLines = function() {

+			return [

+'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',

+'<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">',

+'	<head>',

+'		<title>log4javascript</title>',

+'		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',

+'		<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->',

+'		<meta http-equiv="X-UA-Compatible" content="IE=7" />',

+'		<script type="text/javascript">',

+'			//<![CDATA[',

+'			var loggingEnabled = true;',

+'			var messagesBeforeDocLoaded = [];',

+'',

+'			function toggleLoggingEnabled() {',

+'				setLoggingEnabled($("enableLogging").checked);',

+'			}',

+'',

+'			function setLoggingEnabled(enable) {',

+'				loggingEnabled = enable;',

+'			}',

+'',

+'			function scrollToLatestEntry() {',

+'				var l = getLogContainer();',

+'				if (typeof l.scrollTop != "undefined") {',

+'					var latestLogEntry = l.lastChild;',

+'					if (latestLogEntry) {',

+'						l.scrollTop = l.scrollHeight;',

+'					}',

+'				}',

+'			}',

+'',

+'			function log(logLevel, formattedMessage) {',

+'				if (loggingEnabled) {',

+'					if (loaded) {',

+'						doLog(logLevel, formattedMessage);',

+'					} else {',

+'						messagesBeforeDocLoaded.push([logLevel, formattedMessage]);',

+'					}',

+'				}',

+'			}',

+'',

+'			function doLog(logLevel, formattedMessage) {',

+'				var logEntry = document.createElement("div");',

+'				logEntry.appendChild(document.createTextNode(formattedMessage));',

+'				logEntry.className = "logentry " + logLevel.name;',

+'				getLogContainer().appendChild(logEntry);',

+'				scrollToLatestEntry();',

+'			}',

+'',

+'			function mainPageReloaded() {',

+'				var separator = document.createElement("div");',

+'				separator.className = "separator";',

+'				separator.innerHTML = "&nbsp;";',

+'				getLogContainer().appendChild(separator);',

+'			}',

+'',

+'			var loaded = false;',

+'			var logLevels = ["DEBUG", "INFO", "WARN", "ERROR", "FATAL"];',

+'',

+'			window.onload = function() {',

+'				setLogContainerHeight();',

+'				toggleLoggingEnabled();',

+'				for (var i = 0; i < messagesBeforeDocLoaded.length; i++) {',

+'					doLog(messagesBeforeDocLoaded[i][0], messagesBeforeDocLoaded[i][1]);',

+'				}',

+'				messagesBeforeDocLoaded = [];',

+'				loaded = true;',

+'',

+'				// Workaround to make sure log div starts at the correct size',

+'				setTimeout(setLogContainerHeight, 20);',

+'			};',

+'',

+'			function getLogContainer() {',

+'				return $("log");',

+'			}',

+'',

+'			function clearLog() {',

+'				getLogContainer().innerHTML = "";',

+'			}',

+'',

+'			/* ------------------------------------------------------------------------- */',

+'',

+'			// Other utility functions',

+'',

+'			// Syntax borrowed from Prototype library',

+'			function $(id) {',

+'				return document.getElementById(id);',

+'			}',

+'',

+'			function getWindowHeight() {',

+'				if (window.innerHeight) {',

+'					return window.innerHeight;',

+'				} else if (document.documentElement && document.documentElement.clientHeight) {',

+'					return document.documentElement.clientHeight;',

+'				} else if (document.body) {',

+'					return document.body.clientHeight;',

+'				}',

+'				return 0;',

+'			}',

+'',

+'			function getChromeHeight() {',

+'				return $("toolbar").offsetHeight;',

+'			}',

+'',

+'			function setLogContainerHeight() {',

+'				var windowHeight = getWindowHeight();',

+'				$("body").style.height = getWindowHeight() + "px";',

+'				getLogContainer().style.height = "" +',

+'					Math.max(0, windowHeight - getChromeHeight()) + "px";',

+'			}',

+'',

+'			window.onresize = function() {',

+'				setLogContainerHeight();',

+'			};',

+'',

+'			//]]>',

+'		</script>',

+'		<style type="text/css">',

+'			body {',

+'				background-color: white;',

+'				color: black;',

+'				padding: 0;',

+'				margin: 0;',

+'				font-family: tahoma, verdana, arial, helvetica, sans-serif;',

+'				overflow: hidden;',

+'			}',

+'			',

+'			div#toolbar {',

+'				border-top: solid #ffffff 1px;',

+'				border-bottom: solid #aca899 1px;',

+'				background-color: #f1efe7;',

+'				padding: 3px 5px;',

+'				font-size: 68.75%;',

+'			}',

+'',

+'			div#toolbar input.button {',

+'				padding: 0 5px;',

+'				font-size: 100%;',

+'			}',

+'',

+'			div#log {',

+'				font-family: Courier New, Courier;',

+'				font-size: 75%;',

+'				width: 100%;',

+'				overflow: auto;',

+'				clear: both;',

+'			}',

+'',

+'			*.logentry {',

+'				overflow: visible;',

+'				white-space: pre;',

+'			}',

+'',

+'			*.TRACE {',

+'				color: #666666;',

+'			}',

+'',

+'			*.DEBUG {',

+'				color: green;',

+'			}',

+'',

+'			*.INFO {',

+'				color: #000099;',

+'			}',

+'',

+'			*.WARN {',

+'				color: #999900;',

+'			}',

+'',

+'			*.ERROR {',

+'				color: red;',

+'			}',

+'',

+'			*.FATAL {',

+'				color: #660066;',

+'			}',

+'',

+'			div#log div.separator {',

+'				background-color: #cccccc;',

+'				margin: 5px 0;',

+'				line-height: 1px;',

+'			}',

+'		</style>',

+'	</head>',

+'',

+'	<body id="body">',

+'		<div id="toolbar">',

+'			Options:',

+'			<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" class="stateful" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Enable logging</label>',

+'			<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="stateful button" title="Clear all log messages"  />',

+'			<input type="button" id="closeButton" value="Close" onclick="window.close()" class="stateful button" title="Close the window" />',

+'		</div>',

+'		<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>',

+'	</body>',

+'</html>'

+];

+		};

+

+		var popUp = null;

+		var popUpsBlocked = false;

+		var popUpClosed = false;

+		var popUpLoaded = false;

+		var complainAboutPopUpBlocking = true;

+		var initialized = false;

+		var isSupported = true;

+		var width = 600;

+		var height = 400;

+		var focusPopUp = false;

+		var queuedLoggingEvents = new Array();

+

+		function isLoaded(win) {

+			try {

+				return bool(win.loaded);

+			} catch (ex) {

+				return false;

+			}

+		}

+

+		function finalInit() {

+			popUpLoaded = true;

+			appendQueuedLoggingEvents();

+		}

+

+		function writeHtml(doc) {

+			var lines = getConsoleHtmlLines();

+			doc.open();

+			for (var i = 0, len = lines.length; i < len; i++) {

+				doc.writeln(lines[i]);

+			}

+			doc.close();

+		}

+

+		function pollConsoleWindow() {

+			function pollConsoleWindowLoaded() {

+				if (popUpLoaded) {

+					clearInterval(poll);

+				} else if (bool(popUp) && isLoaded(popUp)) {

+					clearInterval(poll);

+					finalInit();

+				}

+			}

+

+			// Poll the pop-up since the onload event is not reliable

+			var poll = setInterval(pollConsoleWindowLoaded, 100);

+		}

+

+		function init() {

+			var windowProperties = "width=" + width + ",height=" + height + ",status,resizable";

+			var windowName = "log4javascriptLitePopUp" + location.host.replace(/[^a-z0-9]/gi, "_");

+

+			popUp = window.open("", windowName, windowProperties);

+			popUpClosed = false;

+			if (popUp) {

+				if (isLoaded(popUp)) {

+					popUp.mainPageReloaded();

+					finalInit();

+				} else {

+					writeHtml(popUp.document);

+

+					// Check if the pop-up window object is available

+					if (isLoaded(popUp)) {

+						finalInit();

+					} else {

+						pollConsoleWindow();

+					}

+				}

+			} else {

+				isSupported = false;

+				if (complainAboutPopUpBlocking) {

+					alert("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");

+				}

+			}

+			initialized = true;

+		}

+

+		function safeToAppend() {

+			if (!popUpsBlocked && !popUpClosed) {

+				if (popUp.closed) {

+					popUpClosed = true;

+					return false;

+				}

+				if (!popUpLoaded && popUp.loaded) {

+					popUpLoaded = true;

+				}

+			}

+			return !popUpsBlocked && popUpLoaded && !popUpClosed;

+		}

+

+		function padWithZeroes(num, len) {

+			var str = "" + num;

+			while (str.length < len) {

+				str = "0" + str;

+			}

+			return str;

+		}

+

+		function padWithSpaces(str, len) {

+			while (str.length < len) {

+				str += " ";

+			}

+			return str;

+		}

+

+		this.append = function(loggingEvent) {

+			if (!initialized) {

+				init();

+			}

+			queuedLoggingEvents.push(loggingEvent);

+			if (safeToAppend()) {

+				appendQueuedLoggingEvents();

+			}

+		};

+

+		function appendQueuedLoggingEvents() {

+			if (safeToAppend()) {

+				while (queuedLoggingEvents.length > 0) {

+					var currentLoggingEvent = queuedLoggingEvents.shift();

+					var date = currentLoggingEvent.timeStamp;

+					var formattedDate = padWithZeroes(date.getHours(), 2) + ":" +

+						padWithZeroes(date.getMinutes(), 2) + ":" + padWithZeroes(date.getSeconds(), 2);

+					var formattedMessage = formattedDate + " " + padWithSpaces(currentLoggingEvent.level.name, 5) +

+						" - " + currentLoggingEvent.getCombinedMessages();

+					var throwableStringRep = currentLoggingEvent.getThrowableStrRep();

+					if (throwableStringRep) {

+						formattedMessage += newLine + throwableStringRep;

+					}

+					popUp.log(currentLoggingEvent.level, formattedMessage);

+				}

+				if (focusPopUp) {

+					popUp.focus();

+				}

+			}

+		}

+	}

+

+	log4javascript.Appender = Appender;

+

+	/* ---------------------------------------------------------------------- */

+	// Loggers

+

+	function Logger() {

+		var appender = new Appender();

+		var loggerLevel = Level.ALL;

+

+		this.log = function(level, params) {

+			if (enabled && level.isGreaterOrEqual(this.getLevel())) {

+				// Check whether last param is an exception

+				var exception;

+				var finalParamIndex = params.length - 1;

+				var lastParam = params[params.length - 1];

+				if (params.length > 1 && isError(lastParam)) {

+					exception = lastParam;

+					finalParamIndex--;

+				}

+

+				// Construct genuine array for the params

+				var messages = [];

+				for (var i = 0; i <= finalParamIndex; i++) {

+					messages[i] = params[i];

+				}

+

+				var loggingEvent = new LoggingEvent(

+					this, new Date(), level, messages, exception);

+

+				appender.append(loggingEvent);

+			}

+		};

+

+		this.setLevel = function(level) {

+			loggerLevel = level;

+		};

+

+		this.getLevel = function() {

+			return loggerLevel;

+		};

+	}

+

+	Logger.prototype = {

+		trace: function() {

+			this.log(Level.TRACE, arguments);

+		},

+

+		debug: function() {

+			this.log(Level.DEBUG, arguments);

+		},

+

+		info: function() {

+			this.log(Level.INFO, arguments);

+		},

+

+		warn: function() {

+			this.log(Level.WARN, arguments);

+		},

+

+		error: function() {

+			this.log(Level.ERROR, arguments);

+		},

+

+		fatal: function() {

+			this.log(Level.FATAL, arguments);

+		},

+

+		isEnabledFor: function(level) {

+			return level.isGreaterOrEqual(this.getLevel());

+		},

+

+		isTraceEnabled: function() {

+			return this.isEnabledFor(Level.TRACE);

+		},

+

+		isDebugEnabled: function() {

+			return this.isEnabledFor(Level.DEBUG);

+		},

+

+		isInfoEnabled: function() {

+			return this.isEnabledFor(Level.INFO);

+		},

+

+		isWarnEnabled: function() {

+			return this.isEnabledFor(Level.WARN);

+		},

+

+		isErrorEnabled: function() {

+			return this.isEnabledFor(Level.ERROR);

+		},

+

+		isFatalEnabled: function() {

+			return this.isEnabledFor(Level.FATAL);

+		}

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Logger access methods

+

+	var defaultLogger = null;

+	log4javascript.getDefaultLogger = function() {

+		if (!defaultLogger) {

+			defaultLogger = new Logger();

+		}

+		return defaultLogger;

+	};

+

+	log4javascript.getLogger = log4javascript.getDefaultLogger;

+

+	var nullLogger = null;

+	log4javascript.getNullLogger = function() {

+		if (!nullLogger) {

+			nullLogger = new Logger();

+			nullLogger.setLevel(Level.OFF);

+		}

+		return nullLogger;

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Logging events

+

+	var LoggingEvent = function(logger, timeStamp, level, messages,

+			exception) {

+		this.logger = logger;

+		this.timeStamp = timeStamp;

+		this.level = level;

+		this.messages = messages;

+		this.exception = exception;

+	};

+

+	LoggingEvent.prototype = {

+		getThrowableStrRep: function() {

+			return this.exception ?

+				getExceptionStringRep(this.exception) : "";

+		},

+

+		getCombinedMessages: function() {

+			return (this.messages.length === 1) ? this.messages[0] :

+				   this.messages.join(newLine);

+		}

+	};

+

+	log4javascript.LoggingEvent = LoggingEvent;

+

+	// Ensure that the log4javascript object is available in the window. This

+	// is necessary for log4javascript to be available in IE if loaded using

+	// Dojo's module system

+	window.log4javascript = log4javascript;

+})();
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_production.js b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_production.js
new file mode 100644
index 0000000..1a31299
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_production.js
@@ -0,0 +1,188 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}

+return this.length;};}

+if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}

+this.length=this.length-1;return firstItem;}};}

+if(!Array.prototype.splice){Array.prototype.splice=function(startIndex,deleteCount){var itemsAfterDeleted=this.slice(startIndex+deleteCount);var itemsDeleted=this.slice(startIndex,startIndex+deleteCount);this.length=startIndex;var argumentsArray=[];for(var i=0,len=arguments.length;i<len;i++){argumentsArray[i]=arguments[i];}

+var itemsToAppend=(argumentsArray.length>2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i<len;i++){this.push(itemsToAppend[i]);}

+return itemsDeleted;};}

+var log4javascript=(function(){function isUndefined(obj){return typeof obj=="undefined";}

+function EventSupport(){}

+EventSupport.prototype={eventTypes:[],eventListeners:{},setEventTypes:function(eventTypesParam){if(eventTypesParam instanceof Array){this.eventTypes=eventTypesParam;this.eventListeners={};for(var i=0,len=this.eventTypes.length;i<len;i++){this.eventListeners[this.eventTypes[i]]=[];}}else{handleError("log4javascript.EventSupport ["+this+"]: setEventTypes: eventTypes parameter must be an Array");}},addEventListener:function(eventType,listener){if(typeof listener=="function"){if(!array_contains(this.eventTypes,eventType)){handleError("log4javascript.EventSupport ["+this+"]: addEventListener: no event called '"+eventType+"'");}

+this.eventListeners[eventType].push(listener);}else{handleError("log4javascript.EventSupport ["+this+"]: addEventListener: listener must be a function");}},removeEventListener:function(eventType,listener){if(typeof listener=="function"){if(!array_contains(this.eventTypes,eventType)){handleError("log4javascript.EventSupport ["+this+"]: removeEventListener: no event called '"+eventType+"'");}

+array_remove(this.eventListeners[eventType],listener);}else{handleError("log4javascript.EventSupport ["+this+"]: removeEventListener: listener must be a function");}},dispatchEvent:function(eventType,eventArgs){if(array_contains(this.eventTypes,eventType)){var listeners=this.eventListeners[eventType];for(var i=0,len=listeners.length;i<len;i++){listeners[i](this,eventType,eventArgs);}}else{handleError("log4javascript.EventSupport ["+this+"]: dispatchEvent: no event called '"+eventType+"'");}}};var applicationStartDate=new Date();var uniqueId="log4javascript_"+applicationStartDate.getTime()+"_"+

+Math.floor(Math.random()*100000000);var emptyFunction=function(){};var newLine="\r\n";var pageLoaded=false;function Log4JavaScript(){}

+Log4JavaScript.prototype=new EventSupport();log4javascript=new Log4JavaScript();log4javascript.version="1.4.6";log4javascript.edition="log4javascript_production";function toStr(obj){if(obj&&obj.toString){return obj.toString();}else{return String(obj);}}

+function getExceptionMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}else{return toStr(ex);}}

+function getUrlFileName(url){var lastSlashIndex=Math.max(url.lastIndexOf("/"),url.lastIndexOf("\\"));return url.substr(lastSlashIndex+1);}

+function getExceptionStringRep(ex){if(ex){var exStr="Exception: "+getExceptionMessage(ex);try{if(ex.lineNumber){exStr+=" on line number "+ex.lineNumber;}

+if(ex.fileName){exStr+=" in file "+getUrlFileName(ex.fileName);}}catch(localEx){logLog.warn("Unable to obtain file and line information for error");}

+if(showStackTraces&&ex.stack){exStr+=newLine+"Stack trace:"+newLine+ex.stack;}

+return exStr;}

+return null;}

+function bool(obj){return Boolean(obj);}

+function trim(str){return str.replace(/^\s+/,"").replace(/\s+$/,"");}

+function splitIntoLines(text){var text2=text.replace(/\r\n/g,"\n").replace(/\r/g,"\n");return text2.split("\n");}

+var urlEncode=(typeof window.encodeURIComponent!="undefined")?function(str){return encodeURIComponent(str);}:function(str){return escape(str).replace(/\+/g,"%2B").replace(/"/g,"%22").replace(/'/g,"%27").replace(/\//g,"%2F").replace(/=/g,"%3D");};var urlDecode=(typeof window.decodeURIComponent!="undefined")?function(str){return decodeURIComponent(str);}:function(str){return unescape(str).replace(/%2B/g,"+").replace(/%22/g,"\"").replace(/%27/g,"'").replace(/%2F/g,"/").replace(/%3D/g,"=");};function array_remove(arr,val){var index=-1;for(var i=0,len=arr.length;i<len;i++){if(arr[i]===val){index=i;break;}}

+if(index>=0){arr.splice(index,1);return true;}else{return false;}}

+function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}

+return false;}

+function extractBooleanFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return bool(param);}}

+function extractStringFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return String(param);}}

+function extractIntFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{try{var value=parseInt(param,10);return isNaN(value)?defaultValue:value;}catch(ex){logLog.warn("Invalid int param "+param,ex);return defaultValue;}}}

+function extractFunctionFromParam(param,defaultValue){if(typeof param=="function"){return param;}else{return defaultValue;}}

+function isError(err){return(err instanceof Error);}

+if(!Function.prototype.apply){Function.prototype.apply=function(obj,args){var methodName="__apply__";if(typeof obj[methodName]!="undefined"){methodName+=String(Math.random()).substr(2);}

+obj[methodName]=this;var argsStrings=[];for(var i=0,len=args.length;i<len;i++){argsStrings[i]="args["+i+"]";}

+var script="obj."+methodName+"("+argsStrings.join(",")+")";var returnValue=eval(script);delete obj[methodName];return returnValue;};}

+if(!Function.prototype.call){Function.prototype.call=function(obj){var args=[];for(var i=1,len=arguments.length;i<len;i++){args[i-1]=arguments[i];}

+return this.apply(obj,args);};}

+function getListenersPropertyName(eventName){return"__log4javascript_listeners__"+eventName;}

+function addEvent(node,eventName,listener,useCapture,win){win=win?win:window;if(node.addEventListener){node.addEventListener(eventName,listener,useCapture);}else if(node.attachEvent){node.attachEvent("on"+eventName,listener);}else{var propertyName=getListenersPropertyName(eventName);if(!node[propertyName]){node[propertyName]=[];node["on"+eventName]=function(evt){evt=getEvent(evt,win);var listenersPropertyName=getListenersPropertyName(eventName);var listeners=this[listenersPropertyName].concat([]);var currentListener;while((currentListener=listeners.shift())){currentListener.call(this,evt);}};}

+node[propertyName].push(listener);}}

+function removeEvent(node,eventName,listener,useCapture){if(node.removeEventListener){node.removeEventListener(eventName,listener,useCapture);}else if(node.detachEvent){node.detachEvent("on"+eventName,listener);}else{var propertyName=getListenersPropertyName(eventName);if(node[propertyName]){array_remove(node[propertyName],listener);}}}

+function getEvent(evt,win){win=win?win:window;return evt?evt:win.event;}

+function stopEventPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}

+evt.returnValue=false;}

+var logLog={quietMode:false,debugMessages:[],setQuietMode:function(quietMode){this.quietMode=bool(quietMode);},numberOfErrors:0,alertAllErrors:false,setAlertAllErrors:function(alertAllErrors){this.alertAllErrors=alertAllErrors;},debug:function(message){this.debugMessages.push(message);},displayDebug:function(){alert(this.debugMessages.join(newLine));},warn:function(message,exception){},error:function(message,exception){if(++this.numberOfErrors==1||this.alertAllErrors){if(!this.quietMode){var alertMessage="log4javascript error: "+message;if(exception){alertMessage+=newLine+newLine+"Original error: "+getExceptionStringRep(exception);}

+alert(alertMessage);}}}};log4javascript.logLog=logLog;log4javascript.setEventTypes(["load","error"]);function handleError(message,exception){logLog.error(message,exception);log4javascript.dispatchEvent("error",{"message":message,"exception":exception});}

+log4javascript.handleError=handleError;var enabled=!((typeof log4javascript_disabled!="undefined")&&log4javascript_disabled);log4javascript.setEnabled=function(enable){enabled=bool(enable);};log4javascript.isEnabled=function(){return enabled;};var useTimeStampsInMilliseconds=true;log4javascript.setTimeStampsInMilliseconds=function(timeStampsInMilliseconds){useTimeStampsInMilliseconds=bool(timeStampsInMilliseconds);};log4javascript.isTimeStampsInMilliseconds=function(){return useTimeStampsInMilliseconds;};log4javascript.evalInScope=function(expr){return eval(expr);};var showStackTraces=false;log4javascript.setShowStackTraces=function(show){showStackTraces=bool(show);};var Level=function(level,name){this.level=level;this.name=name;};Level.prototype={toString:function(){return this.name;},equals:function(level){return this.level==level.level;},isGreaterOrEqual:function(level){return this.level>=level.level;}};Level.ALL=new Level(Number.MIN_VALUE,"ALL");Level.TRACE=new Level(10000,"TRACE");Level.DEBUG=new Level(20000,"DEBUG");Level.INFO=new Level(30000,"INFO");Level.WARN=new Level(40000,"WARN");Level.ERROR=new Level(50000,"ERROR");Level.FATAL=new Level(60000,"FATAL");Level.OFF=new Level(Number.MAX_VALUE,"OFF");log4javascript.Level=Level;function Timer(name,level){this.name=name;this.level=isUndefined(level)?Level.INFO:level;this.start=new Date();}

+Timer.prototype.getElapsedTime=function(){return new Date().getTime()-this.start.getTime();};var anonymousLoggerName="[anonymous]";var defaultLoggerName="[default]";var nullLoggerName="[null]";var rootLoggerName="root";function Logger(name){this.name=name;this.parent=null;this.children=[];var appenders=[];var loggerLevel=null;var isRoot=(this.name===rootLoggerName);var isNull=(this.name===nullLoggerName);var appenderCache=null;var appenderCacheInvalidated=false;this.addChild=function(childLogger){this.children.push(childLogger);childLogger.parent=this;childLogger.invalidateAppenderCache();};var additive=true;this.getAdditivity=function(){return additive;};this.setAdditivity=function(additivity){var valueChanged=(additive!=additivity);additive=additivity;if(valueChanged){this.invalidateAppenderCache();}};this.addAppender=function(appender){if(isNull){handleError("Logger.addAppender: you may not add an appender to the null logger");}else{if(appender instanceof log4javascript.Appender){if(!array_contains(appenders,appender)){appenders.push(appender);appender.setAddedToLogger(this);this.invalidateAppenderCache();}}else{handleError("Logger.addAppender: appender supplied ('"+

+toStr(appender)+"') is not a subclass of Appender");}}};this.removeAppender=function(appender){array_remove(appenders,appender);appender.setRemovedFromLogger(this);this.invalidateAppenderCache();};this.removeAllAppenders=function(){var appenderCount=appenders.length;if(appenderCount>0){for(var i=0;i<appenderCount;i++){appenders[i].setRemovedFromLogger(this);}

+appenders.length=0;this.invalidateAppenderCache();}};this.getEffectiveAppenders=function(){if(appenderCache===null||appenderCacheInvalidated){var parentEffectiveAppenders=(isRoot||!this.getAdditivity())?[]:this.parent.getEffectiveAppenders();appenderCache=parentEffectiveAppenders.concat(appenders);appenderCacheInvalidated=false;}

+return appenderCache;};this.invalidateAppenderCache=function(){appenderCacheInvalidated=true;for(var i=0,len=this.children.length;i<len;i++){this.children[i].invalidateAppenderCache();}};this.log=function(level,params){if(enabled&&level.isGreaterOrEqual(this.getEffectiveLevel())){var exception;var finalParamIndex=params.length-1;var lastParam=params[finalParamIndex];if(params.length>1&&isError(lastParam)){exception=lastParam;finalParamIndex--;}

+var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];}

+var loggingEvent=new LoggingEvent(this,new Date(),level,messages,exception);this.callAppenders(loggingEvent);}};this.callAppenders=function(loggingEvent){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].doAppend(loggingEvent);}};this.setLevel=function(level){if(isRoot&&level===null){handleError("Logger.setLevel: you cannot set the level of the root logger to null");}else if(level instanceof Level){loggerLevel=level;}else{handleError("Logger.setLevel: level supplied to logger "+

+this.name+" is not an instance of log4javascript.Level");}};this.getLevel=function(){return loggerLevel;};this.getEffectiveLevel=function(){for(var logger=this;logger!==null;logger=logger.parent){var level=logger.getLevel();if(level!==null){return level;}}};this.group=function(name,initiallyExpanded){if(enabled){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].group(name,initiallyExpanded);}}};this.groupEnd=function(){if(enabled){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].groupEnd();}}};var timers={};this.time=function(name,level){if(enabled){if(isUndefined(name)){handleError("Logger.time: a name for the timer must be supplied");}else if(level&&!(level instanceof Level)){handleError("Logger.time: level supplied to timer "+

+name+" is not an instance of log4javascript.Level");}else{timers[name]=new Timer(name,level);}}};this.timeEnd=function(name){if(enabled){if(isUndefined(name)){handleError("Logger.timeEnd: a name for the timer must be supplied");}else if(timers[name]){var timer=timers[name];var milliseconds=timer.getElapsedTime();this.log(timer.level,["Timer "+toStr(name)+" completed in "+milliseconds+"ms"]);delete timers[name];}else{logLog.warn("Logger.timeEnd: no timer found with name "+name);}}};this.assert=function(expr){if(enabled&&!expr){var args=[];for(var i=1,len=arguments.length;i<len;i++){args.push(arguments[i]);}

+args=(args.length>0)?args:["Assertion Failure"];args.push(newLine);args.push(expr);this.log(Level.ERROR,args);}};this.toString=function(){return"Logger["+this.name+"]";};}

+Logger.prototype={trace:function(){this.log(Level.TRACE,arguments);},debug:function(){this.log(Level.DEBUG,arguments);},info:function(){this.log(Level.INFO,arguments);},warn:function(){this.log(Level.WARN,arguments);},error:function(){this.log(Level.ERROR,arguments);},fatal:function(){this.log(Level.FATAL,arguments);},isEnabledFor:function(level){return level.isGreaterOrEqual(this.getEffectiveLevel());},isTraceEnabled:function(){return this.isEnabledFor(Level.TRACE);},isDebugEnabled:function(){return this.isEnabledFor(Level.DEBUG);},isInfoEnabled:function(){return this.isEnabledFor(Level.INFO);},isWarnEnabled:function(){return this.isEnabledFor(Level.WARN);},isErrorEnabled:function(){return this.isEnabledFor(Level.ERROR);},isFatalEnabled:function(){return this.isEnabledFor(Level.FATAL);}};Logger.prototype.trace.isEntryPoint=true;Logger.prototype.debug.isEntryPoint=true;Logger.prototype.info.isEntryPoint=true;Logger.prototype.warn.isEntryPoint=true;Logger.prototype.error.isEntryPoint=true;Logger.prototype.fatal.isEntryPoint=true;var loggers={};var loggerNames=[];var ROOT_LOGGER_DEFAULT_LEVEL=Level.DEBUG;var rootLogger=new Logger(rootLoggerName);rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);log4javascript.getRootLogger=function(){return rootLogger;};log4javascript.getLogger=function(loggerName){if(!(typeof loggerName=="string")){loggerName=anonymousLoggerName;logLog.warn("log4javascript.getLogger: non-string logger name "+

+toStr(loggerName)+" supplied, returning anonymous logger");}

+if(loggerName==rootLoggerName){handleError("log4javascript.getLogger: root logger may not be obtained by name");}

+if(!loggers[loggerName]){var logger=new Logger(loggerName);loggers[loggerName]=logger;loggerNames.push(loggerName);var lastDotIndex=loggerName.lastIndexOf(".");var parentLogger;if(lastDotIndex>-1){var parentLoggerName=loggerName.substring(0,lastDotIndex);parentLogger=log4javascript.getLogger(parentLoggerName);}else{parentLogger=rootLogger;}

+parentLogger.addChild(logger);}

+return loggers[loggerName];};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=log4javascript.getLogger(defaultLoggerName);var a=new log4javascript.PopUpAppender();defaultLogger.addAppender(a);}

+return defaultLogger;};var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger(nullLoggerName);nullLogger.setLevel(Level.OFF);}

+return nullLogger;};log4javascript.resetConfiguration=function(){rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);loggers={};};var LoggingEvent=function(logger,timeStamp,level,messages,exception){this.logger=logger;this.timeStamp=timeStamp;this.timeStampInMilliseconds=timeStamp.getTime();this.timeStampInSeconds=Math.floor(this.timeStampInMilliseconds/1000);this.milliseconds=this.timeStamp.getMilliseconds();this.level=level;this.messages=messages;this.exception=exception;};LoggingEvent.prototype={getThrowableStrRep:function(){return this.exception?getExceptionStringRep(this.exception):"";},getCombinedMessages:function(){return(this.messages.length==1)?this.messages[0]:this.messages.join(newLine);},toString:function(){return"LoggingEvent["+this.level+"]";}};log4javascript.LoggingEvent=LoggingEvent;var Layout=function(){};Layout.prototype={defaults:{loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url"},loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url",batchHeader:"",batchFooter:"",batchSeparator:"",returnsPostData:false,overrideTimeStampsSetting:false,useTimeStampsInMilliseconds:null,format:function(){handleError("Layout.format: layout supplied has no format() method");},ignoresThrowable:function(){handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");},getContentType:function(){return"text/plain";},allowBatching:function(){return true;},setTimeStampsInMilliseconds:function(timeStampsInMilliseconds){this.overrideTimeStampsSetting=true;this.useTimeStampsInMilliseconds=bool(timeStampsInMilliseconds);},isTimeStampsInMilliseconds:function(){return this.overrideTimeStampsSetting?this.useTimeStampsInMilliseconds:useTimeStampsInMilliseconds;},getTimeStampValue:function(loggingEvent){return this.isTimeStampsInMilliseconds()?loggingEvent.timeStampInMilliseconds:loggingEvent.timeStampInSeconds;},getDataValues:function(loggingEvent,combineMessages){var dataValues=[[this.loggerKey,loggingEvent.logger.name],[this.timeStampKey,this.getTimeStampValue(loggingEvent)],[this.levelKey,loggingEvent.level.name],[this.urlKey,window.location.href],[this.messageKey,combineMessages?loggingEvent.getCombinedMessages():loggingEvent.messages]];if(!this.isTimeStampsInMilliseconds()){dataValues.push([this.millisecondsKey,loggingEvent.milliseconds]);}

+if(loggingEvent.exception){dataValues.push([this.exceptionKey,getExceptionStringRep(loggingEvent.exception)]);}

+if(this.hasCustomFields()){for(var i=0,len=this.customFields.length;i<len;i++){var val=this.customFields[i].value;if(typeof val==="function"){val=val(this,loggingEvent);}

+dataValues.push([this.customFields[i].name,val]);}}

+return dataValues;},setKeys:function(loggerKey,timeStampKey,levelKey,messageKey,exceptionKey,urlKey,millisecondsKey){this.loggerKey=extractStringFromParam(loggerKey,this.defaults.loggerKey);this.timeStampKey=extractStringFromParam(timeStampKey,this.defaults.timeStampKey);this.levelKey=extractStringFromParam(levelKey,this.defaults.levelKey);this.messageKey=extractStringFromParam(messageKey,this.defaults.messageKey);this.exceptionKey=extractStringFromParam(exceptionKey,this.defaults.exceptionKey);this.urlKey=extractStringFromParam(urlKey,this.defaults.urlKey);this.millisecondsKey=extractStringFromParam(millisecondsKey,this.defaults.millisecondsKey);},setCustomField:function(name,value){var fieldUpdated=false;for(var i=0,len=this.customFields.length;i<len;i++){if(this.customFields[i].name===name){this.customFields[i].value=value;fieldUpdated=true;}}

+if(!fieldUpdated){this.customFields.push({"name":name,"value":value});}},hasCustomFields:function(){return(this.customFields.length>0);},toString:function(){handleError("Layout.toString: all layouts must override this method");}};log4javascript.Layout=Layout;var Appender=function(){};Appender.prototype=new EventSupport();Appender.prototype.layout=new PatternLayout();Appender.prototype.threshold=Level.ALL;Appender.prototype.loggers=[];Appender.prototype.doAppend=function(loggingEvent){if(enabled&&loggingEvent.level.level>=this.threshold.level){this.append(loggingEvent);}};Appender.prototype.append=function(loggingEvent){};Appender.prototype.setLayout=function(layout){if(layout instanceof Layout){this.layout=layout;}else{handleError("Appender.setLayout: layout supplied to "+

+this.toString()+" is not a subclass of Layout");}};Appender.prototype.getLayout=function(){return this.layout;};Appender.prototype.setThreshold=function(threshold){if(threshold instanceof Level){this.threshold=threshold;}else{handleError("Appender.setThreshold: threshold supplied to "+

+this.toString()+" is not a subclass of Level");}};Appender.prototype.getThreshold=function(){return this.threshold;};Appender.prototype.setAddedToLogger=function(logger){this.loggers.push(logger);};Appender.prototype.setRemovedFromLogger=function(logger){array_remove(this.loggers,logger);};Appender.prototype.group=emptyFunction;Appender.prototype.groupEnd=emptyFunction;Appender.prototype.toString=function(){handleError("Appender.toString: all appenders must override this method");};log4javascript.Appender=Appender;function SimpleLayout(){this.customFields=[];}

+SimpleLayout.prototype=new Layout();SimpleLayout.prototype.format=function(loggingEvent){return loggingEvent.level.name+" - "+loggingEvent.getCombinedMessages();};SimpleLayout.prototype.ignoresThrowable=function(){return true;};SimpleLayout.prototype.toString=function(){return"SimpleLayout";};log4javascript.SimpleLayout=SimpleLayout;function NullLayout(){this.customFields=[];}

+NullLayout.prototype=new Layout();NullLayout.prototype.format=function(loggingEvent){return loggingEvent.messages;};NullLayout.prototype.ignoresThrowable=function(){return true;};NullLayout.prototype.toString=function(){return"NullLayout";};log4javascript.NullLayout=NullLayout;function XmlLayout(combineMessages){this.combineMessages=extractBooleanFromParam(combineMessages,true);this.customFields=[];}

+XmlLayout.prototype=new Layout();XmlLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};XmlLayout.prototype.getContentType=function(){return"text/xml";};XmlLayout.prototype.escapeCdata=function(str){return str.replace(/\]\]>/,"]]>]]&gt;<![CDATA[");};XmlLayout.prototype.format=function(loggingEvent){var layout=this;var i,len;function formatMessage(message){message=(typeof message==="string")?message:toStr(message);return"<log4javascript:message><![CDATA["+

+layout.escapeCdata(message)+"]]></log4javascript:message>";}

+var str="<log4javascript:event logger=\""+loggingEvent.logger.name+"\" timestamp=\""+this.getTimeStampValue(loggingEvent)+"\"";if(!this.isTimeStampsInMilliseconds()){str+=" milliseconds=\""+loggingEvent.milliseconds+"\"";}

+str+=" level=\""+loggingEvent.level.name+"\">"+newLine;if(this.combineMessages){str+=formatMessage(loggingEvent.getCombinedMessages());}else{str+="<log4javascript:messages>"+newLine;for(i=0,len=loggingEvent.messages.length;i<len;i++){str+=formatMessage(loggingEvent.messages[i])+newLine;}

+str+="</log4javascript:messages>"+newLine;}

+if(this.hasCustomFields()){for(i=0,len=this.customFields.length;i<len;i++){str+="<log4javascript:customfield name=\""+

+this.customFields[i].name+"\"><![CDATA["+

+this.customFields[i].value.toString()+"]]></log4javascript:customfield>"+newLine;}}

+if(loggingEvent.exception){str+="<log4javascript:exception><![CDATA["+

+getExceptionStringRep(loggingEvent.exception)+"]]></log4javascript:exception>"+newLine;}

+str+="</log4javascript:event>"+newLine+newLine;return str;};XmlLayout.prototype.ignoresThrowable=function(){return false;};XmlLayout.prototype.toString=function(){return"XmlLayout";};log4javascript.XmlLayout=XmlLayout;function escapeNewLines(str){return str.replace(/\r\n|\r|\n/g,"\\r\\n");}

+function JsonLayout(readable,combineMessages){this.readable=extractBooleanFromParam(readable,false);this.combineMessages=extractBooleanFromParam(combineMessages,true);this.batchHeader=this.readable?"["+newLine:"[";this.batchFooter=this.readable?"]"+newLine:"]";this.batchSeparator=this.readable?","+newLine:",";this.setKeys();this.colon=this.readable?": ":":";this.tab=this.readable?"\t":"";this.lineBreak=this.readable?newLine:"";this.customFields=[];}

+JsonLayout.prototype=new Layout();JsonLayout.prototype.isReadable=function(){return this.readable;};JsonLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};JsonLayout.prototype.format=function(loggingEvent){var layout=this;var dataValues=this.getDataValues(loggingEvent,this.combineMessages);var str="{"+this.lineBreak;var i,len;function formatValue(val,prefix,expand){var formattedValue;var valType=typeof val;if(val instanceof Date){formattedValue=String(val.getTime());}else if(expand&&(val instanceof Array)){formattedValue="["+layout.lineBreak;for(var i=0,len=val.length;i<len;i++){var childPrefix=prefix+layout.tab;formattedValue+=childPrefix+formatValue(val[i],childPrefix,false);if(i<val.length-1){formattedValue+=",";}

+formattedValue+=layout.lineBreak;}

+formattedValue+=prefix+"]";}else if(valType!=="number"&&valType!=="boolean"){formattedValue="\""+escapeNewLines(toStr(val).replace(/\"/g,"\\\""))+"\"";}else{formattedValue=val;}

+return formattedValue;}

+for(i=0,len=dataValues.length-1;i<=len;i++){str+=this.tab+"\""+dataValues[i][0]+"\""+this.colon+formatValue(dataValues[i][1],this.tab,true);if(i<len){str+=",";}

+str+=this.lineBreak;}

+str+="}"+this.lineBreak;return str;};JsonLayout.prototype.ignoresThrowable=function(){return false;};JsonLayout.prototype.toString=function(){return"JsonLayout";};JsonLayout.prototype.getContentType=function(){return"application/json";};log4javascript.JsonLayout=JsonLayout;function HttpPostDataLayout(){this.setKeys();this.customFields=[];this.returnsPostData=true;}

+HttpPostDataLayout.prototype=new Layout();HttpPostDataLayout.prototype.allowBatching=function(){return false;};HttpPostDataLayout.prototype.format=function(loggingEvent){var dataValues=this.getDataValues(loggingEvent);var queryBits=[];for(var i=0,len=dataValues.length;i<len;i++){var val=(dataValues[i][1]instanceof Date)?String(dataValues[i][1].getTime()):dataValues[i][1];queryBits.push(urlEncode(dataValues[i][0])+"="+urlEncode(val));}

+return queryBits.join("&");};HttpPostDataLayout.prototype.ignoresThrowable=function(loggingEvent){return false;};HttpPostDataLayout.prototype.toString=function(){return"HttpPostDataLayout";};log4javascript.HttpPostDataLayout=HttpPostDataLayout;function formatObjectExpansion(obj,depth,indentation){var objectsExpanded=[];function doFormat(obj,depth,indentation){var i,j,len,childDepth,childIndentation,childLines,expansion,childExpansion;if(!indentation){indentation="";}

+function formatString(text){var lines=splitIntoLines(text);for(var j=1,jLen=lines.length;j<jLen;j++){lines[j]=indentation+lines[j];}

+return lines.join(newLine);}

+if(obj===null){return"null";}else if(typeof obj=="undefined"){return"undefined";}else if(typeof obj=="string"){return formatString(obj);}else if(typeof obj=="object"&&array_contains(objectsExpanded,obj)){try{expansion=toStr(obj);}catch(ex){expansion="Error formatting property. Details: "+getExceptionStringRep(ex);}

+return expansion+" [already expanded]";}else if((obj instanceof Array)&&depth>0){objectsExpanded.push(obj);expansion="["+newLine;childDepth=depth-1;childIndentation=indentation+"  ";childLines=[];for(i=0,len=obj.length;i<len;i++){try{childExpansion=doFormat(obj[i],childDepth,childIndentation);childLines.push(childIndentation+childExpansion);}catch(ex){childLines.push(childIndentation+"Error formatting array member. Details: "+

+getExceptionStringRep(ex)+"");}}

+expansion+=childLines.join(","+newLine)+newLine+indentation+"]";return expansion;}else if(Object.prototype.toString.call(obj)=="[object Date]"){return obj.toString();}else if(typeof obj=="object"&&depth>0){objectsExpanded.push(obj);expansion="{"+newLine;childDepth=depth-1;childIndentation=indentation+"  ";childLines=[];for(i in obj){try{childExpansion=doFormat(obj[i],childDepth,childIndentation);childLines.push(childIndentation+i+": "+childExpansion);}catch(ex){childLines.push(childIndentation+i+": Error formatting property. Details: "+

+getExceptionStringRep(ex));}}

+expansion+=childLines.join(","+newLine)+newLine+indentation+"}";return expansion;}else{return formatString(toStr(obj));}}

+return doFormat(obj,depth,indentation);}

+var SimpleDateFormat;(function(){var regex=/('[^']*')|(G+|y+|M+|w+|W+|D+|d+|F+|E+|a+|H+|k+|K+|h+|m+|s+|S+|Z+)|([a-zA-Z]+)|([^a-zA-Z']+)/;var monthNames=["January","February","March","April","May","June","July","August","September","October","November","December"];var dayNames=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var TEXT2=0,TEXT3=1,NUMBER=2,YEAR=3,MONTH=4,TIMEZONE=5;var types={G:TEXT2,y:YEAR,M:MONTH,w:NUMBER,W:NUMBER,D:NUMBER,d:NUMBER,F:NUMBER,E:TEXT3,a:TEXT2,H:NUMBER,k:NUMBER,K:NUMBER,h:NUMBER,m:NUMBER,s:NUMBER,S:NUMBER,Z:TIMEZONE};var ONE_DAY=24*60*60*1000;var ONE_WEEK=7*ONE_DAY;var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK=1;var newDateAtMidnight=function(year,month,day){var d=new Date(year,month,day,0,0,0);d.setMilliseconds(0);return d;};Date.prototype.getDifference=function(date){return this.getTime()-date.getTime();};Date.prototype.isBefore=function(d){return this.getTime()<d.getTime();};Date.prototype.getUTCTime=function(){return Date.UTC(this.getFullYear(),this.getMonth(),this.getDate(),this.getHours(),this.getMinutes(),this.getSeconds(),this.getMilliseconds());};Date.prototype.getTimeSince=function(d){return this.getUTCTime()-d.getUTCTime();};Date.prototype.getPreviousSunday=function(){var midday=new Date(this.getFullYear(),this.getMonth(),this.getDate(),12,0,0);var previousSunday=new Date(midday.getTime()-this.getDay()*ONE_DAY);return newDateAtMidnight(previousSunday.getFullYear(),previousSunday.getMonth(),previousSunday.getDate());};Date.prototype.getWeekInYear=function(minimalDaysInFirstWeek){if(isUndefined(this.minimalDaysInFirstWeek)){minimalDaysInFirstWeek=DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;}

+var previousSunday=this.getPreviousSunday();var startOfYear=newDateAtMidnight(this.getFullYear(),0,1);var numberOfSundays=previousSunday.isBefore(startOfYear)?0:1+Math.floor(previousSunday.getTimeSince(startOfYear)/ONE_WEEK);var numberOfDaysInFirstWeek=7-startOfYear.getDay();var weekInYear=numberOfSundays;if(numberOfDaysInFirstWeek<minimalDaysInFirstWeek){weekInYear--;}

+return weekInYear;};Date.prototype.getWeekInMonth=function(minimalDaysInFirstWeek){if(isUndefined(this.minimalDaysInFirstWeek)){minimalDaysInFirstWeek=DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;}

+var previousSunday=this.getPreviousSunday();var startOfMonth=newDateAtMidnight(this.getFullYear(),this.getMonth(),1);var numberOfSundays=previousSunday.isBefore(startOfMonth)?0:1+Math.floor(previousSunday.getTimeSince(startOfMonth)/ONE_WEEK);var numberOfDaysInFirstWeek=7-startOfMonth.getDay();var weekInMonth=numberOfSundays;if(numberOfDaysInFirstWeek>=minimalDaysInFirstWeek){weekInMonth++;}

+return weekInMonth;};Date.prototype.getDayInYear=function(){var startOfYear=newDateAtMidnight(this.getFullYear(),0,1);return 1+Math.floor(this.getTimeSince(startOfYear)/ONE_DAY);};SimpleDateFormat=function(formatString){this.formatString=formatString;};SimpleDateFormat.prototype.setMinimalDaysInFirstWeek=function(days){this.minimalDaysInFirstWeek=days;};SimpleDateFormat.prototype.getMinimalDaysInFirstWeek=function(){return isUndefined(this.minimalDaysInFirstWeek)?DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK:this.minimalDaysInFirstWeek;};var padWithZeroes=function(str,len){while(str.length<len){str="0"+str;}

+return str;};var formatText=function(data,numberOfLetters,minLength){return(numberOfLetters>=4)?data:data.substr(0,Math.max(minLength,numberOfLetters));};var formatNumber=function(data,numberOfLetters){var dataString=""+data;return padWithZeroes(dataString,numberOfLetters);};SimpleDateFormat.prototype.format=function(date){var formattedString="";var result;var searchString=this.formatString;while((result=regex.exec(searchString))){var quotedString=result[1];var patternLetters=result[2];var otherLetters=result[3];var otherCharacters=result[4];if(quotedString){if(quotedString=="''"){formattedString+="'";}else{formattedString+=quotedString.substring(1,quotedString.length-1);}}else if(otherLetters){}else if(otherCharacters){formattedString+=otherCharacters;}else if(patternLetters){var patternLetter=patternLetters.charAt(0);var numberOfLetters=patternLetters.length;var rawData="";switch(patternLetter){case"G":rawData="AD";break;case"y":rawData=date.getFullYear();break;case"M":rawData=date.getMonth();break;case"w":rawData=date.getWeekInYear(this.getMinimalDaysInFirstWeek());break;case"W":rawData=date.getWeekInMonth(this.getMinimalDaysInFirstWeek());break;case"D":rawData=date.getDayInYear();break;case"d":rawData=date.getDate();break;case"F":rawData=1+Math.floor((date.getDate()-1)/7);break;case"E":rawData=dayNames[date.getDay()];break;case"a":rawData=(date.getHours()>=12)?"PM":"AM";break;case"H":rawData=date.getHours();break;case"k":rawData=date.getHours()||24;break;case"K":rawData=date.getHours()%12;break;case"h":rawData=(date.getHours()%12)||12;break;case"m":rawData=date.getMinutes();break;case"s":rawData=date.getSeconds();break;case"S":rawData=date.getMilliseconds();break;case"Z":rawData=date.getTimezoneOffset();break;}

+switch(types[patternLetter]){case TEXT2:formattedString+=formatText(rawData,numberOfLetters,2);break;case TEXT3:formattedString+=formatText(rawData,numberOfLetters,3);break;case NUMBER:formattedString+=formatNumber(rawData,numberOfLetters);break;case YEAR:if(numberOfLetters<=3){var dataString=""+rawData;formattedString+=dataString.substr(2,2);}else{formattedString+=formatNumber(rawData,numberOfLetters);}

+break;case MONTH:if(numberOfLetters>=3){formattedString+=formatText(monthNames[rawData],numberOfLetters,numberOfLetters);}else{formattedString+=formatNumber(rawData+1,numberOfLetters);}

+break;case TIMEZONE:var isPositive=(rawData>0);var prefix=isPositive?"-":"+";var absData=Math.abs(rawData);var hours=""+Math.floor(absData/60);hours=padWithZeroes(hours,2);var minutes=""+(absData%60);minutes=padWithZeroes(minutes,2);formattedString+=prefix+hours+minutes;break;}}

+searchString=searchString.substr(result.index+result[0].length);}

+return formattedString;};})();log4javascript.SimpleDateFormat=SimpleDateFormat;function PatternLayout(pattern){if(pattern){this.pattern=pattern;}else{this.pattern=PatternLayout.DEFAULT_CONVERSION_PATTERN;}

+this.customFields=[];}

+PatternLayout.TTCC_CONVERSION_PATTERN="%r %p %c - %m%n";PatternLayout.DEFAULT_CONVERSION_PATTERN="%m%n";PatternLayout.ISO8601_DATEFORMAT="yyyy-MM-dd HH:mm:ss,SSS";PatternLayout.DATETIME_DATEFORMAT="dd MMM yyyy HH:mm:ss,SSS";PatternLayout.ABSOLUTETIME_DATEFORMAT="HH:mm:ss,SSS";PatternLayout.prototype=new Layout();PatternLayout.prototype.format=function(loggingEvent){var regex=/%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;var formattedString="";var result;var searchString=this.pattern;while((result=regex.exec(searchString))){var matchedString=result[0];var padding=result[1];var truncation=result[2];var conversionCharacter=result[3];var specifier=result[5];var text=result[6];if(text){formattedString+=""+text;}else{var replacement="";switch(conversionCharacter){case"a":case"m":var depth=0;if(specifier){depth=parseInt(specifier,10);if(isNaN(depth)){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character '"+conversionCharacter+"' - should be a number");depth=0;}}

+var messages=(conversionCharacter==="a")?loggingEvent.messages[0]:loggingEvent.messages;for(var i=0,len=messages.length;i<len;i++){if(i>0&&(replacement.charAt(replacement.length-1)!==" ")){replacement+=" ";}

+if(depth===0){replacement+=messages[i];}else{replacement+=formatObjectExpansion(messages[i],depth);}}

+break;case"c":var loggerName=loggingEvent.logger.name;if(specifier){var precision=parseInt(specifier,10);var loggerNameBits=loggingEvent.logger.name.split(".");if(precision>=loggerNameBits.length){replacement=loggerName;}else{replacement=loggerNameBits.slice(loggerNameBits.length-precision).join(".");}}else{replacement=loggerName;}

+break;case"d":var dateFormat=PatternLayout.ISO8601_DATEFORMAT;if(specifier){dateFormat=specifier;if(dateFormat=="ISO8601"){dateFormat=PatternLayout.ISO8601_DATEFORMAT;}else if(dateFormat=="ABSOLUTE"){dateFormat=PatternLayout.ABSOLUTETIME_DATEFORMAT;}else if(dateFormat=="DATE"){dateFormat=PatternLayout.DATETIME_DATEFORMAT;}}

+replacement=(new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);break;case"f":if(this.hasCustomFields()){var fieldIndex=0;if(specifier){fieldIndex=parseInt(specifier,10);if(isNaN(fieldIndex)){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - should be a number");}else if(fieldIndex===0){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - must be greater than zero");}else if(fieldIndex>this.customFields.length){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - there aren't that many custom fields");}else{fieldIndex=fieldIndex-1;}}

+var val=this.customFields[fieldIndex].value;if(typeof val=="function"){val=val(this,loggingEvent);}

+replacement=val;}

+break;case"n":replacement=newLine;break;case"p":replacement=loggingEvent.level.name;break;case"r":replacement=""+loggingEvent.timeStamp.getDifference(applicationStartDate);break;case"%":replacement="%";break;default:replacement=matchedString;break;}

+var l;if(truncation){l=parseInt(truncation.substr(1),10);var strLen=replacement.length;if(l<strLen){replacement=replacement.substring(strLen-l,strLen);}}

+if(padding){if(padding.charAt(0)=="-"){l=parseInt(padding.substr(1),10);while(replacement.length<l){replacement+=" ";}}else{l=parseInt(padding,10);while(replacement.length<l){replacement=" "+replacement;}}}

+formattedString+=replacement;}

+searchString=searchString.substr(result.index+result[0].length);}

+return formattedString;};PatternLayout.prototype.ignoresThrowable=function(){return true;};PatternLayout.prototype.toString=function(){return"PatternLayout";};log4javascript.PatternLayout=PatternLayout;var xmlHttpFactories=[function(){return new XMLHttpRequest();},function(){return new ActiveXObject("Msxml2.XMLHTTP");},function(){return new ActiveXObject("Microsoft.XMLHTTP");}];var getXmlHttp=function(errorHandler){var xmlHttp=null,factory;for(var i=0,len=xmlHttpFactories.length;i<len;i++){factory=xmlHttpFactories[i];try{xmlHttp=factory();getXmlHttp=factory;return xmlHttp;}catch(e){}}

+if(errorHandler){errorHandler();}else{handleError("getXmlHttp: unable to obtain XMLHttpRequest object");}};function isHttpRequestSuccessful(xmlHttp){return isUndefined(xmlHttp.status)||xmlHttp.status===0||(xmlHttp.status>=200&&xmlHttp.status<300)||xmlHttp.status==1223;}

+function AjaxAppender(url){var appender=this;var isSupported=true;if(!url){handleError("AjaxAppender: URL must be specified in constructor");isSupported=false;}

+var timed=this.defaults.timed;var waitForResponse=this.defaults.waitForResponse;var batchSize=this.defaults.batchSize;var timerInterval=this.defaults.timerInterval;var requestSuccessCallback=this.defaults.requestSuccessCallback;var failCallback=this.defaults.failCallback;var postVarName=this.defaults.postVarName;var sendAllOnUnload=this.defaults.sendAllOnUnload;var contentType=this.defaults.contentType;var sessionId=null;var queuedLoggingEvents=[];var queuedRequests=[];var headers=[];var sending=false;var initialized=false;function checkCanConfigure(configOptionName){if(initialized){handleError("AjaxAppender: configuration option '"+

+configOptionName+"' may not be set after the appender has been initialized");return false;}

+return true;}

+this.getSessionId=function(){return sessionId;};this.setSessionId=function(sessionIdParam){sessionId=extractStringFromParam(sessionIdParam,null);this.layout.setCustomField("sessionid",sessionId);};this.setLayout=function(layoutParam){if(checkCanConfigure("layout")){this.layout=layoutParam;if(sessionId!==null){this.setSessionId(sessionId);}}};this.isTimed=function(){return timed;};this.setTimed=function(timedParam){if(checkCanConfigure("timed")){timed=bool(timedParam);}};this.getTimerInterval=function(){return timerInterval;};this.setTimerInterval=function(timerIntervalParam){if(checkCanConfigure("timerInterval")){timerInterval=extractIntFromParam(timerIntervalParam,timerInterval);}};this.isWaitForResponse=function(){return waitForResponse;};this.setWaitForResponse=function(waitForResponseParam){if(checkCanConfigure("waitForResponse")){waitForResponse=bool(waitForResponseParam);}};this.getBatchSize=function(){return batchSize;};this.setBatchSize=function(batchSizeParam){if(checkCanConfigure("batchSize")){batchSize=extractIntFromParam(batchSizeParam,batchSize);}};this.isSendAllOnUnload=function(){return sendAllOnUnload;};this.setSendAllOnUnload=function(sendAllOnUnloadParam){if(checkCanConfigure("sendAllOnUnload")){sendAllOnUnload=extractBooleanFromParam(sendAllOnUnloadParam,sendAllOnUnload);}};this.setRequestSuccessCallback=function(requestSuccessCallbackParam){requestSuccessCallback=extractFunctionFromParam(requestSuccessCallbackParam,requestSuccessCallback);};this.setFailCallback=function(failCallbackParam){failCallback=extractFunctionFromParam(failCallbackParam,failCallback);};this.getPostVarName=function(){return postVarName;};this.setPostVarName=function(postVarNameParam){if(checkCanConfigure("postVarName")){postVarName=extractStringFromParam(postVarNameParam,postVarName);}};this.getHeaders=function(){return headers;};this.addHeader=function(name,value){if(name.toLowerCase()=="content-type"){contentType=value;}else{headers.push({name:name,value:value});}};function sendAll(){if(isSupported&&enabled){sending=true;var currentRequestBatch;if(waitForResponse){if(queuedRequests.length>0){currentRequestBatch=queuedRequests.shift();sendRequest(preparePostData(currentRequestBatch),sendAll);}else{sending=false;if(timed){scheduleSending();}}}else{while((currentRequestBatch=queuedRequests.shift())){sendRequest(preparePostData(currentRequestBatch));}

+sending=false;if(timed){scheduleSending();}}}}

+this.sendAll=sendAll;function sendAllRemaining(){var sendingAnything=false;if(isSupported&&enabled){var actualBatchSize=appender.getLayout().allowBatching()?batchSize:1;var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);if(queuedLoggingEvents.length>=actualBatchSize){queuedRequests.push(batchedLoggingEvents);batchedLoggingEvents=[];}}

+if(batchedLoggingEvents.length>0){queuedRequests.push(batchedLoggingEvents);}

+sendingAnything=(queuedRequests.length>0);waitForResponse=false;timed=false;sendAll();}

+return sendingAnything;}

+this.sendAllRemaining=sendAllRemaining;function preparePostData(batchedLoggingEvents){var formattedMessages=[];var currentLoggingEvent;var postData="";while((currentLoggingEvent=batchedLoggingEvents.shift())){var currentFormattedMessage=appender.getLayout().format(currentLoggingEvent);if(appender.getLayout().ignoresThrowable()){currentFormattedMessage+=currentLoggingEvent.getThrowableStrRep();}

+formattedMessages.push(currentFormattedMessage);}

+if(batchedLoggingEvents.length==1){postData=formattedMessages.join("");}else{postData=appender.getLayout().batchHeader+

+formattedMessages.join(appender.getLayout().batchSeparator)+

+appender.getLayout().batchFooter;}

+if(contentType==appender.defaults.contentType){postData=appender.getLayout().returnsPostData?postData:urlEncode(postVarName)+"="+urlEncode(postData);if(postData.length>0){postData+="&";}

+postData+="layout="+urlEncode(appender.getLayout().toString());}

+return postData;}

+function scheduleSending(){window.setTimeout(sendAll,timerInterval);}

+function xmlHttpErrorHandler(){var msg="AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}}

+function sendRequest(postData,successCallback){try{var xmlHttp=getXmlHttp(xmlHttpErrorHandler);if(isSupported){if(xmlHttp.overrideMimeType){xmlHttp.overrideMimeType(appender.getLayout().getContentType());}

+xmlHttp.onreadystatechange=function(){if(xmlHttp.readyState==4){if(isHttpRequestSuccessful(xmlHttp)){if(requestSuccessCallback){requestSuccessCallback(xmlHttp);}

+if(successCallback){successCallback(xmlHttp);}}else{var msg="AjaxAppender.append: XMLHttpRequest request to URL "+

+url+" returned status code "+xmlHttp.status;handleError(msg);if(failCallback){failCallback(msg);}}

+xmlHttp.onreadystatechange=emptyFunction;xmlHttp=null;}};xmlHttp.open("POST",url,true);try{for(var i=0,header;header=headers[i++];){xmlHttp.setRequestHeader(header.name,header.value);}

+xmlHttp.setRequestHeader("Content-Type",contentType);}catch(headerEx){var msg="AjaxAppender.append: your browser's XMLHttpRequest implementation"+" does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}

+return;}

+xmlHttp.send(postData);}}catch(ex){var errMsg="AjaxAppender.append: error sending log message to "+url;handleError(errMsg,ex);isSupported=false;if(failCallback){failCallback(errMsg+". Details: "+getExceptionStringRep(ex));}}}

+this.append=function(loggingEvent){if(isSupported){if(!initialized){init();}

+queuedLoggingEvents.push(loggingEvent);var actualBatchSize=this.getLayout().allowBatching()?batchSize:1;if(queuedLoggingEvents.length>=actualBatchSize){var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);}

+queuedRequests.push(batchedLoggingEvents);if(!timed&&(!waitForResponse||(waitForResponse&&!sending))){sendAll();}}}};function init(){initialized=true;if(sendAllOnUnload){var oldBeforeUnload=window.onbeforeunload;window.onbeforeunload=function(){if(oldBeforeUnload){oldBeforeUnload();}

+if(sendAllRemaining()){return"Sending log messages";}};}

+if(timed){scheduleSending();}}}

+AjaxAppender.prototype=new Appender();AjaxAppender.prototype.defaults={waitForResponse:false,timed:false,timerInterval:1000,batchSize:1,sendAllOnUnload:false,requestSuccessCallback:null,failCallback:null,postVarName:"data",contentType:"application/x-www-form-urlencoded"};AjaxAppender.prototype.layout=new HttpPostDataLayout();AjaxAppender.prototype.toString=function(){return"AjaxAppender";};log4javascript.AjaxAppender=AjaxAppender;log4javascript.setDocumentReady=function(){pageLoaded=true;log4javascript.dispatchEvent("load",{});};if(window.addEventListener){window.addEventListener("load",log4javascript.setDocumentReady,false);}else if(window.attachEvent){window.attachEvent("onload",log4javascript.setDocumentReady);}else{var oldOnload=window.onload;if(typeof window.onload!="function"){window.onload=log4javascript.setDocumentReady;}else{window.onload=function(evt){if(oldOnload){oldOnload(evt);}

+log4javascript.setDocumentReady();};}}

+window.log4javascript=log4javascript;return log4javascript;})();

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_production_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_production_uncompressed.js
new file mode 100644
index 0000000..1a29621
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_production_uncompressed.js
@@ -0,0 +1,2290 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+/**

+ * log4javascript

+ *

+ * log4javascript is a logging framework for JavaScript based on log4j

+ * for Java. This file contains all core log4javascript code and is the only

+ * file required to use log4javascript, unless you require support for

+ * document.domain, in which case you will also need console.html, which must be

+ * stored in the same directory as the main log4javascript.js file.

+ *

+ * Author: Tim Down <tim@log4javascript.org>

+ * Version: 1.4.6

+ * Edition: log4javascript_production

+ * Build date: 19 March 2013

+ * Website: http://log4javascript.org

+ */

+

+/* -------------------------------------------------------------------------- */

+// Array-related stuff

+

+// Next three methods are solely for IE5, which is missing them

+if (!Array.prototype.push) {

+	Array.prototype.push = function() {

+		for (var i = 0, len = arguments.length; i < len; i++){

+			this[this.length] = arguments[i];

+		}

+		return this.length;

+	};

+}

+

+if (!Array.prototype.shift) {

+	Array.prototype.shift = function() {

+		if (this.length > 0) {

+			var firstItem = this[0];

+			for (var i = 0, len = this.length - 1; i < len; i++) {

+				this[i] = this[i + 1];

+			}

+			this.length = this.length - 1;

+			return firstItem;

+		}

+	};

+}

+

+if (!Array.prototype.splice) {

+	Array.prototype.splice = function(startIndex, deleteCount) {

+		var itemsAfterDeleted = this.slice(startIndex + deleteCount);

+		var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);

+		this.length = startIndex;

+		// Copy the arguments into a proper Array object

+		var argumentsArray = [];

+		for (var i = 0, len = arguments.length; i < len; i++) {

+			argumentsArray[i] = arguments[i];

+		}

+		var itemsToAppend = (argumentsArray.length > 2) ?

+			itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;

+		for (i = 0, len = itemsToAppend.length; i < len; i++) {

+			this.push(itemsToAppend[i]);

+		}

+		return itemsDeleted;

+	};

+}

+

+/* -------------------------------------------------------------------------- */

+

+var log4javascript = (function() {

+

+	function isUndefined(obj) {

+		return typeof obj == "undefined";

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// Custom event support

+

+	function EventSupport() {}

+

+	EventSupport.prototype = {

+		eventTypes: [],

+		eventListeners: {},

+		setEventTypes: function(eventTypesParam) {

+			if (eventTypesParam instanceof Array) {

+				this.eventTypes = eventTypesParam;

+				this.eventListeners = {};

+				for (var i = 0, len = this.eventTypes.length; i < len; i++) {

+					this.eventListeners[this.eventTypes[i]] = [];

+				}

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: setEventTypes: eventTypes parameter must be an Array");

+			}

+		},

+

+		addEventListener: function(eventType, listener) {

+			if (typeof listener == "function") {

+				if (!array_contains(this.eventTypes, eventType)) {

+					handleError("log4javascript.EventSupport [" + this + "]: addEventListener: no event called '" + eventType + "'");

+				}

+				this.eventListeners[eventType].push(listener);

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: addEventListener: listener must be a function");

+			}

+		},

+

+		removeEventListener: function(eventType, listener) {

+			if (typeof listener == "function") {

+				if (!array_contains(this.eventTypes, eventType)) {

+					handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: no event called '" + eventType + "'");

+				}

+				array_remove(this.eventListeners[eventType], listener);

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: listener must be a function");

+			}

+		},

+

+		dispatchEvent: function(eventType, eventArgs) {

+			if (array_contains(this.eventTypes, eventType)) {

+				var listeners = this.eventListeners[eventType];

+				for (var i = 0, len = listeners.length; i < len; i++) {

+					listeners[i](this, eventType, eventArgs);

+				}

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: dispatchEvent: no event called '" + eventType + "'");

+			}

+		}

+	};

+

+	/* -------------------------------------------------------------------------- */

+

+	var applicationStartDate = new Date();

+	var uniqueId = "log4javascript_" + applicationStartDate.getTime() + "_" +

+		Math.floor(Math.random() * 100000000);

+	var emptyFunction = function() {};

+	var newLine = "\r\n";

+	var pageLoaded = false;

+

+	// Create main log4javascript object; this will be assigned public properties

+	function Log4JavaScript() {}

+	Log4JavaScript.prototype = new EventSupport();

+

+	log4javascript = new Log4JavaScript();

+	log4javascript.version = "1.4.6";

+	log4javascript.edition = "log4javascript_production";

+

+	/* -------------------------------------------------------------------------- */

+	// Utility functions

+

+	function toStr(obj) {

+		if (obj && obj.toString) {

+			return obj.toString();

+		} else {

+			return String(obj);

+		}

+	}

+

+	function getExceptionMessage(ex) {

+		if (ex.message) {

+			return ex.message;

+		} else if (ex.description) {

+			return ex.description;

+		} else {

+			return toStr(ex);

+		}

+	}

+

+	// Gets the portion of the URL after the last slash

+	function getUrlFileName(url) {

+		var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\"));

+		return url.substr(lastSlashIndex + 1);

+	}

+

+	// Returns a nicely formatted representation of an error

+	function getExceptionStringRep(ex) {

+		if (ex) {

+			var exStr = "Exception: " + getExceptionMessage(ex);

+			try {

+				if (ex.lineNumber) {

+					exStr += " on line number " + ex.lineNumber;

+				}

+				if (ex.fileName) {

+					exStr += " in file " + getUrlFileName(ex.fileName);

+				}

+			} catch (localEx) {

+				logLog.warn("Unable to obtain file and line information for error");

+			}

+			if (showStackTraces && ex.stack) {

+				exStr += newLine + "Stack trace:" + newLine + ex.stack;

+			}

+			return exStr;

+		}

+		return null;

+	}

+

+	function bool(obj) {

+		return Boolean(obj);

+	}

+

+	function trim(str) {

+		return str.replace(/^\s+/, "").replace(/\s+$/, "");

+	}

+

+	function splitIntoLines(text) {

+		// Ensure all line breaks are \n only

+		var text2 = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");

+		return text2.split("\n");

+	}

+

+	var urlEncode = (typeof window.encodeURIComponent != "undefined") ?

+		function(str) {

+			return encodeURIComponent(str);

+		}: 

+		function(str) {

+			return escape(str).replace(/\+/g, "%2B").replace(/"/g, "%22").replace(/'/g, "%27").replace(/\//g, "%2F").replace(/=/g, "%3D");

+		};

+

+	var urlDecode = (typeof window.decodeURIComponent != "undefined") ?

+		function(str) {

+			return decodeURIComponent(str);

+		}: 

+		function(str) {

+			return unescape(str).replace(/%2B/g, "+").replace(/%22/g, "\"").replace(/%27/g, "'").replace(/%2F/g, "/").replace(/%3D/g, "=");

+		};

+

+	function array_remove(arr, val) {

+		var index = -1;

+		for (var i = 0, len = arr.length; i < len; i++) {

+			if (arr[i] === val) {

+				index = i;

+				break;

+			}

+		}

+		if (index >= 0) {

+			arr.splice(index, 1);

+			return true;

+		} else {

+			return false;

+		}

+	}

+

+	function array_contains(arr, val) {

+		for(var i = 0, len = arr.length; i < len; i++) {

+			if (arr[i] == val) {

+				return true;

+			}

+		}

+		return false;

+	}

+

+	function extractBooleanFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			return bool(param);

+		}

+	}

+

+	function extractStringFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			return String(param);

+		}

+	}

+

+	function extractIntFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			try {

+				var value = parseInt(param, 10);

+				return isNaN(value) ? defaultValue : value;

+			} catch (ex) {

+				logLog.warn("Invalid int param " + param, ex);

+				return defaultValue;

+			}

+		}

+	}

+

+	function extractFunctionFromParam(param, defaultValue) {

+		if (typeof param == "function") {

+			return param;

+		} else {

+			return defaultValue;

+		}

+	}

+

+	function isError(err) {

+		return (err instanceof Error);

+	}

+

+	if (!Function.prototype.apply){

+		Function.prototype.apply = function(obj, args) {

+			var methodName = "__apply__";

+			if (typeof obj[methodName] != "undefined") {

+				methodName += String(Math.random()).substr(2);

+			}

+			obj[methodName] = this;

+

+			var argsStrings = [];

+			for (var i = 0, len = args.length; i < len; i++) {

+				argsStrings[i] = "args[" + i + "]";

+			}

+			var script = "obj." + methodName + "(" + argsStrings.join(",") + ")";

+			var returnValue = eval(script);

+			delete obj[methodName];

+			return returnValue;

+		};

+	}

+

+	if (!Function.prototype.call){

+		Function.prototype.call = function(obj) {

+			var args = [];

+			for (var i = 1, len = arguments.length; i < len; i++) {

+				args[i - 1] = arguments[i];

+			}

+			return this.apply(obj, args);

+		};

+	}

+

+	function getListenersPropertyName(eventName) {

+		return "__log4javascript_listeners__" + eventName;

+	}

+

+	function addEvent(node, eventName, listener, useCapture, win) {

+		win = win ? win : window;

+		if (node.addEventListener) {

+			node.addEventListener(eventName, listener, useCapture);

+		} else if (node.attachEvent) {

+			node.attachEvent("on" + eventName, listener);

+		} else {

+			var propertyName = getListenersPropertyName(eventName);

+			if (!node[propertyName]) {

+				node[propertyName] = [];

+				// Set event handler

+				node["on" + eventName] = function(evt) {

+					evt = getEvent(evt, win);

+					var listenersPropertyName = getListenersPropertyName(eventName);

+

+					// Clone the array of listeners to leave the original untouched

+					var listeners = this[listenersPropertyName].concat([]);

+					var currentListener;

+

+					// Call each listener in turn

+					while ((currentListener = listeners.shift())) {

+						currentListener.call(this, evt);

+					}

+				};

+			}

+			node[propertyName].push(listener);

+		}

+	}

+

+	function removeEvent(node, eventName, listener, useCapture) {

+		if (node.removeEventListener) {

+			node.removeEventListener(eventName, listener, useCapture);

+		} else if (node.detachEvent) {

+			node.detachEvent("on" + eventName, listener);

+		} else {

+			var propertyName = getListenersPropertyName(eventName);

+			if (node[propertyName]) {

+				array_remove(node[propertyName], listener);

+			}

+		}

+	}

+

+	function getEvent(evt, win) {

+		win = win ? win : window;

+		return evt ? evt : win.event;

+	}

+

+	function stopEventPropagation(evt) {

+		if (evt.stopPropagation) {

+			evt.stopPropagation();

+		} else if (typeof evt.cancelBubble != "undefined") {

+			evt.cancelBubble = true;

+		}

+		evt.returnValue = false;

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// Simple logging for log4javascript itself

+

+	var logLog = {

+		quietMode: false,

+

+		debugMessages: [],

+

+		setQuietMode: function(quietMode) {

+			this.quietMode = bool(quietMode);

+		},

+

+		numberOfErrors: 0,

+

+		alertAllErrors: false,

+

+		setAlertAllErrors: function(alertAllErrors) {

+			this.alertAllErrors = alertAllErrors;

+		},

+

+		debug: function(message) {

+			this.debugMessages.push(message);

+		},

+

+		displayDebug: function() {

+			alert(this.debugMessages.join(newLine));

+		},

+

+		warn: function(message, exception) {

+		},

+

+		error: function(message, exception) {

+			if (++this.numberOfErrors == 1 || this.alertAllErrors) {

+				if (!this.quietMode) {

+					var alertMessage = "log4javascript error: " + message;

+					if (exception) {

+						alertMessage += newLine + newLine + "Original error: " + getExceptionStringRep(exception);

+					}

+					alert(alertMessage);

+				}

+			}

+		}

+	};

+	log4javascript.logLog = logLog;

+

+	log4javascript.setEventTypes(["load", "error"]);

+

+	function handleError(message, exception) {

+		logLog.error(message, exception);

+		log4javascript.dispatchEvent("error", { "message": message, "exception": exception });

+	}

+

+	log4javascript.handleError = handleError;

+

+	/* ---------------------------------------------------------------------- */

+

+	var enabled = !((typeof log4javascript_disabled != "undefined") &&

+					log4javascript_disabled);

+

+	log4javascript.setEnabled = function(enable) {

+		enabled = bool(enable);

+	};

+

+	log4javascript.isEnabled = function() {

+		return enabled;

+	};

+

+	var useTimeStampsInMilliseconds = true;

+

+	log4javascript.setTimeStampsInMilliseconds = function(timeStampsInMilliseconds) {

+		useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);

+	};

+

+	log4javascript.isTimeStampsInMilliseconds = function() {

+		return useTimeStampsInMilliseconds;

+	};

+	

+

+	// This evaluates the given expression in the current scope, thus allowing

+	// scripts to access private variables. Particularly useful for testing

+	log4javascript.evalInScope = function(expr) {

+		return eval(expr);

+	};

+

+	var showStackTraces = false;

+

+	log4javascript.setShowStackTraces = function(show) {

+		showStackTraces = bool(show);

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Levels

+

+	var Level = function(level, name) {

+		this.level = level;

+		this.name = name;

+	};

+

+	Level.prototype = {

+		toString: function() {

+			return this.name;

+		},

+		equals: function(level) {

+			return this.level == level.level;

+		},

+		isGreaterOrEqual: function(level) {

+			return this.level >= level.level;

+		}

+	};

+

+	Level.ALL = new Level(Number.MIN_VALUE, "ALL");

+	Level.TRACE = new Level(10000, "TRACE");

+	Level.DEBUG = new Level(20000, "DEBUG");

+	Level.INFO = new Level(30000, "INFO");

+	Level.WARN = new Level(40000, "WARN");

+	Level.ERROR = new Level(50000, "ERROR");

+	Level.FATAL = new Level(60000, "FATAL");

+	Level.OFF = new Level(Number.MAX_VALUE, "OFF");

+

+	log4javascript.Level = Level;

+

+	/* ---------------------------------------------------------------------- */

+	// Timers

+

+	function Timer(name, level) {

+		this.name = name;

+		this.level = isUndefined(level) ? Level.INFO : level;

+		this.start = new Date();

+	}

+

+	Timer.prototype.getElapsedTime = function() {

+		return new Date().getTime() - this.start.getTime();

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Loggers

+

+	var anonymousLoggerName = "[anonymous]";

+	var defaultLoggerName = "[default]";

+	var nullLoggerName = "[null]";

+	var rootLoggerName = "root";

+

+	function Logger(name) {

+		this.name = name;

+		this.parent = null;

+		this.children = [];

+

+		var appenders = [];

+		var loggerLevel = null;

+		var isRoot = (this.name === rootLoggerName);

+		var isNull = (this.name === nullLoggerName);

+

+		var appenderCache = null;

+		var appenderCacheInvalidated = false;

+		

+		this.addChild = function(childLogger) {

+			this.children.push(childLogger);

+			childLogger.parent = this;

+			childLogger.invalidateAppenderCache();

+		};

+

+		// Additivity

+		var additive = true;

+		this.getAdditivity = function() {

+			return additive;

+		};

+

+		this.setAdditivity = function(additivity) {

+			var valueChanged = (additive != additivity);

+			additive = additivity;

+			if (valueChanged) {

+				this.invalidateAppenderCache();

+			}

+		};

+

+		// Create methods that use the appenders variable in this scope

+		this.addAppender = function(appender) {

+			if (isNull) {

+				handleError("Logger.addAppender: you may not add an appender to the null logger");

+			} else {

+				if (appender instanceof log4javascript.Appender) {

+					if (!array_contains(appenders, appender)) {

+						appenders.push(appender);

+						appender.setAddedToLogger(this);

+						this.invalidateAppenderCache();

+					}

+				} else {

+					handleError("Logger.addAppender: appender supplied ('" +

+						toStr(appender) + "') is not a subclass of Appender");

+				}

+			}

+		};

+

+		this.removeAppender = function(appender) {

+			array_remove(appenders, appender);

+			appender.setRemovedFromLogger(this);

+			this.invalidateAppenderCache();

+		};

+

+		this.removeAllAppenders = function() {

+			var appenderCount = appenders.length;

+			if (appenderCount > 0) {

+				for (var i = 0; i < appenderCount; i++) {

+					appenders[i].setRemovedFromLogger(this);

+				}

+				appenders.length = 0;

+				this.invalidateAppenderCache();

+			}

+		};

+

+		this.getEffectiveAppenders = function() {

+			if (appenderCache === null || appenderCacheInvalidated) {

+				// Build appender cache

+				var parentEffectiveAppenders = (isRoot || !this.getAdditivity()) ?

+					[] : this.parent.getEffectiveAppenders();

+				appenderCache = parentEffectiveAppenders.concat(appenders);

+				appenderCacheInvalidated = false;

+			}

+			return appenderCache;

+		};

+		

+		this.invalidateAppenderCache = function() {

+			appenderCacheInvalidated = true;

+			for (var i = 0, len = this.children.length; i < len; i++) {

+				this.children[i].invalidateAppenderCache();

+			}

+		};

+

+		this.log = function(level, params) {

+			if (enabled && level.isGreaterOrEqual(this.getEffectiveLevel())) {

+				// Check whether last param is an exception

+				var exception;

+				var finalParamIndex = params.length - 1;

+				var lastParam = params[finalParamIndex];

+				if (params.length > 1 && isError(lastParam)) {

+					exception = lastParam;

+					finalParamIndex--;

+				}

+

+				// Construct genuine array for the params

+				var messages = [];

+				for (var i = 0; i <= finalParamIndex; i++) {

+					messages[i] = params[i];

+				}

+

+				var loggingEvent = new LoggingEvent(

+					this, new Date(), level, messages, exception);

+

+				this.callAppenders(loggingEvent);

+			}

+		};

+

+		this.callAppenders = function(loggingEvent) {

+			var effectiveAppenders = this.getEffectiveAppenders();

+			for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+				effectiveAppenders[i].doAppend(loggingEvent);

+			}

+		};

+

+		this.setLevel = function(level) {

+			// Having a level of null on the root logger would be very bad.

+			if (isRoot && level === null) {

+				handleError("Logger.setLevel: you cannot set the level of the root logger to null");

+			} else if (level instanceof Level) {

+				loggerLevel = level;

+			} else {

+				handleError("Logger.setLevel: level supplied to logger " +

+					this.name + " is not an instance of log4javascript.Level");

+			}

+		};

+

+		this.getLevel = function() {

+			return loggerLevel;

+		};

+

+		this.getEffectiveLevel = function() {

+			for (var logger = this; logger !== null; logger = logger.parent) {

+				var level = logger.getLevel();

+				if (level !== null) {

+					return level;

+				}

+			}

+		};

+

+		this.group = function(name, initiallyExpanded) {

+			if (enabled) {

+				var effectiveAppenders = this.getEffectiveAppenders();

+				for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+					effectiveAppenders[i].group(name, initiallyExpanded);

+				}

+			}

+		};

+

+		this.groupEnd = function() {

+			if (enabled) {

+				var effectiveAppenders = this.getEffectiveAppenders();

+				for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+					effectiveAppenders[i].groupEnd();

+				}

+			}

+		};

+

+		var timers = {};

+

+		this.time = function(name, level) {

+			if (enabled) {

+				if (isUndefined(name)) {

+					handleError("Logger.time: a name for the timer must be supplied");

+				} else if (level && !(level instanceof Level)) {

+					handleError("Logger.time: level supplied to timer " +

+						name + " is not an instance of log4javascript.Level");

+				} else {

+					timers[name] = new Timer(name, level);

+				}

+			}

+		};

+

+		this.timeEnd = function(name) {

+			if (enabled) {

+				if (isUndefined(name)) {

+					handleError("Logger.timeEnd: a name for the timer must be supplied");

+				} else if (timers[name]) {

+					var timer = timers[name];

+					var milliseconds = timer.getElapsedTime();

+					this.log(timer.level, ["Timer " + toStr(name) + " completed in " + milliseconds + "ms"]);

+					delete timers[name];

+				} else {

+					logLog.warn("Logger.timeEnd: no timer found with name " + name);

+				}

+			}

+		};

+

+		this.assert = function(expr) {

+			if (enabled && !expr) {

+				var args = [];

+				for (var i = 1, len = arguments.length; i < len; i++) {

+					args.push(arguments[i]);

+				}

+				args = (args.length > 0) ? args : ["Assertion Failure"];

+				args.push(newLine);

+				args.push(expr);

+				this.log(Level.ERROR, args);

+			}

+		};

+

+		this.toString = function() {

+			return "Logger[" + this.name + "]";

+		};

+	}

+

+	Logger.prototype = {

+		trace: function() {

+			this.log(Level.TRACE, arguments);

+		},

+

+		debug: function() {

+			this.log(Level.DEBUG, arguments);

+		},

+

+		info: function() {

+			this.log(Level.INFO, arguments);

+		},

+

+		warn: function() {

+			this.log(Level.WARN, arguments);

+		},

+

+		error: function() {

+			this.log(Level.ERROR, arguments);

+		},

+

+		fatal: function() {

+			this.log(Level.FATAL, arguments);

+		},

+

+		isEnabledFor: function(level) {

+			return level.isGreaterOrEqual(this.getEffectiveLevel());

+		},

+

+		isTraceEnabled: function() {

+			return this.isEnabledFor(Level.TRACE);

+		},

+

+		isDebugEnabled: function() {

+			return this.isEnabledFor(Level.DEBUG);

+		},

+

+		isInfoEnabled: function() {

+			return this.isEnabledFor(Level.INFO);

+		},

+

+		isWarnEnabled: function() {

+			return this.isEnabledFor(Level.WARN);

+		},

+

+		isErrorEnabled: function() {

+			return this.isEnabledFor(Level.ERROR);

+		},

+

+		isFatalEnabled: function() {

+			return this.isEnabledFor(Level.FATAL);

+		}

+	};

+

+	Logger.prototype.trace.isEntryPoint = true;

+	Logger.prototype.debug.isEntryPoint = true;

+	Logger.prototype.info.isEntryPoint = true;

+	Logger.prototype.warn.isEntryPoint = true;

+	Logger.prototype.error.isEntryPoint = true;

+	Logger.prototype.fatal.isEntryPoint = true;

+

+	/* ---------------------------------------------------------------------- */

+	// Logger access methods

+

+	// Hashtable of loggers keyed by logger name

+	var loggers = {};

+	var loggerNames = [];

+

+	var ROOT_LOGGER_DEFAULT_LEVEL = Level.DEBUG;

+	var rootLogger = new Logger(rootLoggerName);

+	rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);

+

+	log4javascript.getRootLogger = function() {

+		return rootLogger;

+	};

+

+	log4javascript.getLogger = function(loggerName) {

+		// Use default logger if loggerName is not specified or invalid

+		if (!(typeof loggerName == "string")) {

+			loggerName = anonymousLoggerName;

+			logLog.warn("log4javascript.getLogger: non-string logger name "	+

+				toStr(loggerName) + " supplied, returning anonymous logger");

+		}

+

+		// Do not allow retrieval of the root logger by name

+		if (loggerName == rootLoggerName) {

+			handleError("log4javascript.getLogger: root logger may not be obtained by name");

+		}

+

+		// Create the logger for this name if it doesn't already exist

+		if (!loggers[loggerName]) {

+			var logger = new Logger(loggerName);

+			loggers[loggerName] = logger;

+			loggerNames.push(loggerName);

+

+			// Set up parent logger, if it doesn't exist

+			var lastDotIndex = loggerName.lastIndexOf(".");

+			var parentLogger;

+			if (lastDotIndex > -1) {

+				var parentLoggerName = loggerName.substring(0, lastDotIndex);

+				parentLogger = log4javascript.getLogger(parentLoggerName); // Recursively sets up grandparents etc.

+			} else {

+				parentLogger = rootLogger;

+			}

+			parentLogger.addChild(logger);

+		}

+		return loggers[loggerName];

+	};

+

+	var defaultLogger = null;

+	log4javascript.getDefaultLogger = function() {

+		if (!defaultLogger) {

+			defaultLogger = log4javascript.getLogger(defaultLoggerName);

+			var a = new log4javascript.PopUpAppender();

+			defaultLogger.addAppender(a);

+		}

+		return defaultLogger;

+	};

+

+	var nullLogger = null;

+	log4javascript.getNullLogger = function() {

+		if (!nullLogger) {

+			nullLogger = new Logger(nullLoggerName);

+			nullLogger.setLevel(Level.OFF);

+		}

+		return nullLogger;

+	};

+

+	// Destroys all loggers

+	log4javascript.resetConfiguration = function() {

+		rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);

+		loggers = {};

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Logging events

+

+	var LoggingEvent = function(logger, timeStamp, level, messages,

+			exception) {

+		this.logger = logger;

+		this.timeStamp = timeStamp;

+		this.timeStampInMilliseconds = timeStamp.getTime();

+		this.timeStampInSeconds = Math.floor(this.timeStampInMilliseconds / 1000);

+		this.milliseconds = this.timeStamp.getMilliseconds();

+		this.level = level;

+		this.messages = messages;

+		this.exception = exception;

+	};

+

+	LoggingEvent.prototype = {

+		getThrowableStrRep: function() {

+			return this.exception ?

+				getExceptionStringRep(this.exception) : "";

+		},

+		getCombinedMessages: function() {

+			return (this.messages.length == 1) ? this.messages[0] :

+				   this.messages.join(newLine);

+		},

+		toString: function() {

+			return "LoggingEvent[" + this.level + "]";

+		}

+	};

+

+	log4javascript.LoggingEvent = LoggingEvent;

+

+	/* ---------------------------------------------------------------------- */

+	// Layout prototype

+

+	var Layout = function() {

+	};

+

+	Layout.prototype = {

+		defaults: {

+			loggerKey: "logger",

+			timeStampKey: "timestamp",

+			millisecondsKey: "milliseconds",

+			levelKey: "level",

+			messageKey: "message",

+			exceptionKey: "exception",

+			urlKey: "url"

+		},

+		loggerKey: "logger",

+		timeStampKey: "timestamp",

+		millisecondsKey: "milliseconds",

+		levelKey: "level",

+		messageKey: "message",

+		exceptionKey: "exception",

+		urlKey: "url",

+		batchHeader: "",

+		batchFooter: "",

+		batchSeparator: "",

+		returnsPostData: false,

+		overrideTimeStampsSetting: false,

+		useTimeStampsInMilliseconds: null,

+

+		format: function() {

+			handleError("Layout.format: layout supplied has no format() method");

+		},

+

+		ignoresThrowable: function() {

+			handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");

+		},

+

+		getContentType: function() {

+			return "text/plain";

+		},

+

+		allowBatching: function() {

+			return true;

+		},

+

+		setTimeStampsInMilliseconds: function(timeStampsInMilliseconds) {

+			this.overrideTimeStampsSetting = true;

+			this.useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);

+		},

+

+		isTimeStampsInMilliseconds: function() {

+			return this.overrideTimeStampsSetting ?

+				this.useTimeStampsInMilliseconds : useTimeStampsInMilliseconds;

+		},

+

+		getTimeStampValue: function(loggingEvent) {

+			return this.isTimeStampsInMilliseconds() ?

+				loggingEvent.timeStampInMilliseconds : loggingEvent.timeStampInSeconds;

+		},

+

+		getDataValues: function(loggingEvent, combineMessages) {

+			var dataValues = [

+				[this.loggerKey, loggingEvent.logger.name],

+				[this.timeStampKey, this.getTimeStampValue(loggingEvent)],

+				[this.levelKey, loggingEvent.level.name],

+				[this.urlKey, window.location.href],

+				[this.messageKey, combineMessages ? loggingEvent.getCombinedMessages() : loggingEvent.messages]

+			];

+			if (!this.isTimeStampsInMilliseconds()) {

+				dataValues.push([this.millisecondsKey, loggingEvent.milliseconds]);

+			}

+			if (loggingEvent.exception) {

+				dataValues.push([this.exceptionKey, getExceptionStringRep(loggingEvent.exception)]);

+			}

+			if (this.hasCustomFields()) {

+				for (var i = 0, len = this.customFields.length; i < len; i++) {

+					var val = this.customFields[i].value;

+

+					// Check if the value is a function. If so, execute it, passing it the

+					// current layout and the logging event

+					if (typeof val === "function") {

+						val = val(this, loggingEvent);

+					}

+					dataValues.push([this.customFields[i].name, val]);

+				}

+			}

+			return dataValues;

+		},

+

+		setKeys: function(loggerKey, timeStampKey, levelKey, messageKey,

+				exceptionKey, urlKey, millisecondsKey) {

+			this.loggerKey = extractStringFromParam(loggerKey, this.defaults.loggerKey);

+			this.timeStampKey = extractStringFromParam(timeStampKey, this.defaults.timeStampKey);

+			this.levelKey = extractStringFromParam(levelKey, this.defaults.levelKey);

+			this.messageKey = extractStringFromParam(messageKey, this.defaults.messageKey);

+			this.exceptionKey = extractStringFromParam(exceptionKey, this.defaults.exceptionKey);

+			this.urlKey = extractStringFromParam(urlKey, this.defaults.urlKey);

+			this.millisecondsKey = extractStringFromParam(millisecondsKey, this.defaults.millisecondsKey);

+		},

+

+		setCustomField: function(name, value) {

+			var fieldUpdated = false;

+			for (var i = 0, len = this.customFields.length; i < len; i++) {

+				if (this.customFields[i].name === name) {

+					this.customFields[i].value = value;

+					fieldUpdated = true;

+				}

+			}

+			if (!fieldUpdated) {

+				this.customFields.push({"name": name, "value": value});

+			}

+		},

+

+		hasCustomFields: function() {

+			return (this.customFields.length > 0);

+		},

+

+		toString: function() {

+			handleError("Layout.toString: all layouts must override this method");

+		}

+	};

+

+	log4javascript.Layout = Layout;

+

+	/* ---------------------------------------------------------------------- */

+	// Appender prototype

+

+	var Appender = function() {};

+

+	Appender.prototype = new EventSupport();

+

+	Appender.prototype.layout = new PatternLayout();

+	Appender.prototype.threshold = Level.ALL;

+	Appender.prototype.loggers = [];

+

+	// Performs threshold checks before delegating actual logging to the

+	// subclass's specific append method.

+	Appender.prototype.doAppend = function(loggingEvent) {

+		if (enabled && loggingEvent.level.level >= this.threshold.level) {

+			this.append(loggingEvent);

+		}

+	};

+

+	Appender.prototype.append = function(loggingEvent) {};

+

+	Appender.prototype.setLayout = function(layout) {

+		if (layout instanceof Layout) {

+			this.layout = layout;

+		} else {

+			handleError("Appender.setLayout: layout supplied to " +

+				this.toString() + " is not a subclass of Layout");

+		}

+	};

+

+	Appender.prototype.getLayout = function() {

+		return this.layout;

+	};

+

+	Appender.prototype.setThreshold = function(threshold) {

+		if (threshold instanceof Level) {

+			this.threshold = threshold;

+		} else {

+			handleError("Appender.setThreshold: threshold supplied to " +

+				this.toString() + " is not a subclass of Level");

+		}

+	};

+

+	Appender.prototype.getThreshold = function() {

+		return this.threshold;

+	};

+

+	Appender.prototype.setAddedToLogger = function(logger) {

+		this.loggers.push(logger);

+	};

+

+	Appender.prototype.setRemovedFromLogger = function(logger) {

+		array_remove(this.loggers, logger);

+	};

+

+	Appender.prototype.group = emptyFunction;

+	Appender.prototype.groupEnd = emptyFunction;

+

+	Appender.prototype.toString = function() {

+		handleError("Appender.toString: all appenders must override this method");

+	};

+

+	log4javascript.Appender = Appender;

+

+	/* ---------------------------------------------------------------------- */

+	// SimpleLayout 

+

+	function SimpleLayout() {

+		this.customFields = [];

+	}

+

+	SimpleLayout.prototype = new Layout();

+

+	SimpleLayout.prototype.format = function(loggingEvent) {

+		return loggingEvent.level.name + " - " + loggingEvent.getCombinedMessages();

+	};

+

+	SimpleLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	SimpleLayout.prototype.toString = function() {

+	    return "SimpleLayout";

+	};

+

+	log4javascript.SimpleLayout = SimpleLayout;

+	/* ----------------------------------------------------------------------- */

+	// NullLayout 

+

+	function NullLayout() {

+		this.customFields = [];

+	}

+

+	NullLayout.prototype = new Layout();

+

+	NullLayout.prototype.format = function(loggingEvent) {

+		return loggingEvent.messages;

+	};

+

+	NullLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	NullLayout.prototype.toString = function() {

+	    return "NullLayout";

+	};

+

+	log4javascript.NullLayout = NullLayout;

+/* ---------------------------------------------------------------------- */

+	// XmlLayout

+

+	function XmlLayout(combineMessages) {

+		this.combineMessages = extractBooleanFromParam(combineMessages, true);

+		this.customFields = [];

+	}

+

+	XmlLayout.prototype = new Layout();

+

+	XmlLayout.prototype.isCombinedMessages = function() {

+		return this.combineMessages;

+	};

+

+	XmlLayout.prototype.getContentType = function() {

+		return "text/xml";

+	};

+

+	XmlLayout.prototype.escapeCdata = function(str) {

+		return str.replace(/\]\]>/, "]]>]]&gt;<![CDATA[");

+	};

+

+	XmlLayout.prototype.format = function(loggingEvent) {

+		var layout = this;

+		var i, len;

+		function formatMessage(message) {

+			message = (typeof message === "string") ? message : toStr(message);

+			return "<log4javascript:message><![CDATA[" +

+				layout.escapeCdata(message) + "]]></log4javascript:message>";

+		}

+

+		var str = "<log4javascript:event logger=\"" + loggingEvent.logger.name +

+			"\" timestamp=\"" + this.getTimeStampValue(loggingEvent) + "\"";

+		if (!this.isTimeStampsInMilliseconds()) {

+			str += " milliseconds=\"" + loggingEvent.milliseconds + "\"";

+		}

+		str += " level=\"" + loggingEvent.level.name + "\">" + newLine;

+		if (this.combineMessages) {

+			str += formatMessage(loggingEvent.getCombinedMessages());

+		} else {

+			str += "<log4javascript:messages>" + newLine;

+			for (i = 0, len = loggingEvent.messages.length; i < len; i++) {

+				str += formatMessage(loggingEvent.messages[i]) + newLine;

+			}

+			str += "</log4javascript:messages>" + newLine;

+		}

+		if (this.hasCustomFields()) {

+			for (i = 0, len = this.customFields.length; i < len; i++) {

+				str += "<log4javascript:customfield name=\"" +

+					this.customFields[i].name + "\"><![CDATA[" +

+					this.customFields[i].value.toString() +

+					"]]></log4javascript:customfield>" + newLine;

+			}

+		}

+		if (loggingEvent.exception) {

+			str += "<log4javascript:exception><![CDATA[" +

+				getExceptionStringRep(loggingEvent.exception) +

+				"]]></log4javascript:exception>" + newLine;

+		}

+		str += "</log4javascript:event>" + newLine + newLine;

+		return str;

+	};

+

+	XmlLayout.prototype.ignoresThrowable = function() {

+	    return false;

+	};

+

+	XmlLayout.prototype.toString = function() {

+	    return "XmlLayout";

+	};

+

+	log4javascript.XmlLayout = XmlLayout;

+	/* ---------------------------------------------------------------------- */

+	// JsonLayout related

+

+	function escapeNewLines(str) {

+		return str.replace(/\r\n|\r|\n/g, "\\r\\n");

+	}

+

+	function JsonLayout(readable, combineMessages) {

+		this.readable = extractBooleanFromParam(readable, false);

+		this.combineMessages = extractBooleanFromParam(combineMessages, true);

+		this.batchHeader = this.readable ? "[" + newLine : "[";

+		this.batchFooter = this.readable ? "]" + newLine : "]";

+		this.batchSeparator = this.readable ? "," + newLine : ",";

+		this.setKeys();

+		this.colon = this.readable ? ": " : ":";

+		this.tab = this.readable ? "\t" : "";

+		this.lineBreak = this.readable ? newLine : "";

+		this.customFields = [];

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// JsonLayout

+

+	JsonLayout.prototype = new Layout();

+

+	JsonLayout.prototype.isReadable = function() {

+		return this.readable;

+	};

+

+	JsonLayout.prototype.isCombinedMessages = function() {

+		return this.combineMessages;

+	};

+

+    JsonLayout.prototype.format = function(loggingEvent) {

+        var layout = this;

+        var dataValues = this.getDataValues(loggingEvent, this.combineMessages);

+        var str = "{" + this.lineBreak;

+        var i, len;

+

+        function formatValue(val, prefix, expand) {

+            // Check the type of the data value to decide whether quotation marks

+            // or expansion are required

+            var formattedValue;

+            var valType = typeof val;

+            if (val instanceof Date) {

+                formattedValue = String(val.getTime());

+            } else if (expand && (val instanceof Array)) {

+                formattedValue = "[" + layout.lineBreak;

+                for (var i = 0, len = val.length; i < len; i++) {

+                    var childPrefix = prefix + layout.tab;

+                    formattedValue += childPrefix + formatValue(val[i], childPrefix, false);

+                    if (i < val.length - 1) {

+                        formattedValue += ",";

+                    }

+                    formattedValue += layout.lineBreak;

+                }

+                formattedValue += prefix + "]";

+            } else if (valType !== "number" && valType !== "boolean") {

+                formattedValue = "\"" + escapeNewLines(toStr(val).replace(/\"/g, "\\\"")) + "\"";

+            } else {

+                formattedValue = val;

+            }

+            return formattedValue;

+        }

+

+        for (i = 0, len = dataValues.length - 1; i <= len; i++) {

+            str += this.tab + "\"" + dataValues[i][0] + "\"" + this.colon + formatValue(dataValues[i][1], this.tab, true);

+            if (i < len) {

+                str += ",";

+            }

+            str += this.lineBreak;

+        }

+

+        str += "}" + this.lineBreak;

+        return str;

+    };

+

+	JsonLayout.prototype.ignoresThrowable = function() {

+	    return false;

+	};

+

+	JsonLayout.prototype.toString = function() {

+	    return "JsonLayout";

+	};

+

+	JsonLayout.prototype.getContentType = function() {

+		return "application/json";

+	};

+

+	log4javascript.JsonLayout = JsonLayout;

+	/* ---------------------------------------------------------------------- */

+	// HttpPostDataLayout

+

+	function HttpPostDataLayout() {

+		this.setKeys();

+		this.customFields = [];

+		this.returnsPostData = true;

+	}

+

+	HttpPostDataLayout.prototype = new Layout();

+

+	// Disable batching

+	HttpPostDataLayout.prototype.allowBatching = function() {

+		return false;

+	};

+

+	HttpPostDataLayout.prototype.format = function(loggingEvent) {

+		var dataValues = this.getDataValues(loggingEvent);

+		var queryBits = [];

+		for (var i = 0, len = dataValues.length; i < len; i++) {

+			var val = (dataValues[i][1] instanceof Date) ?

+				String(dataValues[i][1].getTime()) : dataValues[i][1];

+			queryBits.push(urlEncode(dataValues[i][0]) + "=" + urlEncode(val));

+		}

+		return queryBits.join("&");

+	};

+

+	HttpPostDataLayout.prototype.ignoresThrowable = function(loggingEvent) {

+	    return false;

+	};

+

+	HttpPostDataLayout.prototype.toString = function() {

+	    return "HttpPostDataLayout";

+	};

+

+	log4javascript.HttpPostDataLayout = HttpPostDataLayout;

+	/* ---------------------------------------------------------------------- */

+	// formatObjectExpansion

+

+	function formatObjectExpansion(obj, depth, indentation) {

+		var objectsExpanded = [];

+

+		function doFormat(obj, depth, indentation) {

+			var i, j, len, childDepth, childIndentation, childLines, expansion,

+				childExpansion;

+

+			if (!indentation) {

+				indentation = "";

+			}

+

+			function formatString(text) {

+				var lines = splitIntoLines(text);

+				for (var j = 1, jLen = lines.length; j < jLen; j++) {

+					lines[j] = indentation + lines[j];

+				}

+				return lines.join(newLine);

+			}

+

+			if (obj === null) {

+				return "null";

+			} else if (typeof obj == "undefined") {

+				return "undefined";

+			} else if (typeof obj == "string") {

+				return formatString(obj);

+			} else if (typeof obj == "object" && array_contains(objectsExpanded, obj)) {

+				try {

+					expansion = toStr(obj);

+				} catch (ex) {

+					expansion = "Error formatting property. Details: " + getExceptionStringRep(ex);

+				}

+				return expansion + " [already expanded]";

+			} else if ((obj instanceof Array) && depth > 0) {

+				objectsExpanded.push(obj);

+				expansion = "[" + newLine;

+				childDepth = depth - 1;

+				childIndentation = indentation + "  ";

+				childLines = [];

+				for (i = 0, len = obj.length; i < len; i++) {

+					try {

+						childExpansion = doFormat(obj[i], childDepth, childIndentation);

+						childLines.push(childIndentation + childExpansion);

+					} catch (ex) {

+						childLines.push(childIndentation + "Error formatting array member. Details: " +

+							getExceptionStringRep(ex) + "");

+					}

+				}

+				expansion += childLines.join("," + newLine) + newLine + indentation + "]";

+				return expansion;

+            } else if (Object.prototype.toString.call(obj) == "[object Date]") {

+                return obj.toString();

+			} else if (typeof obj == "object" && depth > 0) {

+				objectsExpanded.push(obj);

+				expansion = "{" + newLine;

+				childDepth = depth - 1;

+				childIndentation = indentation + "  ";

+				childLines = [];

+				for (i in obj) {

+					try {

+						childExpansion = doFormat(obj[i], childDepth, childIndentation);

+						childLines.push(childIndentation + i + ": " + childExpansion);

+					} catch (ex) {

+						childLines.push(childIndentation + i + ": Error formatting property. Details: " +

+							getExceptionStringRep(ex));

+					}

+				}

+				expansion += childLines.join("," + newLine) + newLine + indentation + "}";

+				return expansion;

+			} else {

+				return formatString(toStr(obj));

+			}

+		}

+		return doFormat(obj, depth, indentation);

+	}

+	/* ---------------------------------------------------------------------- */

+	// Date-related stuff

+

+	var SimpleDateFormat;

+

+	(function() {

+		var regex = /('[^']*')|(G+|y+|M+|w+|W+|D+|d+|F+|E+|a+|H+|k+|K+|h+|m+|s+|S+|Z+)|([a-zA-Z]+)|([^a-zA-Z']+)/;

+		var monthNames = ["January", "February", "March", "April", "May", "June",

+			"July", "August", "September", "October", "November", "December"];

+		var dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

+		var TEXT2 = 0, TEXT3 = 1, NUMBER = 2, YEAR = 3, MONTH = 4, TIMEZONE = 5;

+		var types = {

+			G : TEXT2,

+			y : YEAR,

+			M : MONTH,

+			w : NUMBER,

+			W : NUMBER,

+			D : NUMBER,

+			d : NUMBER,

+			F : NUMBER,

+			E : TEXT3,

+			a : TEXT2,

+			H : NUMBER,

+			k : NUMBER,

+			K : NUMBER,

+			h : NUMBER,

+			m : NUMBER,

+			s : NUMBER,

+			S : NUMBER,

+			Z : TIMEZONE

+		};

+		var ONE_DAY = 24 * 60 * 60 * 1000;

+		var ONE_WEEK = 7 * ONE_DAY;

+		var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK = 1;

+

+		var newDateAtMidnight = function(year, month, day) {

+			var d = new Date(year, month, day, 0, 0, 0);

+			d.setMilliseconds(0);

+			return d;

+		};

+

+		Date.prototype.getDifference = function(date) {

+			return this.getTime() - date.getTime();

+		};

+

+		Date.prototype.isBefore = function(d) {

+			return this.getTime() < d.getTime();

+		};

+

+		Date.prototype.getUTCTime = function() {

+			return Date.UTC(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours(), this.getMinutes(),

+					this.getSeconds(), this.getMilliseconds());

+		};

+

+		Date.prototype.getTimeSince = function(d) {

+			return this.getUTCTime() - d.getUTCTime();

+		};

+

+		Date.prototype.getPreviousSunday = function() {

+			// Using midday avoids any possibility of DST messing things up

+			var midday = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 12, 0, 0);

+			var previousSunday = new Date(midday.getTime() - this.getDay() * ONE_DAY);

+			return newDateAtMidnight(previousSunday.getFullYear(), previousSunday.getMonth(),

+					previousSunday.getDate());

+		};

+

+		Date.prototype.getWeekInYear = function(minimalDaysInFirstWeek) {

+			if (isUndefined(this.minimalDaysInFirstWeek)) {

+				minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;

+			}

+			var previousSunday = this.getPreviousSunday();

+			var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);

+			var numberOfSundays = previousSunday.isBefore(startOfYear) ?

+				0 : 1 + Math.floor(previousSunday.getTimeSince(startOfYear) / ONE_WEEK);

+			var numberOfDaysInFirstWeek =  7 - startOfYear.getDay();

+			var weekInYear = numberOfSundays;

+			if (numberOfDaysInFirstWeek < minimalDaysInFirstWeek) {

+				weekInYear--;

+			}

+			return weekInYear;

+		};

+

+		Date.prototype.getWeekInMonth = function(minimalDaysInFirstWeek) {

+			if (isUndefined(this.minimalDaysInFirstWeek)) {

+				minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;

+			}

+			var previousSunday = this.getPreviousSunday();

+			var startOfMonth = newDateAtMidnight(this.getFullYear(), this.getMonth(), 1);

+			var numberOfSundays = previousSunday.isBefore(startOfMonth) ?

+				0 : 1 + Math.floor(previousSunday.getTimeSince(startOfMonth) / ONE_WEEK);

+			var numberOfDaysInFirstWeek =  7 - startOfMonth.getDay();

+			var weekInMonth = numberOfSundays;

+			if (numberOfDaysInFirstWeek >= minimalDaysInFirstWeek) {

+				weekInMonth++;

+			}

+			return weekInMonth;

+		};

+

+		Date.prototype.getDayInYear = function() {

+			var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);

+			return 1 + Math.floor(this.getTimeSince(startOfYear) / ONE_DAY);

+		};

+

+		/* ------------------------------------------------------------------ */

+

+		SimpleDateFormat = function(formatString) {

+			this.formatString = formatString;

+		};

+

+		/**

+		 * Sets the minimum number of days in a week in order for that week to

+		 * be considered as belonging to a particular month or year

+		 */

+		SimpleDateFormat.prototype.setMinimalDaysInFirstWeek = function(days) {

+			this.minimalDaysInFirstWeek = days;

+		};

+

+		SimpleDateFormat.prototype.getMinimalDaysInFirstWeek = function() {

+			return isUndefined(this.minimalDaysInFirstWeek)	?

+				DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK : this.minimalDaysInFirstWeek;

+		};

+

+		var padWithZeroes = function(str, len) {

+			while (str.length < len) {

+				str = "0" + str;

+			}

+			return str;

+		};

+

+		var formatText = function(data, numberOfLetters, minLength) {

+			return (numberOfLetters >= 4) ? data : data.substr(0, Math.max(minLength, numberOfLetters));

+		};

+

+		var formatNumber = function(data, numberOfLetters) {

+			var dataString = "" + data;

+			// Pad with 0s as necessary

+			return padWithZeroes(dataString, numberOfLetters);

+		};

+

+		SimpleDateFormat.prototype.format = function(date) {

+			var formattedString = "";

+			var result;

+			var searchString = this.formatString;

+			while ((result = regex.exec(searchString))) {

+				var quotedString = result[1];

+				var patternLetters = result[2];

+				var otherLetters = result[3];

+				var otherCharacters = result[4];

+

+				// If the pattern matched is quoted string, output the text between the quotes

+				if (quotedString) {

+					if (quotedString == "''") {

+						formattedString += "'";

+					} else {

+						formattedString += quotedString.substring(1, quotedString.length - 1);

+					}

+				} else if (otherLetters) {

+					// Swallow non-pattern letters by doing nothing here

+				} else if (otherCharacters) {

+					// Simply output other characters

+					formattedString += otherCharacters;

+				} else if (patternLetters) {

+					// Replace pattern letters

+					var patternLetter = patternLetters.charAt(0);

+					var numberOfLetters = patternLetters.length;

+					var rawData = "";

+					switch(patternLetter) {

+						case "G":

+							rawData = "AD";

+							break;

+						case "y":

+							rawData = date.getFullYear();

+							break;

+						case "M":

+							rawData = date.getMonth();

+							break;

+						case "w":

+							rawData = date.getWeekInYear(this.getMinimalDaysInFirstWeek());

+							break;

+						case "W":

+							rawData = date.getWeekInMonth(this.getMinimalDaysInFirstWeek());

+							break;

+						case "D":

+							rawData = date.getDayInYear();

+							break;

+						case "d":

+							rawData = date.getDate();

+							break;

+						case "F":

+							rawData = 1 + Math.floor((date.getDate() - 1) / 7);

+							break;

+						case "E":

+							rawData = dayNames[date.getDay()];

+							break;

+						case "a":

+							rawData = (date.getHours() >= 12) ? "PM" : "AM";

+							break;

+						case "H":

+							rawData = date.getHours();

+							break;

+						case "k":

+							rawData = date.getHours() || 24;

+							break;

+						case "K":

+							rawData = date.getHours() % 12;

+							break;

+						case "h":

+							rawData = (date.getHours() % 12) || 12;

+							break;

+						case "m":

+							rawData = date.getMinutes();

+							break;

+						case "s":

+							rawData = date.getSeconds();

+							break;

+						case "S":

+							rawData = date.getMilliseconds();

+							break;

+						case "Z":

+							rawData = date.getTimezoneOffset(); // This returns the number of minutes since GMT was this time.

+							break;

+					}

+					// Format the raw data depending on the type

+					switch(types[patternLetter]) {

+						case TEXT2:

+							formattedString += formatText(rawData, numberOfLetters, 2);

+							break;

+						case TEXT3:

+							formattedString += formatText(rawData, numberOfLetters, 3);

+							break;

+						case NUMBER:

+							formattedString += formatNumber(rawData, numberOfLetters);

+							break;

+						case YEAR:

+							if (numberOfLetters <= 3) {

+								// Output a 2-digit year

+								var dataString = "" + rawData;

+								formattedString += dataString.substr(2, 2);

+							} else {

+								formattedString += formatNumber(rawData, numberOfLetters);

+							}

+							break;

+						case MONTH:

+							if (numberOfLetters >= 3) {

+								formattedString += formatText(monthNames[rawData], numberOfLetters, numberOfLetters);

+							} else {

+								// NB. Months returned by getMonth are zero-based

+								formattedString += formatNumber(rawData + 1, numberOfLetters);

+							}

+							break;

+						case TIMEZONE:

+							var isPositive = (rawData > 0);

+							// The following line looks like a mistake but isn't

+							// because of the way getTimezoneOffset measures.

+							var prefix = isPositive ? "-" : "+";

+							var absData = Math.abs(rawData);

+

+							// Hours

+							var hours = "" + Math.floor(absData / 60);

+							hours = padWithZeroes(hours, 2);

+							// Minutes

+							var minutes = "" + (absData % 60);

+							minutes = padWithZeroes(minutes, 2);

+

+							formattedString += prefix + hours + minutes;

+							break;

+					}

+				}

+				searchString = searchString.substr(result.index + result[0].length);

+			}

+			return formattedString;

+		};

+	})();

+

+	log4javascript.SimpleDateFormat = SimpleDateFormat;

+

+	/* ---------------------------------------------------------------------- */

+	// PatternLayout

+

+	function PatternLayout(pattern) {

+		if (pattern) {

+			this.pattern = pattern;

+		} else {

+			this.pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;

+		}

+		this.customFields = [];

+	}

+

+	PatternLayout.TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n";

+	PatternLayout.DEFAULT_CONVERSION_PATTERN = "%m%n";

+	PatternLayout.ISO8601_DATEFORMAT = "yyyy-MM-dd HH:mm:ss,SSS";

+	PatternLayout.DATETIME_DATEFORMAT = "dd MMM yyyy HH:mm:ss,SSS";

+	PatternLayout.ABSOLUTETIME_DATEFORMAT = "HH:mm:ss,SSS";

+

+	PatternLayout.prototype = new Layout();

+

+	PatternLayout.prototype.format = function(loggingEvent) {

+		var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;

+		var formattedString = "";

+		var result;

+		var searchString = this.pattern;

+

+		// Cannot use regex global flag since it doesn't work with exec in IE5

+		while ((result = regex.exec(searchString))) {

+			var matchedString = result[0];

+			var padding = result[1];

+			var truncation = result[2];

+			var conversionCharacter = result[3];

+			var specifier = result[5];

+			var text = result[6];

+

+			// Check if the pattern matched was just normal text

+			if (text) {

+				formattedString += "" + text;

+			} else {

+				// Create a raw replacement string based on the conversion

+				// character and specifier

+				var replacement = "";

+				switch(conversionCharacter) {

+					case "a": // Array of messages

+					case "m": // Message

+						var depth = 0;

+						if (specifier) {

+							depth = parseInt(specifier, 10);

+							if (isNaN(depth)) {

+								handleError("PatternLayout.format: invalid specifier '" +

+									specifier + "' for conversion character '" + conversionCharacter +

+									"' - should be a number");

+								depth = 0;

+							}

+						}

+						var messages = (conversionCharacter === "a") ? loggingEvent.messages[0] : loggingEvent.messages;

+						for (var i = 0, len = messages.length; i < len; i++) {

+							if (i > 0 && (replacement.charAt(replacement.length - 1) !== " ")) {

+								replacement += " ";

+							}

+							if (depth === 0) {

+								replacement += messages[i];

+							} else {

+								replacement += formatObjectExpansion(messages[i], depth);

+							}

+						}

+						break;

+					case "c": // Logger name

+						var loggerName = loggingEvent.logger.name;

+						if (specifier) {

+							var precision = parseInt(specifier, 10);

+							var loggerNameBits = loggingEvent.logger.name.split(".");

+							if (precision >= loggerNameBits.length) {

+								replacement = loggerName;

+							} else {

+								replacement = loggerNameBits.slice(loggerNameBits.length - precision).join(".");

+							}

+						} else {

+							replacement = loggerName;

+						}

+						break;

+					case "d": // Date

+						var dateFormat = PatternLayout.ISO8601_DATEFORMAT;

+						if (specifier) {

+							dateFormat = specifier;

+							// Pick up special cases

+							if (dateFormat == "ISO8601") {

+								dateFormat = PatternLayout.ISO8601_DATEFORMAT;

+							} else if (dateFormat == "ABSOLUTE") {

+								dateFormat = PatternLayout.ABSOLUTETIME_DATEFORMAT;

+							} else if (dateFormat == "DATE") {

+								dateFormat = PatternLayout.DATETIME_DATEFORMAT;

+							}

+						}

+						// Format the date

+						replacement = (new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);

+						break;

+					case "f": // Custom field

+						if (this.hasCustomFields()) {

+							var fieldIndex = 0;

+							if (specifier) {

+								fieldIndex = parseInt(specifier, 10);

+								if (isNaN(fieldIndex)) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - should be a number");

+								} else if (fieldIndex === 0) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - must be greater than zero");

+								} else if (fieldIndex > this.customFields.length) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - there aren't that many custom fields");

+								} else {

+									fieldIndex = fieldIndex - 1;

+								}

+							}

+                            var val = this.customFields[fieldIndex].value;

+                            if (typeof val == "function") {

+                                val = val(this, loggingEvent);

+                            }

+                            replacement = val;

+						}

+						break;

+					case "n": // New line

+						replacement = newLine;

+						break;

+					case "p": // Level

+						replacement = loggingEvent.level.name;

+						break;

+					case "r": // Milliseconds since log4javascript startup

+						replacement = "" + loggingEvent.timeStamp.getDifference(applicationStartDate);

+						break;

+					case "%": // Literal % sign

+						replacement = "%";

+						break;

+					default:

+						replacement = matchedString;

+						break;

+				}

+				// Format the replacement according to any padding or

+				// truncation specified

+				var l;

+

+				// First, truncation

+				if (truncation) {

+					l = parseInt(truncation.substr(1), 10);

+					var strLen = replacement.length;

+					if (l < strLen) {

+						replacement = replacement.substring(strLen - l, strLen);

+					}

+				}

+				// Next, padding

+				if (padding) {

+					if (padding.charAt(0) == "-") {

+						l = parseInt(padding.substr(1), 10);

+						// Right pad with spaces

+						while (replacement.length < l) {

+							replacement += " ";

+						}

+					} else {

+						l = parseInt(padding, 10);

+						// Left pad with spaces

+						while (replacement.length < l) {

+							replacement = " " + replacement;

+						}

+					}

+				}

+				formattedString += replacement;

+			}

+			searchString = searchString.substr(result.index + result[0].length);

+		}

+		return formattedString;

+	};

+

+	PatternLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	PatternLayout.prototype.toString = function() {

+	    return "PatternLayout";

+	};

+

+	log4javascript.PatternLayout = PatternLayout;

+	/* ---------------------------------------------------------------------- */

+	// AjaxAppender related

+

+	var xmlHttpFactories = [

+		function() { return new XMLHttpRequest(); },

+		function() { return new ActiveXObject("Msxml2.XMLHTTP"); },

+		function() { return new ActiveXObject("Microsoft.XMLHTTP"); }

+	];

+

+	var getXmlHttp = function(errorHandler) {

+		// This is only run the first time; the value of getXmlHttp gets

+		// replaced with the factory that succeeds on the first run

+		var xmlHttp = null, factory;

+		for (var i = 0, len = xmlHttpFactories.length; i < len; i++) {

+			factory = xmlHttpFactories[i];

+			try {

+				xmlHttp = factory();

+				getXmlHttp = factory;

+				return xmlHttp;

+			} catch (e) {

+			}

+		}

+		// If we're here, all factories have failed, so throw an error

+		if (errorHandler) {

+			errorHandler();

+		} else {

+			handleError("getXmlHttp: unable to obtain XMLHttpRequest object");

+		}

+	};

+

+	function isHttpRequestSuccessful(xmlHttp) {

+		return isUndefined(xmlHttp.status) || xmlHttp.status === 0 ||

+			(xmlHttp.status >= 200 && xmlHttp.status < 300) ||

+			xmlHttp.status == 1223 /* Fix for IE */;

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// AjaxAppender

+

+	function AjaxAppender(url) {

+		var appender = this;

+		var isSupported = true;

+		if (!url) {

+			handleError("AjaxAppender: URL must be specified in constructor");

+			isSupported = false;

+		}

+

+		var timed = this.defaults.timed;

+		var waitForResponse = this.defaults.waitForResponse;

+		var batchSize = this.defaults.batchSize;

+		var timerInterval = this.defaults.timerInterval;

+		var requestSuccessCallback = this.defaults.requestSuccessCallback;

+		var failCallback = this.defaults.failCallback;

+		var postVarName = this.defaults.postVarName;

+		var sendAllOnUnload = this.defaults.sendAllOnUnload;

+		var contentType = this.defaults.contentType;

+		var sessionId = null;

+

+		var queuedLoggingEvents = [];

+		var queuedRequests = [];

+		var headers = [];

+		var sending = false;

+		var initialized = false;

+

+		// Configuration methods. The function scope is used to prevent

+		// direct alteration to the appender configuration properties.

+		function checkCanConfigure(configOptionName) {

+			if (initialized) {

+				handleError("AjaxAppender: configuration option '" +

+					configOptionName +

+					"' may not be set after the appender has been initialized");

+				return false;

+			}

+			return true;

+		}

+

+		this.getSessionId = function() { return sessionId; };

+		this.setSessionId = function(sessionIdParam) {

+			sessionId = extractStringFromParam(sessionIdParam, null);

+			this.layout.setCustomField("sessionid", sessionId);

+		};

+

+		this.setLayout = function(layoutParam) {

+			if (checkCanConfigure("layout")) {

+				this.layout = layoutParam;

+				// Set the session id as a custom field on the layout, if not already present

+				if (sessionId !== null) {

+					this.setSessionId(sessionId);

+				}

+			}

+		};

+

+		this.isTimed = function() { return timed; };

+		this.setTimed = function(timedParam) {

+			if (checkCanConfigure("timed")) {

+				timed = bool(timedParam);

+			}

+		};

+

+		this.getTimerInterval = function() { return timerInterval; };

+		this.setTimerInterval = function(timerIntervalParam) {

+			if (checkCanConfigure("timerInterval")) {

+				timerInterval = extractIntFromParam(timerIntervalParam, timerInterval);

+			}

+		};

+

+		this.isWaitForResponse = function() { return waitForResponse; };

+		this.setWaitForResponse = function(waitForResponseParam) {

+			if (checkCanConfigure("waitForResponse")) {

+				waitForResponse = bool(waitForResponseParam);

+			}

+		};

+

+		this.getBatchSize = function() { return batchSize; };

+		this.setBatchSize = function(batchSizeParam) {

+			if (checkCanConfigure("batchSize")) {

+				batchSize = extractIntFromParam(batchSizeParam, batchSize);

+			}

+		};

+

+		this.isSendAllOnUnload = function() { return sendAllOnUnload; };

+		this.setSendAllOnUnload = function(sendAllOnUnloadParam) {

+			if (checkCanConfigure("sendAllOnUnload")) {

+				sendAllOnUnload = extractBooleanFromParam(sendAllOnUnloadParam, sendAllOnUnload);

+			}

+		};

+

+		this.setRequestSuccessCallback = function(requestSuccessCallbackParam) {

+			requestSuccessCallback = extractFunctionFromParam(requestSuccessCallbackParam, requestSuccessCallback);

+		};

+

+		this.setFailCallback = function(failCallbackParam) {

+			failCallback = extractFunctionFromParam(failCallbackParam, failCallback);

+		};

+

+		this.getPostVarName = function() { return postVarName; };

+		this.setPostVarName = function(postVarNameParam) {

+			if (checkCanConfigure("postVarName")) {

+				postVarName = extractStringFromParam(postVarNameParam, postVarName);

+			}

+		};

+

+		this.getHeaders = function() { return headers; };

+		this.addHeader = function(name, value) {

+			if (name.toLowerCase() == "content-type") {

+				contentType = value;

+			} else {

+				headers.push( { name: name, value: value } );

+			}

+		};

+

+		// Internal functions

+		function sendAll() {

+			if (isSupported && enabled) {

+				sending = true;

+				var currentRequestBatch;

+				if (waitForResponse) {

+					// Send the first request then use this function as the callback once

+					// the response comes back

+					if (queuedRequests.length > 0) {

+						currentRequestBatch = queuedRequests.shift();

+						sendRequest(preparePostData(currentRequestBatch), sendAll);

+					} else {

+						sending = false;

+						if (timed) {

+							scheduleSending();

+						}

+					}

+				} else {

+					// Rattle off all the requests without waiting to see the response

+					while ((currentRequestBatch = queuedRequests.shift())) {

+						sendRequest(preparePostData(currentRequestBatch));

+					}

+					sending = false;

+					if (timed) {

+						scheduleSending();

+					}

+				}

+			}

+		}

+

+		this.sendAll = sendAll;

+

+		// Called when the window unloads. At this point we're past caring about

+		// waiting for responses or timers or incomplete batches - everything

+		// must go, now

+		function sendAllRemaining() {

+			var sendingAnything = false;

+			if (isSupported && enabled) {

+				// Create requests for everything left over, batched as normal

+				var actualBatchSize = appender.getLayout().allowBatching() ? batchSize : 1;

+				var currentLoggingEvent;

+				var batchedLoggingEvents = [];

+				while ((currentLoggingEvent = queuedLoggingEvents.shift())) {

+					batchedLoggingEvents.push(currentLoggingEvent);

+					if (queuedLoggingEvents.length >= actualBatchSize) {

+						// Queue this batch of log entries

+						queuedRequests.push(batchedLoggingEvents);

+						batchedLoggingEvents = [];

+					}

+				}

+				// If there's a partially completed batch, add it

+				if (batchedLoggingEvents.length > 0) {

+					queuedRequests.push(batchedLoggingEvents);

+				}

+				sendingAnything = (queuedRequests.length > 0);

+				waitForResponse = false;

+				timed = false;

+				sendAll();

+			}

+			return sendingAnything;

+		}

+

+		this.sendAllRemaining = sendAllRemaining;

+

+		function preparePostData(batchedLoggingEvents) {

+			// Format the logging events

+			var formattedMessages = [];

+			var currentLoggingEvent;

+			var postData = "";

+			while ((currentLoggingEvent = batchedLoggingEvents.shift())) {

+				var currentFormattedMessage = appender.getLayout().format(currentLoggingEvent);

+				if (appender.getLayout().ignoresThrowable()) {

+					currentFormattedMessage += currentLoggingEvent.getThrowableStrRep();

+				}

+				formattedMessages.push(currentFormattedMessage);

+			}

+			// Create the post data string

+			if (batchedLoggingEvents.length == 1) {

+				postData = formattedMessages.join("");

+			} else {

+				postData = appender.getLayout().batchHeader +

+					formattedMessages.join(appender.getLayout().batchSeparator) +

+					appender.getLayout().batchFooter;

+			}

+			if (contentType == appender.defaults.contentType) {

+				postData = appender.getLayout().returnsPostData ? postData :

+					urlEncode(postVarName) + "=" + urlEncode(postData);

+				// Add the layout name to the post data

+				if (postData.length > 0) {

+					postData += "&";

+				}

+				postData += "layout=" + urlEncode(appender.getLayout().toString());

+			}

+			return postData;

+		}

+

+		function scheduleSending() {

+			window.setTimeout(sendAll, timerInterval);

+		}

+

+		function xmlHttpErrorHandler() {

+			var msg = "AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";

+			handleError(msg);

+			isSupported = false;

+			if (failCallback) {

+				failCallback(msg);

+			}

+		}

+

+		function sendRequest(postData, successCallback) {

+			try {

+				var xmlHttp = getXmlHttp(xmlHttpErrorHandler);

+				if (isSupported) {

+					if (xmlHttp.overrideMimeType) {

+						xmlHttp.overrideMimeType(appender.getLayout().getContentType());

+					}

+					xmlHttp.onreadystatechange = function() {

+						if (xmlHttp.readyState == 4) {

+							if (isHttpRequestSuccessful(xmlHttp)) {

+								if (requestSuccessCallback) {

+									requestSuccessCallback(xmlHttp);

+								}

+								if (successCallback) {

+									successCallback(xmlHttp);

+								}

+							} else {

+								var msg = "AjaxAppender.append: XMLHttpRequest request to URL " +

+									url + " returned status code " + xmlHttp.status;

+								handleError(msg);

+								if (failCallback) {

+									failCallback(msg);

+								}

+							}

+							xmlHttp.onreadystatechange = emptyFunction;

+							xmlHttp = null;

+						}

+					};

+					xmlHttp.open("POST", url, true);

+					try {

+						for (var i = 0, header; header = headers[i++]; ) {

+							xmlHttp.setRequestHeader(header.name, header.value);

+						}

+						xmlHttp.setRequestHeader("Content-Type", contentType);

+					} catch (headerEx) {

+						var msg = "AjaxAppender.append: your browser's XMLHttpRequest implementation" +

+							" does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";

+						handleError(msg);

+						isSupported = false;

+						if (failCallback) {

+							failCallback(msg);

+						}

+						return;

+					}

+					xmlHttp.send(postData);

+				}

+			} catch (ex) {

+				var errMsg = "AjaxAppender.append: error sending log message to " + url;

+				handleError(errMsg, ex);

+				isSupported = false;

+				if (failCallback) {

+					failCallback(errMsg + ". Details: " + getExceptionStringRep(ex));

+				}

+			}

+		}

+

+		this.append = function(loggingEvent) {

+			if (isSupported) {

+				if (!initialized) {

+					init();

+				}

+				queuedLoggingEvents.push(loggingEvent);

+				var actualBatchSize = this.getLayout().allowBatching() ? batchSize : 1;

+

+				if (queuedLoggingEvents.length >= actualBatchSize) {

+					var currentLoggingEvent;

+					var batchedLoggingEvents = [];

+					while ((currentLoggingEvent = queuedLoggingEvents.shift())) {

+						batchedLoggingEvents.push(currentLoggingEvent);

+					}

+					// Queue this batch of log entries

+					queuedRequests.push(batchedLoggingEvents);

+

+					// If using a timer, the queue of requests will be processed by the

+					// timer function, so nothing needs to be done here.

+					if (!timed && (!waitForResponse || (waitForResponse && !sending))) {

+						sendAll();

+					}

+				}

+			}

+		};

+

+		function init() {

+			initialized = true;

+			// Add unload event to send outstanding messages

+			if (sendAllOnUnload) {

+				var oldBeforeUnload = window.onbeforeunload;

+				window.onbeforeunload = function() {

+					if (oldBeforeUnload) {

+						oldBeforeUnload();

+					}

+					if (sendAllRemaining()) {

+						return "Sending log messages";

+					}

+				};

+			}

+			// Start timer

+			if (timed) {

+				scheduleSending();

+			}

+		}

+	}

+

+	AjaxAppender.prototype = new Appender();

+

+	AjaxAppender.prototype.defaults = {

+		waitForResponse: false,

+		timed: false,

+		timerInterval: 1000,

+		batchSize: 1,

+		sendAllOnUnload: false,

+		requestSuccessCallback: null,

+		failCallback: null,

+		postVarName: "data",

+		contentType: "application/x-www-form-urlencoded"

+	};

+

+	AjaxAppender.prototype.layout = new HttpPostDataLayout();

+

+	AjaxAppender.prototype.toString = function() {

+		return "AjaxAppender";

+	};

+

+	log4javascript.AjaxAppender = AjaxAppender;

+

+	/* ---------------------------------------------------------------------- */

+	// Main load

+

+   log4javascript.setDocumentReady = function() {

+       pageLoaded = true;

+       log4javascript.dispatchEvent("load", {});

+   };

+

+    if (window.addEventListener) {

+        window.addEventListener("load", log4javascript.setDocumentReady, false);

+    } else if (window.attachEvent) {

+        window.attachEvent("onload", log4javascript.setDocumentReady);

+    } else {

+        var oldOnload = window.onload;

+        if (typeof window.onload != "function") {

+            window.onload = log4javascript.setDocumentReady;

+        } else {

+            window.onload = function(evt) {

+                if (oldOnload) {

+                    oldOnload(evt);

+                }

+                log4javascript.setDocumentReady();

+            };

+        }

+    }

+

+    // Ensure that the log4javascript object is available in the window. This

+    // is necessary for log4javascript to be available in IE if loaded using

+    // Dojo's module system

+    window.log4javascript = log4javascript;

+

+    return log4javascript;

+})();
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_uncompressed.js
new file mode 100644
index 0000000..a644e3b
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/log4javascript_uncompressed.js
@@ -0,0 +1,5879 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+/**

+ * log4javascript

+ *

+ * log4javascript is a logging framework for JavaScript based on log4j

+ * for Java. This file contains all core log4javascript code and is the only

+ * file required to use log4javascript, unless you require support for

+ * document.domain, in which case you will also need console.html, which must be

+ * stored in the same directory as the main log4javascript.js file.

+ *

+ * Author: Tim Down <tim@log4javascript.org>

+ * Version: 1.4.6

+ * Edition: log4javascript

+ * Build date: 19 March 2013

+ * Website: http://log4javascript.org

+ */

+

+/* -------------------------------------------------------------------------- */

+// Array-related stuff

+

+// Next three methods are solely for IE5, which is missing them

+if (!Array.prototype.push) {

+	Array.prototype.push = function() {

+		for (var i = 0, len = arguments.length; i < len; i++){

+			this[this.length] = arguments[i];

+		}

+		return this.length;

+	};

+}

+

+if (!Array.prototype.shift) {

+	Array.prototype.shift = function() {

+		if (this.length > 0) {

+			var firstItem = this[0];

+			for (var i = 0, len = this.length - 1; i < len; i++) {

+				this[i] = this[i + 1];

+			}

+			this.length = this.length - 1;

+			return firstItem;

+		}

+	};

+}

+

+if (!Array.prototype.splice) {

+	Array.prototype.splice = function(startIndex, deleteCount) {

+		var itemsAfterDeleted = this.slice(startIndex + deleteCount);

+		var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);

+		this.length = startIndex;

+		// Copy the arguments into a proper Array object

+		var argumentsArray = [];

+		for (var i = 0, len = arguments.length; i < len; i++) {

+			argumentsArray[i] = arguments[i];

+		}

+		var itemsToAppend = (argumentsArray.length > 2) ?

+			itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;

+		for (i = 0, len = itemsToAppend.length; i < len; i++) {

+			this.push(itemsToAppend[i]);

+		}

+		return itemsDeleted;

+	};

+}

+

+/* -------------------------------------------------------------------------- */

+

+var log4javascript = (function() {

+

+	function isUndefined(obj) {

+		return typeof obj == "undefined";

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// Custom event support

+

+	function EventSupport() {}

+

+	EventSupport.prototype = {

+		eventTypes: [],

+		eventListeners: {},

+		setEventTypes: function(eventTypesParam) {

+			if (eventTypesParam instanceof Array) {

+				this.eventTypes = eventTypesParam;

+				this.eventListeners = {};

+				for (var i = 0, len = this.eventTypes.length; i < len; i++) {

+					this.eventListeners[this.eventTypes[i]] = [];

+				}

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: setEventTypes: eventTypes parameter must be an Array");

+			}

+		},

+

+		addEventListener: function(eventType, listener) {

+			if (typeof listener == "function") {

+				if (!array_contains(this.eventTypes, eventType)) {

+					handleError("log4javascript.EventSupport [" + this + "]: addEventListener: no event called '" + eventType + "'");

+				}

+				this.eventListeners[eventType].push(listener);

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: addEventListener: listener must be a function");

+			}

+		},

+

+		removeEventListener: function(eventType, listener) {

+			if (typeof listener == "function") {

+				if (!array_contains(this.eventTypes, eventType)) {

+					handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: no event called '" + eventType + "'");

+				}

+				array_remove(this.eventListeners[eventType], listener);

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: listener must be a function");

+			}

+		},

+

+		dispatchEvent: function(eventType, eventArgs) {

+			if (array_contains(this.eventTypes, eventType)) {

+				var listeners = this.eventListeners[eventType];

+				for (var i = 0, len = listeners.length; i < len; i++) {

+					listeners[i](this, eventType, eventArgs);

+				}

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: dispatchEvent: no event called '" + eventType + "'");

+			}

+		}

+	};

+

+	/* -------------------------------------------------------------------------- */

+

+	var applicationStartDate = new Date();

+	var uniqueId = "log4javascript_" + applicationStartDate.getTime() + "_" +

+		Math.floor(Math.random() * 100000000);

+	var emptyFunction = function() {};

+	var newLine = "\r\n";

+	var pageLoaded = false;

+

+	// Create main log4javascript object; this will be assigned public properties

+	function Log4JavaScript() {}

+	Log4JavaScript.prototype = new EventSupport();

+

+	log4javascript = new Log4JavaScript();

+	log4javascript.version = "1.4.6";

+	log4javascript.edition = "log4javascript";

+

+	/* -------------------------------------------------------------------------- */

+	// Utility functions

+

+	function toStr(obj) {

+		if (obj && obj.toString) {

+			return obj.toString();

+		} else {

+			return String(obj);

+		}

+	}

+

+	function getExceptionMessage(ex) {

+		if (ex.message) {

+			return ex.message;

+		} else if (ex.description) {

+			return ex.description;

+		} else {

+			return toStr(ex);

+		}

+	}

+

+	// Gets the portion of the URL after the last slash

+	function getUrlFileName(url) {

+		var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\"));

+		return url.substr(lastSlashIndex + 1);

+	}

+

+	// Returns a nicely formatted representation of an error

+	function getExceptionStringRep(ex) {

+		if (ex) {

+			var exStr = "Exception: " + getExceptionMessage(ex);

+			try {

+				if (ex.lineNumber) {

+					exStr += " on line number " + ex.lineNumber;

+				}

+				if (ex.fileName) {

+					exStr += " in file " + getUrlFileName(ex.fileName);

+				}

+			} catch (localEx) {

+				logLog.warn("Unable to obtain file and line information for error");

+			}

+			if (showStackTraces && ex.stack) {

+				exStr += newLine + "Stack trace:" + newLine + ex.stack;

+			}

+			return exStr;

+		}

+		return null;

+	}

+

+	function bool(obj) {

+		return Boolean(obj);

+	}

+

+	function trim(str) {

+		return str.replace(/^\s+/, "").replace(/\s+$/, "");

+	}

+

+	function splitIntoLines(text) {

+		// Ensure all line breaks are \n only

+		var text2 = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");

+		return text2.split("\n");

+	}

+

+	var urlEncode = (typeof window.encodeURIComponent != "undefined") ?

+		function(str) {

+			return encodeURIComponent(str);

+		}: 

+		function(str) {

+			return escape(str).replace(/\+/g, "%2B").replace(/"/g, "%22").replace(/'/g, "%27").replace(/\//g, "%2F").replace(/=/g, "%3D");

+		};

+

+	var urlDecode = (typeof window.decodeURIComponent != "undefined") ?

+		function(str) {

+			return decodeURIComponent(str);

+		}: 

+		function(str) {

+			return unescape(str).replace(/%2B/g, "+").replace(/%22/g, "\"").replace(/%27/g, "'").replace(/%2F/g, "/").replace(/%3D/g, "=");

+		};

+

+	function array_remove(arr, val) {

+		var index = -1;

+		for (var i = 0, len = arr.length; i < len; i++) {

+			if (arr[i] === val) {

+				index = i;

+				break;

+			}

+		}

+		if (index >= 0) {

+			arr.splice(index, 1);

+			return true;

+		} else {

+			return false;

+		}

+	}

+

+	function array_contains(arr, val) {

+		for(var i = 0, len = arr.length; i < len; i++) {

+			if (arr[i] == val) {

+				return true;

+			}

+		}

+		return false;

+	}

+

+	function extractBooleanFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			return bool(param);

+		}

+	}

+

+	function extractStringFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			return String(param);

+		}

+	}

+

+	function extractIntFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			try {

+				var value = parseInt(param, 10);

+				return isNaN(value) ? defaultValue : value;

+			} catch (ex) {

+				logLog.warn("Invalid int param " + param, ex);

+				return defaultValue;

+			}

+		}

+	}

+

+	function extractFunctionFromParam(param, defaultValue) {

+		if (typeof param == "function") {

+			return param;

+		} else {

+			return defaultValue;

+		}

+	}

+

+	function isError(err) {

+		return (err instanceof Error);

+	}

+

+	if (!Function.prototype.apply){

+		Function.prototype.apply = function(obj, args) {

+			var methodName = "__apply__";

+			if (typeof obj[methodName] != "undefined") {

+				methodName += String(Math.random()).substr(2);

+			}

+			obj[methodName] = this;

+

+			var argsStrings = [];

+			for (var i = 0, len = args.length; i < len; i++) {

+				argsStrings[i] = "args[" + i + "]";

+			}

+			var script = "obj." + methodName + "(" + argsStrings.join(",") + ")";

+			var returnValue = eval(script);

+			delete obj[methodName];

+			return returnValue;

+		};

+	}

+

+	if (!Function.prototype.call){

+		Function.prototype.call = function(obj) {

+			var args = [];

+			for (var i = 1, len = arguments.length; i < len; i++) {

+				args[i - 1] = arguments[i];

+			}

+			return this.apply(obj, args);

+		};

+	}

+

+	function getListenersPropertyName(eventName) {

+		return "__log4javascript_listeners__" + eventName;

+	}

+

+	function addEvent(node, eventName, listener, useCapture, win) {

+		win = win ? win : window;

+		if (node.addEventListener) {

+			node.addEventListener(eventName, listener, useCapture);

+		} else if (node.attachEvent) {

+			node.attachEvent("on" + eventName, listener);

+		} else {

+			var propertyName = getListenersPropertyName(eventName);

+			if (!node[propertyName]) {

+				node[propertyName] = [];

+				// Set event handler

+				node["on" + eventName] = function(evt) {

+					evt = getEvent(evt, win);

+					var listenersPropertyName = getListenersPropertyName(eventName);

+

+					// Clone the array of listeners to leave the original untouched

+					var listeners = this[listenersPropertyName].concat([]);

+					var currentListener;

+

+					// Call each listener in turn

+					while ((currentListener = listeners.shift())) {

+						currentListener.call(this, evt);

+					}

+				};

+			}

+			node[propertyName].push(listener);

+		}

+	}

+

+	function removeEvent(node, eventName, listener, useCapture) {

+		if (node.removeEventListener) {

+			node.removeEventListener(eventName, listener, useCapture);

+		} else if (node.detachEvent) {

+			node.detachEvent("on" + eventName, listener);

+		} else {

+			var propertyName = getListenersPropertyName(eventName);

+			if (node[propertyName]) {

+				array_remove(node[propertyName], listener);

+			}

+		}

+	}

+

+	function getEvent(evt, win) {

+		win = win ? win : window;

+		return evt ? evt : win.event;

+	}

+

+	function stopEventPropagation(evt) {

+		if (evt.stopPropagation) {

+			evt.stopPropagation();

+		} else if (typeof evt.cancelBubble != "undefined") {

+			evt.cancelBubble = true;

+		}

+		evt.returnValue = false;

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// Simple logging for log4javascript itself

+

+	var logLog = {

+		quietMode: false,

+

+		debugMessages: [],

+

+		setQuietMode: function(quietMode) {

+			this.quietMode = bool(quietMode);

+		},

+

+		numberOfErrors: 0,

+

+		alertAllErrors: false,

+

+		setAlertAllErrors: function(alertAllErrors) {

+			this.alertAllErrors = alertAllErrors;

+		},

+

+		debug: function(message) {

+			this.debugMessages.push(message);

+		},

+

+		displayDebug: function() {

+			alert(this.debugMessages.join(newLine));

+		},

+

+		warn: function(message, exception) {

+		},

+

+		error: function(message, exception) {

+			if (++this.numberOfErrors == 1 || this.alertAllErrors) {

+				if (!this.quietMode) {

+					var alertMessage = "log4javascript error: " + message;

+					if (exception) {

+						alertMessage += newLine + newLine + "Original error: " + getExceptionStringRep(exception);

+					}

+					alert(alertMessage);

+				}

+			}

+		}

+	};

+	log4javascript.logLog = logLog;

+

+	log4javascript.setEventTypes(["load", "error"]);

+

+	function handleError(message, exception) {

+		logLog.error(message, exception);

+		log4javascript.dispatchEvent("error", { "message": message, "exception": exception });

+	}

+

+	log4javascript.handleError = handleError;

+

+	/* ---------------------------------------------------------------------- */

+

+	var enabled = !((typeof log4javascript_disabled != "undefined") &&

+					log4javascript_disabled);

+

+	log4javascript.setEnabled = function(enable) {

+		enabled = bool(enable);

+	};

+

+	log4javascript.isEnabled = function() {

+		return enabled;

+	};

+

+	var useTimeStampsInMilliseconds = true;

+

+	log4javascript.setTimeStampsInMilliseconds = function(timeStampsInMilliseconds) {

+		useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);

+	};

+

+	log4javascript.isTimeStampsInMilliseconds = function() {

+		return useTimeStampsInMilliseconds;

+	};

+	

+

+	// This evaluates the given expression in the current scope, thus allowing

+	// scripts to access private variables. Particularly useful for testing

+	log4javascript.evalInScope = function(expr) {

+		return eval(expr);

+	};

+

+	var showStackTraces = false;

+

+	log4javascript.setShowStackTraces = function(show) {

+		showStackTraces = bool(show);

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Levels

+

+	var Level = function(level, name) {

+		this.level = level;

+		this.name = name;

+	};

+

+	Level.prototype = {

+		toString: function() {

+			return this.name;

+		},

+		equals: function(level) {

+			return this.level == level.level;

+		},

+		isGreaterOrEqual: function(level) {

+			return this.level >= level.level;

+		}

+	};

+

+	Level.ALL = new Level(Number.MIN_VALUE, "ALL");

+	Level.TRACE = new Level(10000, "TRACE");

+	Level.DEBUG = new Level(20000, "DEBUG");

+	Level.INFO = new Level(30000, "INFO");

+	Level.WARN = new Level(40000, "WARN");

+	Level.ERROR = new Level(50000, "ERROR");

+	Level.FATAL = new Level(60000, "FATAL");

+	Level.OFF = new Level(Number.MAX_VALUE, "OFF");

+

+	log4javascript.Level = Level;

+

+	/* ---------------------------------------------------------------------- */

+	// Timers

+

+	function Timer(name, level) {

+		this.name = name;

+		this.level = isUndefined(level) ? Level.INFO : level;

+		this.start = new Date();

+	}

+

+	Timer.prototype.getElapsedTime = function() {

+		return new Date().getTime() - this.start.getTime();

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Loggers

+

+	var anonymousLoggerName = "[anonymous]";

+	var defaultLoggerName = "[default]";

+	var nullLoggerName = "[null]";

+	var rootLoggerName = "root";

+

+	function Logger(name) {

+		this.name = name;

+		this.parent = null;

+		this.children = [];

+

+		var appenders = [];

+		var loggerLevel = null;

+		var isRoot = (this.name === rootLoggerName);

+		var isNull = (this.name === nullLoggerName);

+

+		var appenderCache = null;

+		var appenderCacheInvalidated = false;

+		

+		this.addChild = function(childLogger) {

+			this.children.push(childLogger);

+			childLogger.parent = this;

+			childLogger.invalidateAppenderCache();

+		};

+

+		// Additivity

+		var additive = true;

+		this.getAdditivity = function() {

+			return additive;

+		};

+

+		this.setAdditivity = function(additivity) {

+			var valueChanged = (additive != additivity);

+			additive = additivity;

+			if (valueChanged) {

+				this.invalidateAppenderCache();

+			}

+		};

+

+		// Create methods that use the appenders variable in this scope

+		this.addAppender = function(appender) {

+			if (isNull) {

+				handleError("Logger.addAppender: you may not add an appender to the null logger");

+			} else {

+				if (appender instanceof log4javascript.Appender) {

+					if (!array_contains(appenders, appender)) {

+						appenders.push(appender);

+						appender.setAddedToLogger(this);

+						this.invalidateAppenderCache();

+					}

+				} else {

+					handleError("Logger.addAppender: appender supplied ('" +

+						toStr(appender) + "') is not a subclass of Appender");

+				}

+			}

+		};

+

+		this.removeAppender = function(appender) {

+			array_remove(appenders, appender);

+			appender.setRemovedFromLogger(this);

+			this.invalidateAppenderCache();

+		};

+

+		this.removeAllAppenders = function() {

+			var appenderCount = appenders.length;

+			if (appenderCount > 0) {

+				for (var i = 0; i < appenderCount; i++) {

+					appenders[i].setRemovedFromLogger(this);

+				}

+				appenders.length = 0;

+				this.invalidateAppenderCache();

+			}

+		};

+

+		this.getEffectiveAppenders = function() {

+			if (appenderCache === null || appenderCacheInvalidated) {

+				// Build appender cache

+				var parentEffectiveAppenders = (isRoot || !this.getAdditivity()) ?

+					[] : this.parent.getEffectiveAppenders();

+				appenderCache = parentEffectiveAppenders.concat(appenders);

+				appenderCacheInvalidated = false;

+			}

+			return appenderCache;

+		};

+		

+		this.invalidateAppenderCache = function() {

+			appenderCacheInvalidated = true;

+			for (var i = 0, len = this.children.length; i < len; i++) {

+				this.children[i].invalidateAppenderCache();

+			}

+		};

+

+		this.log = function(level, params) {

+			if (enabled && level.isGreaterOrEqual(this.getEffectiveLevel())) {

+				// Check whether last param is an exception

+				var exception;

+				var finalParamIndex = params.length - 1;

+				var lastParam = params[finalParamIndex];

+				if (params.length > 1 && isError(lastParam)) {

+					exception = lastParam;

+					finalParamIndex--;

+				}

+

+				// Construct genuine array for the params

+				var messages = [];

+				for (var i = 0; i <= finalParamIndex; i++) {

+					messages[i] = params[i];

+				}

+

+				var loggingEvent = new LoggingEvent(

+					this, new Date(), level, messages, exception);

+

+				this.callAppenders(loggingEvent);

+			}

+		};

+

+		this.callAppenders = function(loggingEvent) {

+			var effectiveAppenders = this.getEffectiveAppenders();

+			for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+				effectiveAppenders[i].doAppend(loggingEvent);

+			}

+		};

+

+		this.setLevel = function(level) {

+			// Having a level of null on the root logger would be very bad.

+			if (isRoot && level === null) {

+				handleError("Logger.setLevel: you cannot set the level of the root logger to null");

+			} else if (level instanceof Level) {

+				loggerLevel = level;

+			} else {

+				handleError("Logger.setLevel: level supplied to logger " +

+					this.name + " is not an instance of log4javascript.Level");

+			}

+		};

+

+		this.getLevel = function() {

+			return loggerLevel;

+		};

+

+		this.getEffectiveLevel = function() {

+			for (var logger = this; logger !== null; logger = logger.parent) {

+				var level = logger.getLevel();

+				if (level !== null) {

+					return level;

+				}

+			}

+		};

+

+		this.group = function(name, initiallyExpanded) {

+			if (enabled) {

+				var effectiveAppenders = this.getEffectiveAppenders();

+				for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+					effectiveAppenders[i].group(name, initiallyExpanded);

+				}

+			}

+		};

+

+		this.groupEnd = function() {

+			if (enabled) {

+				var effectiveAppenders = this.getEffectiveAppenders();

+				for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+					effectiveAppenders[i].groupEnd();

+				}

+			}

+		};

+

+		var timers = {};

+

+		this.time = function(name, level) {

+			if (enabled) {

+				if (isUndefined(name)) {

+					handleError("Logger.time: a name for the timer must be supplied");

+				} else if (level && !(level instanceof Level)) {

+					handleError("Logger.time: level supplied to timer " +

+						name + " is not an instance of log4javascript.Level");

+				} else {

+					timers[name] = new Timer(name, level);

+				}

+			}

+		};

+

+		this.timeEnd = function(name) {

+			if (enabled) {

+				if (isUndefined(name)) {

+					handleError("Logger.timeEnd: a name for the timer must be supplied");

+				} else if (timers[name]) {

+					var timer = timers[name];

+					var milliseconds = timer.getElapsedTime();

+					this.log(timer.level, ["Timer " + toStr(name) + " completed in " + milliseconds + "ms"]);

+					delete timers[name];

+				} else {

+					logLog.warn("Logger.timeEnd: no timer found with name " + name);

+				}

+			}

+		};

+

+		this.assert = function(expr) {

+			if (enabled && !expr) {

+				var args = [];

+				for (var i = 1, len = arguments.length; i < len; i++) {

+					args.push(arguments[i]);

+				}

+				args = (args.length > 0) ? args : ["Assertion Failure"];

+				args.push(newLine);

+				args.push(expr);

+				this.log(Level.ERROR, args);

+			}

+		};

+

+		this.toString = function() {

+			return "Logger[" + this.name + "]";

+		};

+	}

+

+	Logger.prototype = {

+		trace: function() {

+			this.log(Level.TRACE, arguments);

+		},

+

+		debug: function() {

+			this.log(Level.DEBUG, arguments);

+		},

+

+		info: function() {

+			this.log(Level.INFO, arguments);

+		},

+

+		warn: function() {

+			this.log(Level.WARN, arguments);

+		},

+

+		error: function() {

+			this.log(Level.ERROR, arguments);

+		},

+

+		fatal: function() {

+			this.log(Level.FATAL, arguments);

+		},

+

+		isEnabledFor: function(level) {

+			return level.isGreaterOrEqual(this.getEffectiveLevel());

+		},

+

+		isTraceEnabled: function() {

+			return this.isEnabledFor(Level.TRACE);

+		},

+

+		isDebugEnabled: function() {

+			return this.isEnabledFor(Level.DEBUG);

+		},

+

+		isInfoEnabled: function() {

+			return this.isEnabledFor(Level.INFO);

+		},

+

+		isWarnEnabled: function() {

+			return this.isEnabledFor(Level.WARN);

+		},

+

+		isErrorEnabled: function() {

+			return this.isEnabledFor(Level.ERROR);

+		},

+

+		isFatalEnabled: function() {

+			return this.isEnabledFor(Level.FATAL);

+		}

+	};

+

+	Logger.prototype.trace.isEntryPoint = true;

+	Logger.prototype.debug.isEntryPoint = true;

+	Logger.prototype.info.isEntryPoint = true;

+	Logger.prototype.warn.isEntryPoint = true;

+	Logger.prototype.error.isEntryPoint = true;

+	Logger.prototype.fatal.isEntryPoint = true;

+

+	/* ---------------------------------------------------------------------- */

+	// Logger access methods

+

+	// Hashtable of loggers keyed by logger name

+	var loggers = {};

+	var loggerNames = [];

+

+	var ROOT_LOGGER_DEFAULT_LEVEL = Level.DEBUG;

+	var rootLogger = new Logger(rootLoggerName);

+	rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);

+

+	log4javascript.getRootLogger = function() {

+		return rootLogger;

+	};

+

+	log4javascript.getLogger = function(loggerName) {

+		// Use default logger if loggerName is not specified or invalid

+		if (!(typeof loggerName == "string")) {

+			loggerName = anonymousLoggerName;

+			logLog.warn("log4javascript.getLogger: non-string logger name "	+

+				toStr(loggerName) + " supplied, returning anonymous logger");

+		}

+

+		// Do not allow retrieval of the root logger by name

+		if (loggerName == rootLoggerName) {

+			handleError("log4javascript.getLogger: root logger may not be obtained by name");

+		}

+

+		// Create the logger for this name if it doesn't already exist

+		if (!loggers[loggerName]) {

+			var logger = new Logger(loggerName);

+			loggers[loggerName] = logger;

+			loggerNames.push(loggerName);

+

+			// Set up parent logger, if it doesn't exist

+			var lastDotIndex = loggerName.lastIndexOf(".");

+			var parentLogger;

+			if (lastDotIndex > -1) {

+				var parentLoggerName = loggerName.substring(0, lastDotIndex);

+				parentLogger = log4javascript.getLogger(parentLoggerName); // Recursively sets up grandparents etc.

+			} else {

+				parentLogger = rootLogger;

+			}

+			parentLogger.addChild(logger);

+		}

+		return loggers[loggerName];

+	};

+

+	var defaultLogger = null;

+	log4javascript.getDefaultLogger = function() {

+		if (!defaultLogger) {

+			defaultLogger = log4javascript.getLogger(defaultLoggerName);

+			var a = new log4javascript.PopUpAppender();

+			defaultLogger.addAppender(a);

+		}

+		return defaultLogger;

+	};

+

+	var nullLogger = null;

+	log4javascript.getNullLogger = function() {

+		if (!nullLogger) {

+			nullLogger = new Logger(nullLoggerName);

+			nullLogger.setLevel(Level.OFF);

+		}

+		return nullLogger;

+	};

+

+	// Destroys all loggers

+	log4javascript.resetConfiguration = function() {

+		rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);

+		loggers = {};

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Logging events

+

+	var LoggingEvent = function(logger, timeStamp, level, messages,

+			exception) {

+		this.logger = logger;

+		this.timeStamp = timeStamp;

+		this.timeStampInMilliseconds = timeStamp.getTime();

+		this.timeStampInSeconds = Math.floor(this.timeStampInMilliseconds / 1000);

+		this.milliseconds = this.timeStamp.getMilliseconds();

+		this.level = level;

+		this.messages = messages;

+		this.exception = exception;

+	};

+

+	LoggingEvent.prototype = {

+		getThrowableStrRep: function() {

+			return this.exception ?

+				getExceptionStringRep(this.exception) : "";

+		},

+		getCombinedMessages: function() {

+			return (this.messages.length == 1) ? this.messages[0] :

+				   this.messages.join(newLine);

+		},

+		toString: function() {

+			return "LoggingEvent[" + this.level + "]";

+		}

+	};

+

+	log4javascript.LoggingEvent = LoggingEvent;

+

+	/* ---------------------------------------------------------------------- */

+	// Layout prototype

+

+	var Layout = function() {

+	};

+

+	Layout.prototype = {

+		defaults: {

+			loggerKey: "logger",

+			timeStampKey: "timestamp",

+			millisecondsKey: "milliseconds",

+			levelKey: "level",

+			messageKey: "message",

+			exceptionKey: "exception",

+			urlKey: "url"

+		},

+		loggerKey: "logger",

+		timeStampKey: "timestamp",

+		millisecondsKey: "milliseconds",

+		levelKey: "level",

+		messageKey: "message",

+		exceptionKey: "exception",

+		urlKey: "url",

+		batchHeader: "",

+		batchFooter: "",

+		batchSeparator: "",

+		returnsPostData: false,

+		overrideTimeStampsSetting: false,

+		useTimeStampsInMilliseconds: null,

+

+		format: function() {

+			handleError("Layout.format: layout supplied has no format() method");

+		},

+

+		ignoresThrowable: function() {

+			handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");

+		},

+

+		getContentType: function() {

+			return "text/plain";

+		},

+

+		allowBatching: function() {

+			return true;

+		},

+

+		setTimeStampsInMilliseconds: function(timeStampsInMilliseconds) {

+			this.overrideTimeStampsSetting = true;

+			this.useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);

+		},

+

+		isTimeStampsInMilliseconds: function() {

+			return this.overrideTimeStampsSetting ?

+				this.useTimeStampsInMilliseconds : useTimeStampsInMilliseconds;

+		},

+

+		getTimeStampValue: function(loggingEvent) {

+			return this.isTimeStampsInMilliseconds() ?

+				loggingEvent.timeStampInMilliseconds : loggingEvent.timeStampInSeconds;

+		},

+

+		getDataValues: function(loggingEvent, combineMessages) {

+			var dataValues = [

+				[this.loggerKey, loggingEvent.logger.name],

+				[this.timeStampKey, this.getTimeStampValue(loggingEvent)],

+				[this.levelKey, loggingEvent.level.name],

+				[this.urlKey, window.location.href],

+				[this.messageKey, combineMessages ? loggingEvent.getCombinedMessages() : loggingEvent.messages]

+			];

+			if (!this.isTimeStampsInMilliseconds()) {

+				dataValues.push([this.millisecondsKey, loggingEvent.milliseconds]);

+			}

+			if (loggingEvent.exception) {

+				dataValues.push([this.exceptionKey, getExceptionStringRep(loggingEvent.exception)]);

+			}

+			if (this.hasCustomFields()) {

+				for (var i = 0, len = this.customFields.length; i < len; i++) {

+					var val = this.customFields[i].value;

+

+					// Check if the value is a function. If so, execute it, passing it the

+					// current layout and the logging event

+					if (typeof val === "function") {

+						val = val(this, loggingEvent);

+					}

+					dataValues.push([this.customFields[i].name, val]);

+				}

+			}

+			return dataValues;

+		},

+

+		setKeys: function(loggerKey, timeStampKey, levelKey, messageKey,

+				exceptionKey, urlKey, millisecondsKey) {

+			this.loggerKey = extractStringFromParam(loggerKey, this.defaults.loggerKey);

+			this.timeStampKey = extractStringFromParam(timeStampKey, this.defaults.timeStampKey);

+			this.levelKey = extractStringFromParam(levelKey, this.defaults.levelKey);

+			this.messageKey = extractStringFromParam(messageKey, this.defaults.messageKey);

+			this.exceptionKey = extractStringFromParam(exceptionKey, this.defaults.exceptionKey);

+			this.urlKey = extractStringFromParam(urlKey, this.defaults.urlKey);

+			this.millisecondsKey = extractStringFromParam(millisecondsKey, this.defaults.millisecondsKey);

+		},

+

+		setCustomField: function(name, value) {

+			var fieldUpdated = false;

+			for (var i = 0, len = this.customFields.length; i < len; i++) {

+				if (this.customFields[i].name === name) {

+					this.customFields[i].value = value;

+					fieldUpdated = true;

+				}

+			}

+			if (!fieldUpdated) {

+				this.customFields.push({"name": name, "value": value});

+			}

+		},

+

+		hasCustomFields: function() {

+			return (this.customFields.length > 0);

+		},

+

+		toString: function() {

+			handleError("Layout.toString: all layouts must override this method");

+		}

+	};

+

+	log4javascript.Layout = Layout;

+

+	/* ---------------------------------------------------------------------- */

+	// Appender prototype

+

+	var Appender = function() {};

+

+	Appender.prototype = new EventSupport();

+

+	Appender.prototype.layout = new PatternLayout();

+	Appender.prototype.threshold = Level.ALL;

+	Appender.prototype.loggers = [];

+

+	// Performs threshold checks before delegating actual logging to the

+	// subclass's specific append method.

+	Appender.prototype.doAppend = function(loggingEvent) {

+		if (enabled && loggingEvent.level.level >= this.threshold.level) {

+			this.append(loggingEvent);

+		}

+	};

+

+	Appender.prototype.append = function(loggingEvent) {};

+

+	Appender.prototype.setLayout = function(layout) {

+		if (layout instanceof Layout) {

+			this.layout = layout;

+		} else {

+			handleError("Appender.setLayout: layout supplied to " +

+				this.toString() + " is not a subclass of Layout");

+		}

+	};

+

+	Appender.prototype.getLayout = function() {

+		return this.layout;

+	};

+

+	Appender.prototype.setThreshold = function(threshold) {

+		if (threshold instanceof Level) {

+			this.threshold = threshold;

+		} else {

+			handleError("Appender.setThreshold: threshold supplied to " +

+				this.toString() + " is not a subclass of Level");

+		}

+	};

+

+	Appender.prototype.getThreshold = function() {

+		return this.threshold;

+	};

+

+	Appender.prototype.setAddedToLogger = function(logger) {

+		this.loggers.push(logger);

+	};

+

+	Appender.prototype.setRemovedFromLogger = function(logger) {

+		array_remove(this.loggers, logger);

+	};

+

+	Appender.prototype.group = emptyFunction;

+	Appender.prototype.groupEnd = emptyFunction;

+

+	Appender.prototype.toString = function() {

+		handleError("Appender.toString: all appenders must override this method");

+	};

+

+	log4javascript.Appender = Appender;

+

+	/* ---------------------------------------------------------------------- */

+	// SimpleLayout 

+

+	function SimpleLayout() {

+		this.customFields = [];

+	}

+

+	SimpleLayout.prototype = new Layout();

+

+	SimpleLayout.prototype.format = function(loggingEvent) {

+		return loggingEvent.level.name + " - " + loggingEvent.getCombinedMessages();

+	};

+

+	SimpleLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	SimpleLayout.prototype.toString = function() {

+	    return "SimpleLayout";

+	};

+

+	log4javascript.SimpleLayout = SimpleLayout;

+	/* ----------------------------------------------------------------------- */

+	// NullLayout 

+

+	function NullLayout() {

+		this.customFields = [];

+	}

+

+	NullLayout.prototype = new Layout();

+

+	NullLayout.prototype.format = function(loggingEvent) {

+		return loggingEvent.messages;

+	};

+

+	NullLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	NullLayout.prototype.toString = function() {

+	    return "NullLayout";

+	};

+

+	log4javascript.NullLayout = NullLayout;

+/* ---------------------------------------------------------------------- */

+	// XmlLayout

+

+	function XmlLayout(combineMessages) {

+		this.combineMessages = extractBooleanFromParam(combineMessages, true);

+		this.customFields = [];

+	}

+

+	XmlLayout.prototype = new Layout();

+

+	XmlLayout.prototype.isCombinedMessages = function() {

+		return this.combineMessages;

+	};

+

+	XmlLayout.prototype.getContentType = function() {

+		return "text/xml";

+	};

+

+	XmlLayout.prototype.escapeCdata = function(str) {

+		return str.replace(/\]\]>/, "]]>]]&gt;<![CDATA[");

+	};

+

+	XmlLayout.prototype.format = function(loggingEvent) {

+		var layout = this;

+		var i, len;

+		function formatMessage(message) {

+			message = (typeof message === "string") ? message : toStr(message);

+			return "<log4javascript:message><![CDATA[" +

+				layout.escapeCdata(message) + "]]></log4javascript:message>";

+		}

+

+		var str = "<log4javascript:event logger=\"" + loggingEvent.logger.name +

+			"\" timestamp=\"" + this.getTimeStampValue(loggingEvent) + "\"";

+		if (!this.isTimeStampsInMilliseconds()) {

+			str += " milliseconds=\"" + loggingEvent.milliseconds + "\"";

+		}

+		str += " level=\"" + loggingEvent.level.name + "\">" + newLine;

+		if (this.combineMessages) {

+			str += formatMessage(loggingEvent.getCombinedMessages());

+		} else {

+			str += "<log4javascript:messages>" + newLine;

+			for (i = 0, len = loggingEvent.messages.length; i < len; i++) {

+				str += formatMessage(loggingEvent.messages[i]) + newLine;

+			}

+			str += "</log4javascript:messages>" + newLine;

+		}

+		if (this.hasCustomFields()) {

+			for (i = 0, len = this.customFields.length; i < len; i++) {

+				str += "<log4javascript:customfield name=\"" +

+					this.customFields[i].name + "\"><![CDATA[" +

+					this.customFields[i].value.toString() +

+					"]]></log4javascript:customfield>" + newLine;

+			}

+		}

+		if (loggingEvent.exception) {

+			str += "<log4javascript:exception><![CDATA[" +

+				getExceptionStringRep(loggingEvent.exception) +

+				"]]></log4javascript:exception>" + newLine;

+		}

+		str += "</log4javascript:event>" + newLine + newLine;

+		return str;

+	};

+

+	XmlLayout.prototype.ignoresThrowable = function() {

+	    return false;

+	};

+

+	XmlLayout.prototype.toString = function() {

+	    return "XmlLayout";

+	};

+

+	log4javascript.XmlLayout = XmlLayout;

+	/* ---------------------------------------------------------------------- */

+	// JsonLayout related

+

+	function escapeNewLines(str) {

+		return str.replace(/\r\n|\r|\n/g, "\\r\\n");

+	}

+

+	function JsonLayout(readable, combineMessages) {

+		this.readable = extractBooleanFromParam(readable, false);

+		this.combineMessages = extractBooleanFromParam(combineMessages, true);

+		this.batchHeader = this.readable ? "[" + newLine : "[";

+		this.batchFooter = this.readable ? "]" + newLine : "]";

+		this.batchSeparator = this.readable ? "," + newLine : ",";

+		this.setKeys();

+		this.colon = this.readable ? ": " : ":";

+		this.tab = this.readable ? "\t" : "";

+		this.lineBreak = this.readable ? newLine : "";

+		this.customFields = [];

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// JsonLayout

+

+	JsonLayout.prototype = new Layout();

+

+	JsonLayout.prototype.isReadable = function() {

+		return this.readable;

+	};

+

+	JsonLayout.prototype.isCombinedMessages = function() {

+		return this.combineMessages;

+	};

+

+    JsonLayout.prototype.format = function(loggingEvent) {

+        var layout = this;

+        var dataValues = this.getDataValues(loggingEvent, this.combineMessages);

+        var str = "{" + this.lineBreak;

+        var i, len;

+

+        function formatValue(val, prefix, expand) {

+            // Check the type of the data value to decide whether quotation marks

+            // or expansion are required

+            var formattedValue;

+            var valType = typeof val;

+            if (val instanceof Date) {

+                formattedValue = String(val.getTime());

+            } else if (expand && (val instanceof Array)) {

+                formattedValue = "[" + layout.lineBreak;

+                for (var i = 0, len = val.length; i < len; i++) {

+                    var childPrefix = prefix + layout.tab;

+                    formattedValue += childPrefix + formatValue(val[i], childPrefix, false);

+                    if (i < val.length - 1) {

+                        formattedValue += ",";

+                    }

+                    formattedValue += layout.lineBreak;

+                }

+                formattedValue += prefix + "]";

+            } else if (valType !== "number" && valType !== "boolean") {

+                formattedValue = "\"" + escapeNewLines(toStr(val).replace(/\"/g, "\\\"")) + "\"";

+            } else {

+                formattedValue = val;

+            }

+            return formattedValue;

+        }

+

+        for (i = 0, len = dataValues.length - 1; i <= len; i++) {

+            str += this.tab + "\"" + dataValues[i][0] + "\"" + this.colon + formatValue(dataValues[i][1], this.tab, true);

+            if (i < len) {

+                str += ",";

+            }

+            str += this.lineBreak;

+        }

+

+        str += "}" + this.lineBreak;

+        return str;

+    };

+

+	JsonLayout.prototype.ignoresThrowable = function() {

+	    return false;

+	};

+

+	JsonLayout.prototype.toString = function() {

+	    return "JsonLayout";

+	};

+

+	JsonLayout.prototype.getContentType = function() {

+		return "application/json";

+	};

+

+	log4javascript.JsonLayout = JsonLayout;

+	/* ---------------------------------------------------------------------- */

+	// HttpPostDataLayout

+

+	function HttpPostDataLayout() {

+		this.setKeys();

+		this.customFields = [];

+		this.returnsPostData = true;

+	}

+

+	HttpPostDataLayout.prototype = new Layout();

+

+	// Disable batching

+	HttpPostDataLayout.prototype.allowBatching = function() {

+		return false;

+	};

+

+	HttpPostDataLayout.prototype.format = function(loggingEvent) {

+		var dataValues = this.getDataValues(loggingEvent);

+		var queryBits = [];

+		for (var i = 0, len = dataValues.length; i < len; i++) {

+			var val = (dataValues[i][1] instanceof Date) ?

+				String(dataValues[i][1].getTime()) : dataValues[i][1];

+			queryBits.push(urlEncode(dataValues[i][0]) + "=" + urlEncode(val));

+		}

+		return queryBits.join("&");

+	};

+

+	HttpPostDataLayout.prototype.ignoresThrowable = function(loggingEvent) {

+	    return false;

+	};

+

+	HttpPostDataLayout.prototype.toString = function() {

+	    return "HttpPostDataLayout";

+	};

+

+	log4javascript.HttpPostDataLayout = HttpPostDataLayout;

+	/* ---------------------------------------------------------------------- */

+	// formatObjectExpansion

+

+	function formatObjectExpansion(obj, depth, indentation) {

+		var objectsExpanded = [];

+

+		function doFormat(obj, depth, indentation) {

+			var i, j, len, childDepth, childIndentation, childLines, expansion,

+				childExpansion;

+

+			if (!indentation) {

+				indentation = "";

+			}

+

+			function formatString(text) {

+				var lines = splitIntoLines(text);

+				for (var j = 1, jLen = lines.length; j < jLen; j++) {

+					lines[j] = indentation + lines[j];

+				}

+				return lines.join(newLine);

+			}

+

+			if (obj === null) {

+				return "null";

+			} else if (typeof obj == "undefined") {

+				return "undefined";

+			} else if (typeof obj == "string") {

+				return formatString(obj);

+			} else if (typeof obj == "object" && array_contains(objectsExpanded, obj)) {

+				try {

+					expansion = toStr(obj);

+				} catch (ex) {

+					expansion = "Error formatting property. Details: " + getExceptionStringRep(ex);

+				}

+				return expansion + " [already expanded]";

+			} else if ((obj instanceof Array) && depth > 0) {

+				objectsExpanded.push(obj);

+				expansion = "[" + newLine;

+				childDepth = depth - 1;

+				childIndentation = indentation + "  ";

+				childLines = [];

+				for (i = 0, len = obj.length; i < len; i++) {

+					try {

+						childExpansion = doFormat(obj[i], childDepth, childIndentation);

+						childLines.push(childIndentation + childExpansion);

+					} catch (ex) {

+						childLines.push(childIndentation + "Error formatting array member. Details: " +

+							getExceptionStringRep(ex) + "");

+					}

+				}

+				expansion += childLines.join("," + newLine) + newLine + indentation + "]";

+				return expansion;

+            } else if (Object.prototype.toString.call(obj) == "[object Date]") {

+                return obj.toString();

+			} else if (typeof obj == "object" && depth > 0) {

+				objectsExpanded.push(obj);

+				expansion = "{" + newLine;

+				childDepth = depth - 1;

+				childIndentation = indentation + "  ";

+				childLines = [];

+				for (i in obj) {

+					try {

+						childExpansion = doFormat(obj[i], childDepth, childIndentation);

+						childLines.push(childIndentation + i + ": " + childExpansion);

+					} catch (ex) {

+						childLines.push(childIndentation + i + ": Error formatting property. Details: " +

+							getExceptionStringRep(ex));

+					}

+				}

+				expansion += childLines.join("," + newLine) + newLine + indentation + "}";

+				return expansion;

+			} else {

+				return formatString(toStr(obj));

+			}

+		}

+		return doFormat(obj, depth, indentation);

+	}

+	/* ---------------------------------------------------------------------- */

+	// Date-related stuff

+

+	var SimpleDateFormat;

+

+	(function() {

+		var regex = /('[^']*')|(G+|y+|M+|w+|W+|D+|d+|F+|E+|a+|H+|k+|K+|h+|m+|s+|S+|Z+)|([a-zA-Z]+)|([^a-zA-Z']+)/;

+		var monthNames = ["January", "February", "March", "April", "May", "June",

+			"July", "August", "September", "October", "November", "December"];

+		var dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

+		var TEXT2 = 0, TEXT3 = 1, NUMBER = 2, YEAR = 3, MONTH = 4, TIMEZONE = 5;

+		var types = {

+			G : TEXT2,

+			y : YEAR,

+			M : MONTH,

+			w : NUMBER,

+			W : NUMBER,

+			D : NUMBER,

+			d : NUMBER,

+			F : NUMBER,

+			E : TEXT3,

+			a : TEXT2,

+			H : NUMBER,

+			k : NUMBER,

+			K : NUMBER,

+			h : NUMBER,

+			m : NUMBER,

+			s : NUMBER,

+			S : NUMBER,

+			Z : TIMEZONE

+		};

+		var ONE_DAY = 24 * 60 * 60 * 1000;

+		var ONE_WEEK = 7 * ONE_DAY;

+		var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK = 1;

+

+		var newDateAtMidnight = function(year, month, day) {

+			var d = new Date(year, month, day, 0, 0, 0);

+			d.setMilliseconds(0);

+			return d;

+		};

+

+		Date.prototype.getDifference = function(date) {

+			return this.getTime() - date.getTime();

+		};

+

+		Date.prototype.isBefore = function(d) {

+			return this.getTime() < d.getTime();

+		};

+

+		Date.prototype.getUTCTime = function() {

+			return Date.UTC(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours(), this.getMinutes(),

+					this.getSeconds(), this.getMilliseconds());

+		};

+

+		Date.prototype.getTimeSince = function(d) {

+			return this.getUTCTime() - d.getUTCTime();

+		};

+

+		Date.prototype.getPreviousSunday = function() {

+			// Using midday avoids any possibility of DST messing things up

+			var midday = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 12, 0, 0);

+			var previousSunday = new Date(midday.getTime() - this.getDay() * ONE_DAY);

+			return newDateAtMidnight(previousSunday.getFullYear(), previousSunday.getMonth(),

+					previousSunday.getDate());

+		};

+

+		Date.prototype.getWeekInYear = function(minimalDaysInFirstWeek) {

+			if (isUndefined(this.minimalDaysInFirstWeek)) {

+				minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;

+			}

+			var previousSunday = this.getPreviousSunday();

+			var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);

+			var numberOfSundays = previousSunday.isBefore(startOfYear) ?

+				0 : 1 + Math.floor(previousSunday.getTimeSince(startOfYear) / ONE_WEEK);

+			var numberOfDaysInFirstWeek =  7 - startOfYear.getDay();

+			var weekInYear = numberOfSundays;

+			if (numberOfDaysInFirstWeek < minimalDaysInFirstWeek) {

+				weekInYear--;

+			}

+			return weekInYear;

+		};

+

+		Date.prototype.getWeekInMonth = function(minimalDaysInFirstWeek) {

+			if (isUndefined(this.minimalDaysInFirstWeek)) {

+				minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;

+			}

+			var previousSunday = this.getPreviousSunday();

+			var startOfMonth = newDateAtMidnight(this.getFullYear(), this.getMonth(), 1);

+			var numberOfSundays = previousSunday.isBefore(startOfMonth) ?

+				0 : 1 + Math.floor(previousSunday.getTimeSince(startOfMonth) / ONE_WEEK);

+			var numberOfDaysInFirstWeek =  7 - startOfMonth.getDay();

+			var weekInMonth = numberOfSundays;

+			if (numberOfDaysInFirstWeek >= minimalDaysInFirstWeek) {

+				weekInMonth++;

+			}

+			return weekInMonth;

+		};

+

+		Date.prototype.getDayInYear = function() {

+			var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);

+			return 1 + Math.floor(this.getTimeSince(startOfYear) / ONE_DAY);

+		};

+

+		/* ------------------------------------------------------------------ */

+

+		SimpleDateFormat = function(formatString) {

+			this.formatString = formatString;

+		};

+

+		/**

+		 * Sets the minimum number of days in a week in order for that week to

+		 * be considered as belonging to a particular month or year

+		 */

+		SimpleDateFormat.prototype.setMinimalDaysInFirstWeek = function(days) {

+			this.minimalDaysInFirstWeek = days;

+		};

+

+		SimpleDateFormat.prototype.getMinimalDaysInFirstWeek = function() {

+			return isUndefined(this.minimalDaysInFirstWeek)	?

+				DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK : this.minimalDaysInFirstWeek;

+		};

+

+		var padWithZeroes = function(str, len) {

+			while (str.length < len) {

+				str = "0" + str;

+			}

+			return str;

+		};

+

+		var formatText = function(data, numberOfLetters, minLength) {

+			return (numberOfLetters >= 4) ? data : data.substr(0, Math.max(minLength, numberOfLetters));

+		};

+

+		var formatNumber = function(data, numberOfLetters) {

+			var dataString = "" + data;

+			// Pad with 0s as necessary

+			return padWithZeroes(dataString, numberOfLetters);

+		};

+

+		SimpleDateFormat.prototype.format = function(date) {

+			var formattedString = "";

+			var result;

+			var searchString = this.formatString;

+			while ((result = regex.exec(searchString))) {

+				var quotedString = result[1];

+				var patternLetters = result[2];

+				var otherLetters = result[3];

+				var otherCharacters = result[4];

+

+				// If the pattern matched is quoted string, output the text between the quotes

+				if (quotedString) {

+					if (quotedString == "''") {

+						formattedString += "'";

+					} else {

+						formattedString += quotedString.substring(1, quotedString.length - 1);

+					}

+				} else if (otherLetters) {

+					// Swallow non-pattern letters by doing nothing here

+				} else if (otherCharacters) {

+					// Simply output other characters

+					formattedString += otherCharacters;

+				} else if (patternLetters) {

+					// Replace pattern letters

+					var patternLetter = patternLetters.charAt(0);

+					var numberOfLetters = patternLetters.length;

+					var rawData = "";

+					switch(patternLetter) {

+						case "G":

+							rawData = "AD";

+							break;

+						case "y":

+							rawData = date.getFullYear();

+							break;

+						case "M":

+							rawData = date.getMonth();

+							break;

+						case "w":

+							rawData = date.getWeekInYear(this.getMinimalDaysInFirstWeek());

+							break;

+						case "W":

+							rawData = date.getWeekInMonth(this.getMinimalDaysInFirstWeek());

+							break;

+						case "D":

+							rawData = date.getDayInYear();

+							break;

+						case "d":

+							rawData = date.getDate();

+							break;

+						case "F":

+							rawData = 1 + Math.floor((date.getDate() - 1) / 7);

+							break;

+						case "E":

+							rawData = dayNames[date.getDay()];

+							break;

+						case "a":

+							rawData = (date.getHours() >= 12) ? "PM" : "AM";

+							break;

+						case "H":

+							rawData = date.getHours();

+							break;

+						case "k":

+							rawData = date.getHours() || 24;

+							break;

+						case "K":

+							rawData = date.getHours() % 12;

+							break;

+						case "h":

+							rawData = (date.getHours() % 12) || 12;

+							break;

+						case "m":

+							rawData = date.getMinutes();

+							break;

+						case "s":

+							rawData = date.getSeconds();

+							break;

+						case "S":

+							rawData = date.getMilliseconds();

+							break;

+						case "Z":

+							rawData = date.getTimezoneOffset(); // This returns the number of minutes since GMT was this time.

+							break;

+					}

+					// Format the raw data depending on the type

+					switch(types[patternLetter]) {

+						case TEXT2:

+							formattedString += formatText(rawData, numberOfLetters, 2);

+							break;

+						case TEXT3:

+							formattedString += formatText(rawData, numberOfLetters, 3);

+							break;

+						case NUMBER:

+							formattedString += formatNumber(rawData, numberOfLetters);

+							break;

+						case YEAR:

+							if (numberOfLetters <= 3) {

+								// Output a 2-digit year

+								var dataString = "" + rawData;

+								formattedString += dataString.substr(2, 2);

+							} else {

+								formattedString += formatNumber(rawData, numberOfLetters);

+							}

+							break;

+						case MONTH:

+							if (numberOfLetters >= 3) {

+								formattedString += formatText(monthNames[rawData], numberOfLetters, numberOfLetters);

+							} else {

+								// NB. Months returned by getMonth are zero-based

+								formattedString += formatNumber(rawData + 1, numberOfLetters);

+							}

+							break;

+						case TIMEZONE:

+							var isPositive = (rawData > 0);

+							// The following line looks like a mistake but isn't

+							// because of the way getTimezoneOffset measures.

+							var prefix = isPositive ? "-" : "+";

+							var absData = Math.abs(rawData);

+

+							// Hours

+							var hours = "" + Math.floor(absData / 60);

+							hours = padWithZeroes(hours, 2);

+							// Minutes

+							var minutes = "" + (absData % 60);

+							minutes = padWithZeroes(minutes, 2);

+

+							formattedString += prefix + hours + minutes;

+							break;

+					}

+				}

+				searchString = searchString.substr(result.index + result[0].length);

+			}

+			return formattedString;

+		};

+	})();

+

+	log4javascript.SimpleDateFormat = SimpleDateFormat;

+

+	/* ---------------------------------------------------------------------- */

+	// PatternLayout

+

+	function PatternLayout(pattern) {

+		if (pattern) {

+			this.pattern = pattern;

+		} else {

+			this.pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;

+		}

+		this.customFields = [];

+	}

+

+	PatternLayout.TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n";

+	PatternLayout.DEFAULT_CONVERSION_PATTERN = "%m%n";

+	PatternLayout.ISO8601_DATEFORMAT = "yyyy-MM-dd HH:mm:ss,SSS";

+	PatternLayout.DATETIME_DATEFORMAT = "dd MMM yyyy HH:mm:ss,SSS";

+	PatternLayout.ABSOLUTETIME_DATEFORMAT = "HH:mm:ss,SSS";

+

+	PatternLayout.prototype = new Layout();

+

+	PatternLayout.prototype.format = function(loggingEvent) {

+		var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;

+		var formattedString = "";

+		var result;

+		var searchString = this.pattern;

+

+		// Cannot use regex global flag since it doesn't work with exec in IE5

+		while ((result = regex.exec(searchString))) {

+			var matchedString = result[0];

+			var padding = result[1];

+			var truncation = result[2];

+			var conversionCharacter = result[3];

+			var specifier = result[5];

+			var text = result[6];

+

+			// Check if the pattern matched was just normal text

+			if (text) {

+				formattedString += "" + text;

+			} else {

+				// Create a raw replacement string based on the conversion

+				// character and specifier

+				var replacement = "";

+				switch(conversionCharacter) {

+					case "a": // Array of messages

+					case "m": // Message

+						var depth = 0;

+						if (specifier) {

+							depth = parseInt(specifier, 10);

+							if (isNaN(depth)) {

+								handleError("PatternLayout.format: invalid specifier '" +

+									specifier + "' for conversion character '" + conversionCharacter +

+									"' - should be a number");

+								depth = 0;

+							}

+						}

+						var messages = (conversionCharacter === "a") ? loggingEvent.messages[0] : loggingEvent.messages;

+						for (var i = 0, len = messages.length; i < len; i++) {

+							if (i > 0 && (replacement.charAt(replacement.length - 1) !== " ")) {

+								replacement += " ";

+							}

+							if (depth === 0) {

+								replacement += messages[i];

+							} else {

+								replacement += formatObjectExpansion(messages[i], depth);

+							}

+						}

+						break;

+					case "c": // Logger name

+						var loggerName = loggingEvent.logger.name;

+						if (specifier) {

+							var precision = parseInt(specifier, 10);

+							var loggerNameBits = loggingEvent.logger.name.split(".");

+							if (precision >= loggerNameBits.length) {

+								replacement = loggerName;

+							} else {

+								replacement = loggerNameBits.slice(loggerNameBits.length - precision).join(".");

+							}

+						} else {

+							replacement = loggerName;

+						}

+						break;

+					case "d": // Date

+						var dateFormat = PatternLayout.ISO8601_DATEFORMAT;

+						if (specifier) {

+							dateFormat = specifier;

+							// Pick up special cases

+							if (dateFormat == "ISO8601") {

+								dateFormat = PatternLayout.ISO8601_DATEFORMAT;

+							} else if (dateFormat == "ABSOLUTE") {

+								dateFormat = PatternLayout.ABSOLUTETIME_DATEFORMAT;

+							} else if (dateFormat == "DATE") {

+								dateFormat = PatternLayout.DATETIME_DATEFORMAT;

+							}

+						}

+						// Format the date

+						replacement = (new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);

+						break;

+					case "f": // Custom field

+						if (this.hasCustomFields()) {

+							var fieldIndex = 0;

+							if (specifier) {

+								fieldIndex = parseInt(specifier, 10);

+								if (isNaN(fieldIndex)) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - should be a number");

+								} else if (fieldIndex === 0) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - must be greater than zero");

+								} else if (fieldIndex > this.customFields.length) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - there aren't that many custom fields");

+								} else {

+									fieldIndex = fieldIndex - 1;

+								}

+							}

+                            var val = this.customFields[fieldIndex].value;

+                            if (typeof val == "function") {

+                                val = val(this, loggingEvent);

+                            }

+                            replacement = val;

+						}

+						break;

+					case "n": // New line

+						replacement = newLine;

+						break;

+					case "p": // Level

+						replacement = loggingEvent.level.name;

+						break;

+					case "r": // Milliseconds since log4javascript startup

+						replacement = "" + loggingEvent.timeStamp.getDifference(applicationStartDate);

+						break;

+					case "%": // Literal % sign

+						replacement = "%";

+						break;

+					default:

+						replacement = matchedString;

+						break;

+				}

+				// Format the replacement according to any padding or

+				// truncation specified

+				var l;

+

+				// First, truncation

+				if (truncation) {

+					l = parseInt(truncation.substr(1), 10);

+					var strLen = replacement.length;

+					if (l < strLen) {

+						replacement = replacement.substring(strLen - l, strLen);

+					}

+				}

+				// Next, padding

+				if (padding) {

+					if (padding.charAt(0) == "-") {

+						l = parseInt(padding.substr(1), 10);

+						// Right pad with spaces

+						while (replacement.length < l) {

+							replacement += " ";

+						}

+					} else {

+						l = parseInt(padding, 10);

+						// Left pad with spaces

+						while (replacement.length < l) {

+							replacement = " " + replacement;

+						}

+					}

+				}

+				formattedString += replacement;

+			}

+			searchString = searchString.substr(result.index + result[0].length);

+		}

+		return formattedString;

+	};

+

+	PatternLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	PatternLayout.prototype.toString = function() {

+	    return "PatternLayout";

+	};

+

+	log4javascript.PatternLayout = PatternLayout;

+	/* ---------------------------------------------------------------------- */

+	// AlertAppender

+

+	function AlertAppender() {}

+

+	AlertAppender.prototype = new Appender();

+

+	AlertAppender.prototype.layout = new SimpleLayout();

+

+	AlertAppender.prototype.append = function(loggingEvent) {

+		var formattedMessage = this.getLayout().format(loggingEvent);

+		if (this.getLayout().ignoresThrowable()) {

+			formattedMessage += loggingEvent.getThrowableStrRep();

+		}

+		alert(formattedMessage);

+	};

+

+	AlertAppender.prototype.toString = function() {

+		return "AlertAppender";

+	};

+

+	log4javascript.AlertAppender = AlertAppender;

+	/* ---------------------------------------------------------------------- */

+	// BrowserConsoleAppender (only works in Opera and Safari and Firefox with

+	// Firebug extension)

+

+	function BrowserConsoleAppender() {}

+

+	BrowserConsoleAppender.prototype = new log4javascript.Appender();

+	BrowserConsoleAppender.prototype.layout = new NullLayout();

+	BrowserConsoleAppender.prototype.threshold = Level.DEBUG;

+

+	BrowserConsoleAppender.prototype.append = function(loggingEvent) {

+		var appender = this;

+

+		var getFormattedMessage = function() {

+			var layout = appender.getLayout();

+			var formattedMessage = layout.format(loggingEvent);

+			if (layout.ignoresThrowable() && loggingEvent.exception) {

+				formattedMessage += loggingEvent.getThrowableStrRep();

+			}

+			return formattedMessage;

+		};

+

+		if ((typeof opera != "undefined") && opera.postError) { // Opera

+			opera.postError(getFormattedMessage());

+		} else if (window.console && window.console.log) { // Safari and Firebug

+			var formattedMesage = getFormattedMessage();

+			// Log to Firebug using its logging methods or revert to the console.log

+			// method in Safari

+			if (window.console.debug && Level.DEBUG.isGreaterOrEqual(loggingEvent.level)) {

+				window.console.debug(formattedMesage);

+			} else if (window.console.info && Level.INFO.equals(loggingEvent.level)) {

+				window.console.info(formattedMesage);

+			} else if (window.console.warn && Level.WARN.equals(loggingEvent.level)) {

+				window.console.warn(formattedMesage);

+			} else if (window.console.error && loggingEvent.level.isGreaterOrEqual(Level.ERROR)) {

+				window.console.error(formattedMesage);

+			} else {

+				window.console.log(formattedMesage);

+			}

+		}

+	};

+

+	BrowserConsoleAppender.prototype.group = function(name) {

+		if (window.console && window.console.group) {

+			window.console.group(name);

+		}

+	};

+

+	BrowserConsoleAppender.prototype.groupEnd = function() {

+		if (window.console && window.console.groupEnd) {

+			window.console.groupEnd();

+		}

+	};

+

+	BrowserConsoleAppender.prototype.toString = function() {

+		return "BrowserConsoleAppender";

+	};

+

+	log4javascript.BrowserConsoleAppender = BrowserConsoleAppender;

+	/* ---------------------------------------------------------------------- */

+	// AjaxAppender related

+

+	var xmlHttpFactories = [

+		function() { return new XMLHttpRequest(); },

+		function() { return new ActiveXObject("Msxml2.XMLHTTP"); },

+		function() { return new ActiveXObject("Microsoft.XMLHTTP"); }

+	];

+

+	var getXmlHttp = function(errorHandler) {

+		// This is only run the first time; the value of getXmlHttp gets

+		// replaced with the factory that succeeds on the first run

+		var xmlHttp = null, factory;

+		for (var i = 0, len = xmlHttpFactories.length; i < len; i++) {

+			factory = xmlHttpFactories[i];

+			try {

+				xmlHttp = factory();

+				getXmlHttp = factory;

+				return xmlHttp;

+			} catch (e) {

+			}

+		}

+		// If we're here, all factories have failed, so throw an error

+		if (errorHandler) {

+			errorHandler();

+		} else {

+			handleError("getXmlHttp: unable to obtain XMLHttpRequest object");

+		}

+	};

+

+	function isHttpRequestSuccessful(xmlHttp) {

+		return isUndefined(xmlHttp.status) || xmlHttp.status === 0 ||

+			(xmlHttp.status >= 200 && xmlHttp.status < 300) ||

+			xmlHttp.status == 1223 /* Fix for IE */;

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// AjaxAppender

+

+	function AjaxAppender(url) {

+		var appender = this;

+		var isSupported = true;

+		if (!url) {

+			handleError("AjaxAppender: URL must be specified in constructor");

+			isSupported = false;

+		}

+

+		var timed = this.defaults.timed;

+		var waitForResponse = this.defaults.waitForResponse;

+		var batchSize = this.defaults.batchSize;

+		var timerInterval = this.defaults.timerInterval;

+		var requestSuccessCallback = this.defaults.requestSuccessCallback;

+		var failCallback = this.defaults.failCallback;

+		var postVarName = this.defaults.postVarName;

+		var sendAllOnUnload = this.defaults.sendAllOnUnload;

+		var contentType = this.defaults.contentType;

+		var sessionId = null;

+

+		var queuedLoggingEvents = [];

+		var queuedRequests = [];

+		var headers = [];

+		var sending = false;

+		var initialized = false;

+

+		// Configuration methods. The function scope is used to prevent

+		// direct alteration to the appender configuration properties.

+		function checkCanConfigure(configOptionName) {

+			if (initialized) {

+				handleError("AjaxAppender: configuration option '" +

+					configOptionName +

+					"' may not be set after the appender has been initialized");

+				return false;

+			}

+			return true;

+		}

+

+		this.getSessionId = function() { return sessionId; };

+		this.setSessionId = function(sessionIdParam) {

+			sessionId = extractStringFromParam(sessionIdParam, null);

+			this.layout.setCustomField("sessionid", sessionId);

+		};

+

+		this.setLayout = function(layoutParam) {

+			if (checkCanConfigure("layout")) {

+				this.layout = layoutParam;

+				// Set the session id as a custom field on the layout, if not already present

+				if (sessionId !== null) {

+					this.setSessionId(sessionId);

+				}

+			}

+		};

+

+		this.isTimed = function() { return timed; };

+		this.setTimed = function(timedParam) {

+			if (checkCanConfigure("timed")) {

+				timed = bool(timedParam);

+			}

+		};

+

+		this.getTimerInterval = function() { return timerInterval; };

+		this.setTimerInterval = function(timerIntervalParam) {

+			if (checkCanConfigure("timerInterval")) {

+				timerInterval = extractIntFromParam(timerIntervalParam, timerInterval);

+			}

+		};

+

+		this.isWaitForResponse = function() { return waitForResponse; };

+		this.setWaitForResponse = function(waitForResponseParam) {

+			if (checkCanConfigure("waitForResponse")) {

+				waitForResponse = bool(waitForResponseParam);

+			}

+		};

+

+		this.getBatchSize = function() { return batchSize; };

+		this.setBatchSize = function(batchSizeParam) {

+			if (checkCanConfigure("batchSize")) {

+				batchSize = extractIntFromParam(batchSizeParam, batchSize);

+			}

+		};

+

+		this.isSendAllOnUnload = function() { return sendAllOnUnload; };

+		this.setSendAllOnUnload = function(sendAllOnUnloadParam) {

+			if (checkCanConfigure("sendAllOnUnload")) {

+				sendAllOnUnload = extractBooleanFromParam(sendAllOnUnloadParam, sendAllOnUnload);

+			}

+		};

+

+		this.setRequestSuccessCallback = function(requestSuccessCallbackParam) {

+			requestSuccessCallback = extractFunctionFromParam(requestSuccessCallbackParam, requestSuccessCallback);

+		};

+

+		this.setFailCallback = function(failCallbackParam) {

+			failCallback = extractFunctionFromParam(failCallbackParam, failCallback);

+		};

+

+		this.getPostVarName = function() { return postVarName; };

+		this.setPostVarName = function(postVarNameParam) {

+			if (checkCanConfigure("postVarName")) {

+				postVarName = extractStringFromParam(postVarNameParam, postVarName);

+			}

+		};

+

+		this.getHeaders = function() { return headers; };

+		this.addHeader = function(name, value) {

+			if (name.toLowerCase() == "content-type") {

+				contentType = value;

+			} else {

+				headers.push( { name: name, value: value } );

+			}

+		};

+

+		// Internal functions

+		function sendAll() {

+			if (isSupported && enabled) {

+				sending = true;

+				var currentRequestBatch;

+				if (waitForResponse) {

+					// Send the first request then use this function as the callback once

+					// the response comes back

+					if (queuedRequests.length > 0) {

+						currentRequestBatch = queuedRequests.shift();

+						sendRequest(preparePostData(currentRequestBatch), sendAll);

+					} else {

+						sending = false;

+						if (timed) {

+							scheduleSending();

+						}

+					}

+				} else {

+					// Rattle off all the requests without waiting to see the response

+					while ((currentRequestBatch = queuedRequests.shift())) {

+						sendRequest(preparePostData(currentRequestBatch));

+					}

+					sending = false;

+					if (timed) {

+						scheduleSending();

+					}

+				}

+			}

+		}

+

+		this.sendAll = sendAll;

+

+		// Called when the window unloads. At this point we're past caring about

+		// waiting for responses or timers or incomplete batches - everything

+		// must go, now

+		function sendAllRemaining() {

+			var sendingAnything = false;

+			if (isSupported && enabled) {

+				// Create requests for everything left over, batched as normal

+				var actualBatchSize = appender.getLayout().allowBatching() ? batchSize : 1;

+				var currentLoggingEvent;

+				var batchedLoggingEvents = [];

+				while ((currentLoggingEvent = queuedLoggingEvents.shift())) {

+					batchedLoggingEvents.push(currentLoggingEvent);

+					if (queuedLoggingEvents.length >= actualBatchSize) {

+						// Queue this batch of log entries

+						queuedRequests.push(batchedLoggingEvents);

+						batchedLoggingEvents = [];

+					}

+				}

+				// If there's a partially completed batch, add it

+				if (batchedLoggingEvents.length > 0) {

+					queuedRequests.push(batchedLoggingEvents);

+				}

+				sendingAnything = (queuedRequests.length > 0);

+				waitForResponse = false;

+				timed = false;

+				sendAll();

+			}

+			return sendingAnything;

+		}

+

+		this.sendAllRemaining = sendAllRemaining;

+

+		function preparePostData(batchedLoggingEvents) {

+			// Format the logging events

+			var formattedMessages = [];

+			var currentLoggingEvent;

+			var postData = "";

+			while ((currentLoggingEvent = batchedLoggingEvents.shift())) {

+				var currentFormattedMessage = appender.getLayout().format(currentLoggingEvent);

+				if (appender.getLayout().ignoresThrowable()) {

+					currentFormattedMessage += currentLoggingEvent.getThrowableStrRep();

+				}

+				formattedMessages.push(currentFormattedMessage);

+			}

+			// Create the post data string

+			if (batchedLoggingEvents.length == 1) {

+				postData = formattedMessages.join("");

+			} else {

+				postData = appender.getLayout().batchHeader +

+					formattedMessages.join(appender.getLayout().batchSeparator) +

+					appender.getLayout().batchFooter;

+			}

+			if (contentType == appender.defaults.contentType) {

+				postData = appender.getLayout().returnsPostData ? postData :

+					urlEncode(postVarName) + "=" + urlEncode(postData);

+				// Add the layout name to the post data

+				if (postData.length > 0) {

+					postData += "&";

+				}

+				postData += "layout=" + urlEncode(appender.getLayout().toString());

+			}

+			return postData;

+		}

+

+		function scheduleSending() {

+			window.setTimeout(sendAll, timerInterval);

+		}

+

+		function xmlHttpErrorHandler() {

+			var msg = "AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";

+			handleError(msg);

+			isSupported = false;

+			if (failCallback) {

+				failCallback(msg);

+			}

+		}

+

+		function sendRequest(postData, successCallback) {

+			try {

+				var xmlHttp = getXmlHttp(xmlHttpErrorHandler);

+				if (isSupported) {

+					if (xmlHttp.overrideMimeType) {

+						xmlHttp.overrideMimeType(appender.getLayout().getContentType());

+					}

+					xmlHttp.onreadystatechange = function() {

+						if (xmlHttp.readyState == 4) {

+							if (isHttpRequestSuccessful(xmlHttp)) {

+								if (requestSuccessCallback) {

+									requestSuccessCallback(xmlHttp);

+								}

+								if (successCallback) {

+									successCallback(xmlHttp);

+								}

+							} else {

+								var msg = "AjaxAppender.append: XMLHttpRequest request to URL " +

+									url + " returned status code " + xmlHttp.status;

+								handleError(msg);

+								if (failCallback) {

+									failCallback(msg);

+								}

+							}

+							xmlHttp.onreadystatechange = emptyFunction;

+							xmlHttp = null;

+						}

+					};

+					xmlHttp.open("POST", url, true);

+					try {

+						for (var i = 0, header; header = headers[i++]; ) {

+							xmlHttp.setRequestHeader(header.name, header.value);

+						}

+						xmlHttp.setRequestHeader("Content-Type", contentType);

+					} catch (headerEx) {

+						var msg = "AjaxAppender.append: your browser's XMLHttpRequest implementation" +

+							" does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";

+						handleError(msg);

+						isSupported = false;

+						if (failCallback) {

+							failCallback(msg);

+						}

+						return;

+					}

+					xmlHttp.send(postData);

+				}

+			} catch (ex) {

+				var errMsg = "AjaxAppender.append: error sending log message to " + url;

+				handleError(errMsg, ex);

+				isSupported = false;

+				if (failCallback) {

+					failCallback(errMsg + ". Details: " + getExceptionStringRep(ex));

+				}

+			}

+		}

+

+		this.append = function(loggingEvent) {

+			if (isSupported) {

+				if (!initialized) {

+					init();

+				}

+				queuedLoggingEvents.push(loggingEvent);

+				var actualBatchSize = this.getLayout().allowBatching() ? batchSize : 1;

+

+				if (queuedLoggingEvents.length >= actualBatchSize) {

+					var currentLoggingEvent;

+					var batchedLoggingEvents = [];

+					while ((currentLoggingEvent = queuedLoggingEvents.shift())) {

+						batchedLoggingEvents.push(currentLoggingEvent);

+					}

+					// Queue this batch of log entries

+					queuedRequests.push(batchedLoggingEvents);

+

+					// If using a timer, the queue of requests will be processed by the

+					// timer function, so nothing needs to be done here.

+					if (!timed && (!waitForResponse || (waitForResponse && !sending))) {

+						sendAll();

+					}

+				}

+			}

+		};

+

+		function init() {

+			initialized = true;

+			// Add unload event to send outstanding messages

+			if (sendAllOnUnload) {

+				var oldBeforeUnload = window.onbeforeunload;

+				window.onbeforeunload = function() {

+					if (oldBeforeUnload) {

+						oldBeforeUnload();

+					}

+					if (sendAllRemaining()) {

+						return "Sending log messages";

+					}

+				};

+			}

+			// Start timer

+			if (timed) {

+				scheduleSending();

+			}

+		}

+	}

+

+	AjaxAppender.prototype = new Appender();

+

+	AjaxAppender.prototype.defaults = {

+		waitForResponse: false,

+		timed: false,

+		timerInterval: 1000,

+		batchSize: 1,

+		sendAllOnUnload: false,

+		requestSuccessCallback: null,

+		failCallback: null,

+		postVarName: "data",

+		contentType: "application/x-www-form-urlencoded"

+	};

+

+	AjaxAppender.prototype.layout = new HttpPostDataLayout();

+

+	AjaxAppender.prototype.toString = function() {

+		return "AjaxAppender";

+	};

+

+	log4javascript.AjaxAppender = AjaxAppender;

+	/* ---------------------------------------------------------------------- */

+	// PopUpAppender and InPageAppender related

+

+	function setCookie(name, value, days, path) {

+	    var expires;

+	    path = path ? "; path=" + path : "";

+		if (days) {

+			var date = new Date();

+			date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));

+			expires = "; expires=" + date.toGMTString();

+		} else {

+		    expires = "";

+	    }

+		document.cookie = escape(name) + "=" + escape(value) + expires + path;

+	}

+

+	function getCookie(name) {

+		var nameEquals = escape(name) + "=";

+		var ca = document.cookie.split(";");

+		for (var i = 0, len = ca.length; i < len; i++) {

+			var c = ca[i];

+			while (c.charAt(0) === " ") {

+			    c = c.substring(1, c.length);

+			}

+			if (c.indexOf(nameEquals) === 0) {

+			    return unescape(c.substring(nameEquals.length, c.length));

+	        }

+		}

+		return null;

+	}

+

+	// Gets the base URL of the location of the log4javascript script.

+	// This is far from infallible.

+	function getBaseUrl() {

+		var scripts = document.getElementsByTagName("script");

+		for (var i = 0, len = scripts.length; i < len; ++i) {

+			if (scripts[i].src.indexOf("log4javascript") != -1) {

+				var lastSlash = scripts[i].src.lastIndexOf("/");

+				return (lastSlash == -1) ? "" : scripts[i].src.substr(0, lastSlash + 1);

+			}

+		}

+        return null;

+    }

+

+	function isLoaded(win) {

+		try {

+			return bool(win.loaded);

+		} catch (ex) {

+			return false;

+		}

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// ConsoleAppender (prototype for PopUpAppender and InPageAppender)

+

+	var ConsoleAppender;

+

+	// Create an anonymous function to protect base console methods

+	(function() {

+		var getConsoleHtmlLines = function() {

+			return [

+'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',

+'<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">',

+'	<head>',

+'		<title>log4javascript</title>',

+'		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',

+'		<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->',

+'		<meta http-equiv="X-UA-Compatible" content="IE=7" />',

+'		<script type="text/javascript">var isIe = false, isIePre7 = false;</script>',

+'		<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->',

+'		<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->',

+'		<script type="text/javascript">',

+'			//<![CDATA[',

+'			var loggingEnabled = true;',

+'			var logQueuedEventsTimer = null;',

+'			var logEntries = [];',

+'			var logEntriesAndSeparators = [];',

+'			var logItems = [];',

+'			var renderDelay = 100;',

+'			var unrenderedLogItemsExist = false;',

+'			var rootGroup, currentGroup = null;',

+'			var loaded = false;',

+'			var currentLogItem = null;',

+'			var logMainContainer;',

+'',

+'			function copyProperties(obj, props) {',

+'				for (var i in props) {',

+'					obj[i] = props[i];',

+'				}',

+'			}',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItem() {',

+'			}',

+'',

+'			LogItem.prototype = {',

+'				mainContainer: null,',

+'				wrappedContainer: null,',

+'				unwrappedContainer: null,',

+'				group: null,',

+'',

+'				appendToLog: function() {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].appendToLog();',

+'					}',

+'					this.group.update();',

+'				},',

+'',

+'				doRemove: function(doUpdate, removeFromGroup) {',

+'					if (this.rendered) {',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].remove();',

+'						}',

+'						this.unwrappedElementContainer = null;',

+'						this.wrappedElementContainer = null;',

+'						this.mainElementContainer = null;',

+'					}',

+'					if (this.group && removeFromGroup) {',

+'						this.group.removeChild(this, doUpdate);',

+'					}',

+'					if (this === currentLogItem) {',

+'						currentLogItem = null;',

+'					}',

+'				},',

+'',

+'				remove: function(doUpdate, removeFromGroup) {',

+'					this.doRemove(doUpdate, removeFromGroup);',

+'				},',

+'',

+'				render: function() {},',

+'',

+'				accept: function(visitor) {',

+'					visitor.visit(this);',

+'				},',

+'',

+'				getUnwrappedDomContainer: function() {',

+'					return this.group.unwrappedElementContainer.contentDiv;',

+'				},',

+'',

+'				getWrappedDomContainer: function() {',

+'					return this.group.wrappedElementContainer.contentDiv;',

+'				},',

+'',

+'				getMainDomContainer: function() {',

+'					return this.group.mainElementContainer.contentDiv;',

+'				}',

+'			};',

+'',

+'			LogItem.serializedItemKeys = {LOG_ENTRY: 0, GROUP_START: 1, GROUP_END: 2};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItemContainerElement() {',

+'			}',

+'',

+'			LogItemContainerElement.prototype = {',

+'				appendToLog: function() {',

+'					var insertBeforeFirst = (newestAtTop && this.containerDomNode.hasChildNodes());',

+'					if (insertBeforeFirst) {',

+'						this.containerDomNode.insertBefore(this.mainDiv, this.containerDomNode.firstChild);',

+'					} else {',

+'						this.containerDomNode.appendChild(this.mainDiv);',

+'					}',

+'				}',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function SeparatorElementContainer(containerDomNode) {',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.className = "separator";',

+'				this.mainDiv.innerHTML = "&nbsp;";',

+'			}',

+'',

+'			SeparatorElementContainer.prototype = new LogItemContainerElement();',

+'',

+'			SeparatorElementContainer.prototype.remove = function() {',

+'				this.mainDiv.parentNode.removeChild(this.mainDiv);',

+'				this.mainDiv = null;',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function Separator() {',

+'				this.rendered = false;',

+'			}',

+'',

+'			Separator.prototype = new LogItem();',

+'',

+'			copyProperties(Separator.prototype, {',

+'				render: function() {',

+'					var containerDomNode = this.group.contentDiv;',

+'					if (isIe) {',

+'						this.unwrappedElementContainer = new SeparatorElementContainer(this.getUnwrappedDomContainer());',

+'						this.wrappedElementContainer = new SeparatorElementContainer(this.getWrappedDomContainer());',

+'						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',

+'					} else {',

+'						this.mainElementContainer = new SeparatorElementContainer(this.getMainDomContainer());',

+'						this.elementContainers = [this.mainElementContainer];',

+'					}',

+'					this.content = this.formattedMessage;',

+'					this.rendered = true;',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function GroupElementContainer(group, containerDomNode, isRoot, isWrapped) {',

+'				this.group = group;',

+'				this.containerDomNode = containerDomNode;',

+'				this.isRoot = isRoot;',

+'				this.isWrapped = isWrapped;',

+'				this.expandable = false;',

+'',

+'				if (this.isRoot) {',

+'					if (isIe) {',

+'						this.contentDiv = logMainContainer.appendChild(document.createElement("div"));',

+'						this.contentDiv.id = this.isWrapped ? "log_wrapped" : "log_unwrapped";',

+'					} else {',

+'						this.contentDiv = logMainContainer;',

+'					}',

+'				} else {',

+'					var groupElementContainer = this;',

+'					',

+'					this.mainDiv = document.createElement("div");',

+'					this.mainDiv.className = "group";',

+'',

+'					this.headingDiv = this.mainDiv.appendChild(document.createElement("div"));',

+'					this.headingDiv.className = "groupheading";',

+'',

+'					this.expander = this.headingDiv.appendChild(document.createElement("span"));',

+'					this.expander.className = "expander unselectable greyedout";',

+'					this.expander.unselectable = true;',

+'					var expanderText = this.group.expanded ? "-" : "+";',

+'					this.expanderTextNode = this.expander.appendChild(document.createTextNode(expanderText));',

+'					',

+'					this.headingDiv.appendChild(document.createTextNode(" " + this.group.name));',

+'',

+'					this.contentDiv = this.mainDiv.appendChild(document.createElement("div"));',

+'					var contentCssClass = this.group.expanded ? "expanded" : "collapsed";',

+'					this.contentDiv.className = "groupcontent " + contentCssClass;',

+'',

+'					this.expander.onclick = function() {',

+'						if (groupElementContainer.group.expandable) {',

+'							groupElementContainer.group.toggleExpanded();',

+'						}',

+'					};',

+'				}',

+'			}',

+'',

+'			GroupElementContainer.prototype = new LogItemContainerElement();',

+'',

+'			copyProperties(GroupElementContainer.prototype, {',

+'				toggleExpanded: function() {',

+'					if (!this.isRoot) {',

+'						var oldCssClass, newCssClass, expanderText;',

+'						if (this.group.expanded) {',

+'							newCssClass = "expanded";',

+'							oldCssClass = "collapsed";',

+'							expanderText = "-";',

+'						} else {',

+'							newCssClass = "collapsed";',

+'							oldCssClass = "expanded";',

+'							expanderText = "+";',

+'						}',

+'						replaceClass(this.contentDiv, newCssClass, oldCssClass);',

+'						this.expanderTextNode.nodeValue = expanderText;',

+'					}',

+'				},',

+'',

+'				remove: function() {',

+'					if (!this.isRoot) {',

+'						this.headingDiv = null;',

+'						this.expander.onclick = null;',

+'						this.expander = null;',

+'						this.expanderTextNode = null;',

+'						this.contentDiv = null;',

+'						this.containerDomNode = null;',

+'						this.mainDiv.parentNode.removeChild(this.mainDiv);',

+'						this.mainDiv = null;',

+'					}',

+'				},',

+'',

+'				reverseChildren: function() {',

+'					// Invert the order of the log entries',

+'					var node = null;',

+'',

+'					// Remove all the log container nodes',

+'					var childDomNodes = [];',

+'					while ((node = this.contentDiv.firstChild)) {',

+'						this.contentDiv.removeChild(node);',

+'						childDomNodes.push(node);',

+'					}',

+'',

+'					// Put them all back in reverse order',

+'					while ((node = childDomNodes.pop())) {',

+'						this.contentDiv.appendChild(node);',

+'					}',

+'				},',

+'',

+'				update: function() {',

+'					if (!this.isRoot) {',

+'						if (this.group.expandable) {',

+'							removeClass(this.expander, "greyedout");',

+'						} else {',

+'							addClass(this.expander, "greyedout");',

+'						}',

+'					}',

+'				},',

+'',

+'				clear: function() {',

+'					if (this.isRoot) {',

+'						this.contentDiv.innerHTML = "";',

+'					}',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function Group(name, isRoot, initiallyExpanded) {',

+'				this.name = name;',

+'				this.group = null;',

+'				this.isRoot = isRoot;',

+'				this.initiallyExpanded = initiallyExpanded;',

+'				this.elementContainers = [];',

+'				this.children = [];',

+'				this.expanded = initiallyExpanded;',

+'				this.rendered = false;',

+'				this.expandable = false;',

+'			}',

+'',

+'			Group.prototype = new LogItem();',

+'',

+'			copyProperties(Group.prototype, {',

+'				addChild: function(logItem) {',

+'					this.children.push(logItem);',

+'					logItem.group = this;',

+'				},',

+'',

+'				render: function() {',

+'					if (isIe) {',

+'						var unwrappedDomContainer, wrappedDomContainer;',

+'						if (this.isRoot) {',

+'							unwrappedDomContainer = logMainContainer;',

+'							wrappedDomContainer = logMainContainer;',

+'						} else {',

+'							unwrappedDomContainer = this.getUnwrappedDomContainer();',

+'							wrappedDomContainer = this.getWrappedDomContainer();',

+'						}',

+'						this.unwrappedElementContainer = new GroupElementContainer(this, unwrappedDomContainer, this.isRoot, false);',

+'						this.wrappedElementContainer = new GroupElementContainer(this, wrappedDomContainer, this.isRoot, true);',

+'						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',

+'					} else {',

+'						var mainDomContainer = this.isRoot ? logMainContainer : this.getMainDomContainer();',

+'						this.mainElementContainer = new GroupElementContainer(this, mainDomContainer, this.isRoot, false);',

+'						this.elementContainers = [this.mainElementContainer];',

+'					}',

+'					this.rendered = true;',

+'				},',

+'',

+'				toggleExpanded: function() {',

+'					this.expanded = !this.expanded;',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].toggleExpanded();',

+'					}',

+'				},',

+'',

+'				expand: function() {',

+'					if (!this.expanded) {',

+'						this.toggleExpanded();',

+'					}',

+'				},',

+'',

+'				accept: function(visitor) {',

+'					visitor.visitGroup(this);',

+'				},',

+'',

+'				reverseChildren: function() {',

+'					if (this.rendered) {',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].reverseChildren();',

+'						}',

+'					}',

+'				},',

+'',

+'				update: function() {',

+'					var previouslyExpandable = this.expandable;',

+'					this.expandable = (this.children.length !== 0);',

+'					if (this.expandable !== previouslyExpandable) {',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].update();',

+'						}',

+'					}',

+'				},',

+'',

+'				flatten: function() {',

+'					var visitor = new GroupFlattener();',

+'					this.accept(visitor);',

+'					return visitor.logEntriesAndSeparators;',

+'				},',

+'',

+'				removeChild: function(child, doUpdate) {',

+'					array_remove(this.children, child);',

+'					child.group = null;',

+'					if (doUpdate) {',

+'						this.update();',

+'					}',

+'				},',

+'',

+'				remove: function(doUpdate, removeFromGroup) {',

+'					for (var i = 0, len = this.children.length; i < len; i++) {',

+'						this.children[i].remove(false, false);',

+'					}',

+'					this.children = [];',

+'					this.update();',

+'					if (this === currentGroup) {',

+'						currentGroup = this.group;',

+'					}',

+'					this.doRemove(doUpdate, removeFromGroup);',

+'				},',

+'',

+'				serialize: function(items) {',

+'					items.push([LogItem.serializedItemKeys.GROUP_START, this.name]);',

+'					for (var i = 0, len = this.children.length; i < len; i++) {',

+'						this.children[i].serialize(items);',

+'					}',

+'					if (this !== currentGroup) {',

+'						items.push([LogItem.serializedItemKeys.GROUP_END]);',

+'					}',

+'				},',

+'',

+'				clear: function() {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].clear();',

+'					}',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryElementContainer() {',

+'			}',

+'',

+'			LogEntryElementContainer.prototype = new LogItemContainerElement();',

+'',

+'			copyProperties(LogEntryElementContainer.prototype, {',

+'				remove: function() {',

+'					this.doRemove();',

+'				},',

+'',

+'				doRemove: function() {',

+'					this.mainDiv.parentNode.removeChild(this.mainDiv);',

+'					this.mainDiv = null;',

+'					this.contentElement = null;',

+'					this.containerDomNode = null;',

+'				},',

+'',

+'				setContent: function(content, wrappedContent) {',

+'					if (content === this.formattedMessage) {',

+'						this.contentElement.innerHTML = "";',

+'						this.contentElement.appendChild(document.createTextNode(this.formattedMessage));',

+'					} else {',

+'						this.contentElement.innerHTML = content;',

+'					}',

+'				},',

+'',

+'				setSearchMatch: function(isMatch) {',

+'					var oldCssClass = isMatch ? "searchnonmatch" : "searchmatch";',

+'					var newCssClass = isMatch ? "searchmatch" : "searchnonmatch";',

+'					replaceClass(this.mainDiv, newCssClass, oldCssClass);',

+'				},',

+'',

+'				clearSearch: function() {',

+'					removeClass(this.mainDiv, "searchmatch");',

+'					removeClass(this.mainDiv, "searchnonmatch");',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryWrappedElementContainer(logEntry, containerDomNode) {',

+'				this.logEntry = logEntry;',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));',

+'				this.mainDiv.className = "logentry wrapped " + this.logEntry.level;',

+'				this.contentElement = this.mainDiv;',

+'			}',

+'',

+'			LogEntryWrappedElementContainer.prototype = new LogEntryElementContainer();',

+'',

+'			LogEntryWrappedElementContainer.prototype.setContent = function(content, wrappedContent) {',

+'				if (content === this.formattedMessage) {',

+'					this.contentElement.innerHTML = "";',

+'					this.contentElement.appendChild(document.createTextNode(this.formattedMessage));',

+'				} else {',

+'					this.contentElement.innerHTML = wrappedContent;',

+'				}',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryUnwrappedElementContainer(logEntry, containerDomNode) {',

+'				this.logEntry = logEntry;',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.className = "logentry unwrapped " + this.logEntry.level;',

+'				this.pre = this.mainDiv.appendChild(document.createElement("pre"));',

+'				this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));',

+'				this.pre.className = "unwrapped";',

+'				this.contentElement = this.pre;',

+'			}',

+'',

+'			LogEntryUnwrappedElementContainer.prototype = new LogEntryElementContainer();',

+'',

+'			LogEntryUnwrappedElementContainer.prototype.remove = function() {',

+'				this.doRemove();',

+'				this.pre = null;',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryMainElementContainer(logEntry, containerDomNode) {',

+'				this.logEntry = logEntry;',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.className = "logentry nonielogentry " + this.logEntry.level;',

+'				this.contentElement = this.mainDiv.appendChild(document.createElement("span"));',

+'				this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));',

+'			}',

+'',

+'			LogEntryMainElementContainer.prototype = new LogEntryElementContainer();',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntry(level, formattedMessage) {',

+'				this.level = level;',

+'				this.formattedMessage = formattedMessage;',

+'				this.rendered = false;',

+'			}',

+'',

+'			LogEntry.prototype = new LogItem();',

+'',

+'			copyProperties(LogEntry.prototype, {',

+'				render: function() {',

+'					var logEntry = this;',

+'					var containerDomNode = this.group.contentDiv;',

+'',

+'					// Support for the CSS attribute white-space in IE for Windows is',

+'					// non-existent pre version 6 and slightly odd in 6, so instead',

+'					// use two different HTML elements',

+'					if (isIe) {',

+'						this.formattedMessage = this.formattedMessage.replace(/\\r\\n/g, "\\r"); // Workaround for IE\'s treatment of white space',

+'						this.unwrappedElementContainer = new LogEntryUnwrappedElementContainer(this, this.getUnwrappedDomContainer());',

+'						this.wrappedElementContainer = new LogEntryWrappedElementContainer(this, this.getWrappedDomContainer());',

+'						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',

+'					} else {',

+'						this.mainElementContainer = new LogEntryMainElementContainer(this, this.getMainDomContainer());',

+'						this.elementContainers = [this.mainElementContainer];',

+'					}',

+'					this.content = this.formattedMessage;',

+'					this.rendered = true;',

+'				},',

+'',

+'				setContent: function(content, wrappedContent) {',

+'					if (content != this.content) {',

+'						if (isIe && (content !== this.formattedMessage)) {',

+'							content = content.replace(/\\r\\n/g, "\\r"); // Workaround for IE\'s treatment of white space',

+'						}',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].setContent(content, wrappedContent);',

+'						}',

+'						this.content = content;',

+'					}',

+'				},',

+'',

+'				getSearchMatches: function() {',

+'					var matches = [];',

+'					var i, len;',

+'					if (isIe) {',

+'						var unwrappedEls = getElementsByClass(this.unwrappedElementContainer.mainDiv, "searchterm", "span");',

+'						var wrappedEls = getElementsByClass(this.wrappedElementContainer.mainDiv, "searchterm", "span");',

+'						for (i = 0, len = unwrappedEls.length; i < len; i++) {',

+'							matches[i] = new Match(this.level, null, unwrappedEls[i], wrappedEls[i]);',

+'						}',

+'					} else {',

+'						var els = getElementsByClass(this.mainElementContainer.mainDiv, "searchterm", "span");',

+'						for (i = 0, len = els.length; i < len; i++) {',

+'							matches[i] = new Match(this.level, els[i]);',

+'						}',

+'					}',

+'					return matches;',

+'				},',

+'',

+'				setSearchMatch: function(isMatch) {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].setSearchMatch(isMatch);',

+'					}',

+'				},',

+'',

+'				clearSearch: function() {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].clearSearch();',

+'					}',

+'				},',

+'',

+'				accept: function(visitor) {',

+'					visitor.visitLogEntry(this);',

+'				},',

+'',

+'				serialize: function(items) {',

+'					items.push([LogItem.serializedItemKeys.LOG_ENTRY, this.level, this.formattedMessage]);',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItemVisitor() {',

+'			}',

+'',

+'			LogItemVisitor.prototype = {',

+'				visit: function(logItem) {',

+'				},',

+'',

+'				visitParent: function(logItem) {',

+'					if (logItem.group) {',

+'						logItem.group.accept(this);',

+'					}',

+'				},',

+'',

+'				visitChildren: function(logItem) {',

+'					for (var i = 0, len = logItem.children.length; i < len; i++) {',

+'						logItem.children[i].accept(this);',

+'					}',

+'				},',

+'',

+'				visitLogEntry: function(logEntry) {',

+'					this.visit(logEntry);',

+'				},',

+'',

+'				visitSeparator: function(separator) {',

+'					this.visit(separator);',

+'				},',

+'',

+'				visitGroup: function(group) {',

+'					this.visit(group);',

+'				}',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function GroupFlattener() {',

+'				this.logEntriesAndSeparators = [];',

+'			}',

+'',

+'			GroupFlattener.prototype = new LogItemVisitor();',

+'',

+'			GroupFlattener.prototype.visitGroup = function(group) {',

+'				this.visitChildren(group);',

+'			};',

+'',

+'			GroupFlattener.prototype.visitLogEntry = function(logEntry) {',

+'				this.logEntriesAndSeparators.push(logEntry);',

+'			};',

+'',

+'			GroupFlattener.prototype.visitSeparator = function(separator) {',

+'				this.logEntriesAndSeparators.push(separator);',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			window.onload = function() {',

+'				// Sort out document.domain',

+'				if (location.search) {',

+'					var queryBits = unescape(location.search).substr(1).split("&"), nameValueBits;',

+'					for (var i = 0, len = queryBits.length; i < len; i++) {',

+'						nameValueBits = queryBits[i].split("=");',

+'						if (nameValueBits[0] == "log4javascript_domain") {',

+'							document.domain = nameValueBits[1];',

+'							break;',

+'						}',

+'					}',

+'				}',

+'',

+'				// Create DOM objects',

+'				logMainContainer = $("log");',

+'				if (isIePre7) {',

+'					addClass(logMainContainer, "oldIe");',

+'				}',

+'',

+'				rootGroup = new Group("root", true);',

+'				rootGroup.render();',

+'				currentGroup = rootGroup;',

+'				',

+'				setCommandInputWidth();',

+'				setLogContainerHeight();',

+'				toggleLoggingEnabled();',

+'				toggleSearchEnabled();',

+'				toggleSearchFilter();',

+'				toggleSearchHighlight();',

+'				applyFilters();',

+'				checkAllLevels();',

+'				toggleWrap();',

+'				toggleNewestAtTop();',

+'				toggleScrollToLatest();',

+'				renderQueuedLogItems();',

+'				loaded = true;',

+'				$("command").value = "";',

+'				$("command").autocomplete = "off";',

+'				$("command").onkeydown = function(evt) {',

+'					evt = getEvent(evt);',

+'					if (evt.keyCode == 10 || evt.keyCode == 13) { // Return/Enter',

+'						evalCommandLine();',

+'						stopPropagation(evt);',

+'					} else if (evt.keyCode == 27) { // Escape',

+'						this.value = "";',

+'						this.focus();',

+'					} else if (evt.keyCode == 38 && commandHistory.length > 0) { // Up',

+'						currentCommandIndex = Math.max(0, currentCommandIndex - 1);',

+'						this.value = commandHistory[currentCommandIndex];',

+'						moveCaretToEnd(this);',

+'					} else if (evt.keyCode == 40 && commandHistory.length > 0) { // Down',

+'						currentCommandIndex = Math.min(commandHistory.length - 1, currentCommandIndex + 1);',

+'						this.value = commandHistory[currentCommandIndex];',

+'						moveCaretToEnd(this);',

+'					}',

+'				};',

+'',

+'				// Prevent the keypress moving the caret in Firefox',

+'				$("command").onkeypress = function(evt) {',

+'					evt = getEvent(evt);',

+'					if (evt.keyCode == 38 && commandHistory.length > 0 && evt.preventDefault) { // Up',

+'						evt.preventDefault();',

+'					}',

+'				};',

+'',

+'				// Prevent the keyup event blurring the input in Opera',

+'				$("command").onkeyup = function(evt) {',

+'					evt = getEvent(evt);',

+'					if (evt.keyCode == 27 && evt.preventDefault) { // Up',

+'						evt.preventDefault();',

+'						this.focus();',

+'					}',

+'				};',

+'',

+'				// Add document keyboard shortcuts',

+'				document.onkeydown = function keyEventHandler(evt) {',

+'					evt = getEvent(evt);',

+'					switch (evt.keyCode) {',

+'						case 69: // Ctrl + shift + E: re-execute last command',

+'							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',

+'								evalLastCommand();',

+'								cancelKeyEvent(evt);',

+'								return false;',

+'							}',

+'							break;',

+'						case 75: // Ctrl + shift + K: focus search',

+'							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',

+'								focusSearch();',

+'								cancelKeyEvent(evt);',

+'								return false;',

+'							}',

+'							break;',

+'						case 40: // Ctrl + shift + down arrow: focus command line',

+'						case 76: // Ctrl + shift + L: focus command line',

+'							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',

+'								focusCommandLine();',

+'								cancelKeyEvent(evt);',

+'								return false;',

+'							}',

+'							break;',

+'					}',

+'				};',

+'',

+'				// Workaround to make sure log div starts at the correct size',

+'				setTimeout(setLogContainerHeight, 20);',

+'',

+'				setShowCommandLine(showCommandLine);',

+'				doSearch();',

+'			};',

+'',

+'			window.onunload = function() {',

+'				if (mainWindowExists()) {',

+'					appender.unload();',

+'				}',

+'				appender = null;',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function toggleLoggingEnabled() {',

+'				setLoggingEnabled($("enableLogging").checked);',

+'			}',

+'',

+'			function setLoggingEnabled(enable) {',

+'				loggingEnabled = enable;',

+'			}',

+'',

+'			var appender = null;',

+'',

+'			function setAppender(appenderParam) {',

+'				appender = appenderParam;',

+'			}',

+'',

+'			function setShowCloseButton(showCloseButton) {',

+'				$("closeButton").style.display = showCloseButton ? "inline" : "none";',

+'			}',

+'',

+'			function setShowHideButton(showHideButton) {',

+'				$("hideButton").style.display = showHideButton ? "inline" : "none";',

+'			}',

+'',

+'			var newestAtTop = false;',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItemContentReverser() {',

+'			}',

+'			',

+'			LogItemContentReverser.prototype = new LogItemVisitor();',

+'			',

+'			LogItemContentReverser.prototype.visitGroup = function(group) {',

+'				group.reverseChildren();',

+'				this.visitChildren(group);',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function setNewestAtTop(isNewestAtTop) {',

+'				var oldNewestAtTop = newestAtTop;',

+'				var i, iLen, j, jLen;',

+'				newestAtTop = Boolean(isNewestAtTop);',

+'				if (oldNewestAtTop != newestAtTop) {',

+'					var visitor = new LogItemContentReverser();',

+'					rootGroup.accept(visitor);',

+'',

+'					// Reassemble the matches array',

+'					if (currentSearch) {',

+'						var currentMatch = currentSearch.matches[currentMatchIndex];',

+'						var matchIndex = 0;',

+'						var matches = [];',

+'						var actOnLogEntry = function(logEntry) {',

+'							var logEntryMatches = logEntry.getSearchMatches();',

+'							for (j = 0, jLen = logEntryMatches.length; j < jLen; j++) {',

+'								matches[matchIndex] = logEntryMatches[j];',

+'								if (currentMatch && logEntryMatches[j].equals(currentMatch)) {',

+'									currentMatchIndex = matchIndex;',

+'								}',

+'								matchIndex++;',

+'							}',

+'						};',

+'						if (newestAtTop) {',

+'							for (i = logEntries.length - 1; i >= 0; i--) {',

+'								actOnLogEntry(logEntries[i]);',

+'							}',

+'						} else {',

+'							for (i = 0, iLen = logEntries.length; i < iLen; i++) {',

+'								actOnLogEntry(logEntries[i]);',

+'							}',

+'						}',

+'						currentSearch.matches = matches;',

+'						if (currentMatch) {',

+'							currentMatch.setCurrent();',

+'						}',

+'					} else if (scrollToLatest) {',

+'						doScrollToLatest();',

+'					}',

+'				}',

+'				$("newestAtTop").checked = isNewestAtTop;',

+'			}',

+'',

+'			function toggleNewestAtTop() {',

+'				var isNewestAtTop = $("newestAtTop").checked;',

+'				setNewestAtTop(isNewestAtTop);',

+'			}',

+'',

+'			var scrollToLatest = true;',

+'',

+'			function setScrollToLatest(isScrollToLatest) {',

+'				scrollToLatest = isScrollToLatest;',

+'				if (scrollToLatest) {',

+'					doScrollToLatest();',

+'				}',

+'				$("scrollToLatest").checked = isScrollToLatest;',

+'			}',

+'',

+'			function toggleScrollToLatest() {',

+'				var isScrollToLatest = $("scrollToLatest").checked;',

+'				setScrollToLatest(isScrollToLatest);',

+'			}',

+'',

+'			function doScrollToLatest() {',

+'				var l = logMainContainer;',

+'				if (typeof l.scrollTop != "undefined") {',

+'					if (newestAtTop) {',

+'						l.scrollTop = 0;',

+'					} else {',

+'						var latestLogEntry = l.lastChild;',

+'						if (latestLogEntry) {',

+'							l.scrollTop = l.scrollHeight;',

+'						}',

+'					}',

+'				}',

+'			}',

+'',

+'			var closeIfOpenerCloses = true;',

+'',

+'			function setCloseIfOpenerCloses(isCloseIfOpenerCloses) {',

+'				closeIfOpenerCloses = isCloseIfOpenerCloses;',

+'			}',

+'',

+'			var maxMessages = null;',

+'',

+'			function setMaxMessages(max) {',

+'				maxMessages = max;',

+'				pruneLogEntries();',

+'			}',

+'',

+'			var showCommandLine = false;',

+'',

+'			function setShowCommandLine(isShowCommandLine) {',

+'				showCommandLine = isShowCommandLine;',

+'				if (loaded) {',

+'					$("commandLine").style.display = showCommandLine ? "block" : "none";',

+'					setCommandInputWidth();',

+'					setLogContainerHeight();',

+'				}',

+'			}',

+'',

+'			function focusCommandLine() {',

+'				if (loaded) {',

+'					$("command").focus();',

+'				}',

+'			}',

+'',

+'			function focusSearch() {',

+'				if (loaded) {',

+'					$("searchBox").focus();',

+'				}',

+'			}',

+'',

+'			function getLogItems() {',

+'				var items = [];',

+'				for (var i = 0, len = logItems.length; i < len; i++) {',

+'					logItems[i].serialize(items);',

+'				}',

+'				return items;',

+'			}',

+'',

+'			function setLogItems(items) {',

+'				var loggingReallyEnabled = loggingEnabled;',

+'				// Temporarily turn logging on',

+'				loggingEnabled = true;',

+'				for (var i = 0, len = items.length; i < len; i++) {',

+'					switch (items[i][0]) {',

+'						case LogItem.serializedItemKeys.LOG_ENTRY:',

+'							log(items[i][1], items[i][2]);',

+'							break;',

+'						case LogItem.serializedItemKeys.GROUP_START:',

+'							group(items[i][1]);',

+'							break;',

+'						case LogItem.serializedItemKeys.GROUP_END:',

+'							groupEnd();',

+'							break;',

+'					}',

+'				}',

+'				loggingEnabled = loggingReallyEnabled;',

+'			}',

+'',

+'			function log(logLevel, formattedMessage) {',

+'				if (loggingEnabled) {',

+'					var logEntry = new LogEntry(logLevel, formattedMessage);',

+'					logEntries.push(logEntry);',

+'					logEntriesAndSeparators.push(logEntry);',

+'					logItems.push(logEntry);',

+'					currentGroup.addChild(logEntry);',

+'					if (loaded) {',

+'						if (logQueuedEventsTimer !== null) {',

+'							clearTimeout(logQueuedEventsTimer);',

+'						}',

+'						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);',

+'						unrenderedLogItemsExist = true;',

+'					}',

+'				}',

+'			}',

+'',

+'			function renderQueuedLogItems() {',

+'				logQueuedEventsTimer = null;',

+'				var pruned = pruneLogEntries();',

+'',

+'				// Render any unrendered log entries and apply the current search to them',

+'				var initiallyHasMatches = currentSearch ? currentSearch.hasMatches() : false;',

+'				for (var i = 0, len = logItems.length; i < len; i++) {',

+'					if (!logItems[i].rendered) {',

+'						logItems[i].render();',

+'						logItems[i].appendToLog();',

+'						if (currentSearch && (logItems[i] instanceof LogEntry)) {',

+'							currentSearch.applyTo(logItems[i]);',

+'						}',

+'					}',

+'				}',

+'				if (currentSearch) {',

+'					if (pruned) {',

+'						if (currentSearch.hasVisibleMatches()) {',

+'							if (currentMatchIndex === null) {',

+'								setCurrentMatchIndex(0);',

+'							}',

+'							displayMatches();',

+'						} else {',

+'							displayNoMatches();',

+'						}',

+'					} else if (!initiallyHasMatches && currentSearch.hasVisibleMatches()) {',

+'						setCurrentMatchIndex(0);',

+'						displayMatches();',

+'					}',

+'				}',

+'				if (scrollToLatest) {',

+'					doScrollToLatest();',

+'				}',

+'				unrenderedLogItemsExist = false;',

+'			}',

+'',

+'			function pruneLogEntries() {',

+'				if ((maxMessages !== null) && (logEntriesAndSeparators.length > maxMessages)) {',

+'					var numberToDelete = logEntriesAndSeparators.length - maxMessages;',

+'					var prunedLogEntries = logEntriesAndSeparators.slice(0, numberToDelete);',

+'					if (currentSearch) {',

+'						currentSearch.removeMatches(prunedLogEntries);',

+'					}',

+'					var group;',

+'					for (var i = 0; i < numberToDelete; i++) {',

+'						group = logEntriesAndSeparators[i].group;',

+'						array_remove(logItems, logEntriesAndSeparators[i]);',

+'						array_remove(logEntries, logEntriesAndSeparators[i]);',

+'						logEntriesAndSeparators[i].remove(true, true);',

+'						if (group.children.length === 0 && group !== currentGroup && group !== rootGroup) {',

+'							array_remove(logItems, group);',

+'							group.remove(true, true);',

+'						}',

+'					}',

+'					logEntriesAndSeparators = array_removeFromStart(logEntriesAndSeparators, numberToDelete);',

+'					return true;',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function group(name, startExpanded) {',

+'				if (loggingEnabled) {',

+'					initiallyExpanded = (typeof startExpanded === "undefined") ? true : Boolean(startExpanded);',

+'					var newGroup = new Group(name, false, initiallyExpanded);',

+'					currentGroup.addChild(newGroup);',

+'					currentGroup = newGroup;',

+'					logItems.push(newGroup);',

+'					if (loaded) {',

+'						if (logQueuedEventsTimer !== null) {',

+'							clearTimeout(logQueuedEventsTimer);',

+'						}',

+'						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);',

+'						unrenderedLogItemsExist = true;',

+'					}',

+'				}',

+'			}',

+'',

+'			function groupEnd() {',

+'				currentGroup = (currentGroup === rootGroup) ? rootGroup : currentGroup.group;',

+'			}',

+'',

+'			function mainPageReloaded() {',

+'				currentGroup = rootGroup;',

+'				var separator = new Separator();',

+'				logEntriesAndSeparators.push(separator);',

+'				logItems.push(separator);',

+'				currentGroup.addChild(separator);',

+'			}',

+'',

+'			function closeWindow() {',

+'				if (appender && mainWindowExists()) {',

+'					appender.close(true);',

+'				} else {',

+'					window.close();',

+'				}',

+'			}',

+'',

+'			function hide() {',

+'				if (appender && mainWindowExists()) {',

+'					appender.hide();',

+'				}',

+'			}',

+'',

+'			var mainWindow = window;',

+'			var windowId = "log4javascriptConsoleWindow_" + new Date().getTime() + "_" + ("" + Math.random()).substr(2);',

+'',

+'			function setMainWindow(win) {',

+'				mainWindow = win;',

+'				mainWindow[windowId] = window;',

+'				// If this is a pop-up, poll the opener to see if it\'s closed',

+'				if (opener && closeIfOpenerCloses) {',

+'					pollOpener();',

+'				}',

+'			}',

+'',

+'			function pollOpener() {',

+'				if (closeIfOpenerCloses) {',

+'					if (mainWindowExists()) {',

+'						setTimeout(pollOpener, 500);',

+'					} else {',

+'						closeWindow();',

+'					}',

+'				}',

+'			}',

+'',

+'			function mainWindowExists() {',

+'				try {',

+'					return (mainWindow && !mainWindow.closed &&',

+'						mainWindow[windowId] == window);',

+'				} catch (ex) {}',

+'				return false;',

+'			}',

+'',

+'			var logLevels = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"];',

+'',

+'			function getCheckBox(logLevel) {',

+'				return $("switch_" + logLevel);',

+'			}',

+'',

+'			function getIeWrappedLogContainer() {',

+'				return $("log_wrapped");',

+'			}',

+'',

+'			function getIeUnwrappedLogContainer() {',

+'				return $("log_unwrapped");',

+'			}',

+'',

+'			function applyFilters() {',

+'				for (var i = 0; i < logLevels.length; i++) {',

+'					if (getCheckBox(logLevels[i]).checked) {',

+'						addClass(logMainContainer, logLevels[i]);',

+'					} else {',

+'						removeClass(logMainContainer, logLevels[i]);',

+'					}',

+'				}',

+'				updateSearchFromFilters();',

+'			}',

+'',

+'			function toggleAllLevels() {',

+'				var turnOn = $("switch_ALL").checked;',

+'				for (var i = 0; i < logLevels.length; i++) {',

+'					getCheckBox(logLevels[i]).checked = turnOn;',

+'					if (turnOn) {',

+'						addClass(logMainContainer, logLevels[i]);',

+'					} else {',

+'						removeClass(logMainContainer, logLevels[i]);',

+'					}',

+'				}',

+'			}',

+'',

+'			function checkAllLevels() {',

+'				for (var i = 0; i < logLevels.length; i++) {',

+'					if (!getCheckBox(logLevels[i]).checked) {',

+'						getCheckBox("ALL").checked = false;',

+'						return;',

+'					}',

+'				}',

+'				getCheckBox("ALL").checked = true;',

+'			}',

+'',

+'			function clearLog() {',

+'				rootGroup.clear();',

+'				currentGroup = rootGroup;',

+'				logEntries = [];',

+'				logItems = [];',

+'				logEntriesAndSeparators = [];',

+' 				doSearch();',

+'			}',

+'',

+'			function toggleWrap() {',

+'				var enable = $("wrap").checked;',

+'				if (enable) {',

+'					addClass(logMainContainer, "wrap");',

+'				} else {',

+'					removeClass(logMainContainer, "wrap");',

+'				}',

+'				refreshCurrentMatch();',

+'			}',

+'',

+'			/* ------------------------------------------------------------------- */',

+'',

+'			// Search',

+'',

+'			var searchTimer = null;',

+'',

+'			function scheduleSearch() {',

+'				try {',

+'					clearTimeout(searchTimer);',

+'				} catch (ex) {',

+'					// Do nothing',

+'				}',

+'				searchTimer = setTimeout(doSearch, 500);',

+'			}',

+'',

+'			function Search(searchTerm, isRegex, searchRegex, isCaseSensitive) {',

+'				this.searchTerm = searchTerm;',

+'				this.isRegex = isRegex;',

+'				this.searchRegex = searchRegex;',

+'				this.isCaseSensitive = isCaseSensitive;',

+'				this.matches = [];',

+'			}',

+'',

+'			Search.prototype = {',

+'				hasMatches: function() {',

+'					return this.matches.length > 0;',

+'				},',

+'',

+'				hasVisibleMatches: function() {',

+'					if (this.hasMatches()) {',

+'						for (var i = 0; i < this.matches.length; i++) {',

+'							if (this.matches[i].isVisible()) {',

+'								return true;',

+'							}',

+'						}',

+'					}',

+'					return false;',

+'				},',

+'',

+'				match: function(logEntry) {',

+'					var entryText = String(logEntry.formattedMessage);',

+'					var matchesSearch = false;',

+'					if (this.isRegex) {',

+'						matchesSearch = this.searchRegex.test(entryText);',

+'					} else if (this.isCaseSensitive) {',

+'						matchesSearch = (entryText.indexOf(this.searchTerm) > -1);',

+'					} else {',

+'						matchesSearch = (entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1);',

+'					}',

+'					return matchesSearch;',

+'				},',

+'',

+'				getNextVisibleMatchIndex: function() {',

+'					for (var i = currentMatchIndex + 1; i < this.matches.length; i++) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					// Start again from the first match',

+'					for (i = 0; i <= currentMatchIndex; i++) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					return -1;',

+'				},',

+'',

+'				getPreviousVisibleMatchIndex: function() {',

+'					for (var i = currentMatchIndex - 1; i >= 0; i--) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					// Start again from the last match',

+'					for (var i = this.matches.length - 1; i >= currentMatchIndex; i--) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					return -1;',

+'				},',

+'',

+'				applyTo: function(logEntry) {',

+'					var doesMatch = this.match(logEntry);',

+'					if (doesMatch) {',

+'						logEntry.group.expand();',

+'						logEntry.setSearchMatch(true);',

+'						var logEntryContent;',

+'						var wrappedLogEntryContent;',

+'						var searchTermReplacementStartTag = "<span class=\\\"searchterm\\\">";',

+'						var searchTermReplacementEndTag = "<" + "/span>";',

+'						var preTagName = isIe ? "pre" : "span";',

+'						var preStartTag = "<" + preTagName + " class=\\\"pre\\\">";',

+'						var preEndTag = "<" + "/" + preTagName + ">";',

+'						var startIndex = 0;',

+'						var searchIndex, matchedText, textBeforeMatch;',

+'						if (this.isRegex) {',

+'							var flags = this.isCaseSensitive ? "g" : "gi";',

+'							var capturingRegex = new RegExp("(" + this.searchRegex.source + ")", flags);',

+'',

+'							// Replace the search term with temporary tokens for the start and end tags',

+'							var rnd = ("" + Math.random()).substr(2);',

+'							var startToken = "%%s" + rnd + "%%";',

+'							var endToken = "%%e" + rnd + "%%";',

+'							logEntryContent = logEntry.formattedMessage.replace(capturingRegex, startToken + "$1" + endToken);',

+'',

+'							// Escape the HTML to get rid of angle brackets',

+'							logEntryContent = escapeHtml(logEntryContent);',

+'',

+'							// Substitute the proper HTML back in for the search match',

+'							var result;',

+'							var searchString = logEntryContent;',

+'							logEntryContent = "";',

+'							wrappedLogEntryContent = "";',

+'							while ((searchIndex = searchString.indexOf(startToken, startIndex)) > -1) {',

+'								var endTokenIndex = searchString.indexOf(endToken, searchIndex);',

+'								matchedText = searchString.substring(searchIndex + startToken.length, endTokenIndex);',

+'								textBeforeMatch = searchString.substring(startIndex, searchIndex);',

+'								logEntryContent += preStartTag + textBeforeMatch + preEndTag;',

+'								logEntryContent += searchTermReplacementStartTag + preStartTag + matchedText +',

+'									preEndTag + searchTermReplacementEndTag;',

+'								if (isIe) {',

+'									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +',

+'										matchedText + searchTermReplacementEndTag;',

+'								}',

+'								startIndex = endTokenIndex + endToken.length;',

+'							}',

+'							logEntryContent += preStartTag + searchString.substr(startIndex) + preEndTag;',

+'							if (isIe) {',

+'								wrappedLogEntryContent += searchString.substr(startIndex);',

+'							}',

+'						} else {',

+'							logEntryContent = "";',

+'							wrappedLogEntryContent = "";',

+'							var searchTermReplacementLength = searchTermReplacementStartTag.length +',

+'								this.searchTerm.length + searchTermReplacementEndTag.length;',

+'							var searchTermLength = this.searchTerm.length;',

+'							var searchTermLowerCase = this.searchTerm.toLowerCase();',

+'							var logTextLowerCase = logEntry.formattedMessage.toLowerCase();',

+'							while ((searchIndex = logTextLowerCase.indexOf(searchTermLowerCase, startIndex)) > -1) {',

+'								matchedText = escapeHtml(logEntry.formattedMessage.substr(searchIndex, this.searchTerm.length));',

+'								textBeforeMatch = escapeHtml(logEntry.formattedMessage.substring(startIndex, searchIndex));',

+'								var searchTermReplacement = searchTermReplacementStartTag +',

+'									preStartTag + matchedText + preEndTag + searchTermReplacementEndTag;',

+'								logEntryContent += preStartTag + textBeforeMatch + preEndTag + searchTermReplacement;',

+'								if (isIe) {',

+'									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +',

+'										matchedText + searchTermReplacementEndTag;',

+'								}',

+'								startIndex = searchIndex + searchTermLength;',

+'							}',

+'							var textAfterLastMatch = escapeHtml(logEntry.formattedMessage.substr(startIndex));',

+'							logEntryContent += preStartTag + textAfterLastMatch + preEndTag;',

+'							if (isIe) {',

+'								wrappedLogEntryContent += textAfterLastMatch;',

+'							}',

+'						}',

+'						logEntry.setContent(logEntryContent, wrappedLogEntryContent);',

+'						var logEntryMatches = logEntry.getSearchMatches();',

+'						this.matches = this.matches.concat(logEntryMatches);',

+'					} else {',

+'						logEntry.setSearchMatch(false);',

+'						logEntry.setContent(logEntry.formattedMessage, logEntry.formattedMessage);',

+'					}',

+'					return doesMatch;',

+'				},',

+'',

+'				removeMatches: function(logEntries) {',

+'					var matchesToRemoveCount = 0;',

+'					var currentMatchRemoved = false;',

+'					var matchesToRemove = [];',

+'					var i, iLen, j, jLen;',

+'',

+'					// Establish the list of matches to be removed',

+'					for (i = 0, iLen = this.matches.length; i < iLen; i++) {',

+'						for (j = 0, jLen = logEntries.length; j < jLen; j++) {',

+'							if (this.matches[i].belongsTo(logEntries[j])) {',

+'								matchesToRemove.push(this.matches[i]);',

+'								if (i === currentMatchIndex) {',

+'									currentMatchRemoved = true;',

+'								}',

+'							}',

+'						}',

+'					}',

+'',

+'					// Set the new current match index if the current match has been deleted',

+'					// This will be the first match that appears after the first log entry being',

+'					// deleted, if one exists; otherwise, it\'s the first match overall',

+'					var newMatch = currentMatchRemoved ? null : this.matches[currentMatchIndex];',

+'					if (currentMatchRemoved) {',

+'						for (i = currentMatchIndex, iLen = this.matches.length; i < iLen; i++) {',

+'							if (this.matches[i].isVisible() && !array_contains(matchesToRemove, this.matches[i])) {',

+'								newMatch = this.matches[i];',

+'								break;',

+'							}',

+'						}',

+'					}',

+'',

+'					// Remove the matches',

+'					for (i = 0, iLen = matchesToRemove.length; i < iLen; i++) {',

+'						array_remove(this.matches, matchesToRemove[i]);',

+'						matchesToRemove[i].remove();',

+'					}',

+'',

+'					// Set the new match, if one exists',

+'					if (this.hasVisibleMatches()) {',

+'						if (newMatch === null) {',

+'							setCurrentMatchIndex(0);',

+'						} else {',

+'							// Get the index of the new match',

+'							var newMatchIndex = 0;',

+'							for (i = 0, iLen = this.matches.length; i < iLen; i++) {',

+'								if (newMatch === this.matches[i]) {',

+'									newMatchIndex = i;',

+'									break;',

+'								}',

+'							}',

+'							setCurrentMatchIndex(newMatchIndex);',

+'						}',

+'					} else {',

+'						currentMatchIndex = null;',

+'						displayNoMatches();',

+'					}',

+'				}',

+'			};',

+'',

+'			function getPageOffsetTop(el, container) {',

+'				var currentEl = el;',

+'				var y = 0;',

+'				while (currentEl && currentEl != container) {',

+'					y += currentEl.offsetTop;',

+'					currentEl = currentEl.offsetParent;',

+'				}',

+'				return y;',

+'			}',

+'',

+'			function scrollIntoView(el) {',

+'				var logContainer = logMainContainer;',

+'				// Check if the whole width of the element is visible and centre if not',

+'				if (!$("wrap").checked) {',

+'					var logContainerLeft = logContainer.scrollLeft;',

+'					var logContainerRight = logContainerLeft  + logContainer.offsetWidth;',

+'					var elLeft = el.offsetLeft;',

+'					var elRight = elLeft + el.offsetWidth;',

+'					if (elLeft < logContainerLeft || elRight > logContainerRight) {',

+'						logContainer.scrollLeft = elLeft - (logContainer.offsetWidth - el.offsetWidth) / 2;',

+'					}',

+'				}',

+'				// Check if the whole height of the element is visible and centre if not',

+'				var logContainerTop = logContainer.scrollTop;',

+'				var logContainerBottom = logContainerTop  + logContainer.offsetHeight;',

+'				var elTop = getPageOffsetTop(el) - getToolBarsHeight();',

+'				var elBottom = elTop + el.offsetHeight;',

+'				if (elTop < logContainerTop || elBottom > logContainerBottom) {',

+'					logContainer.scrollTop = elTop - (logContainer.offsetHeight - el.offsetHeight) / 2;',

+'				}',

+'			}',

+'',

+'			function Match(logEntryLevel, spanInMainDiv, spanInUnwrappedPre, spanInWrappedDiv) {',

+'				this.logEntryLevel = logEntryLevel;',

+'				this.spanInMainDiv = spanInMainDiv;',

+'				if (isIe) {',

+'					this.spanInUnwrappedPre = spanInUnwrappedPre;',

+'					this.spanInWrappedDiv = spanInWrappedDiv;',

+'				}',

+'				this.mainSpan = isIe ? spanInUnwrappedPre : spanInMainDiv;',

+'			}',

+'',

+'			Match.prototype = {',

+'				equals: function(match) {',

+'					return this.mainSpan === match.mainSpan;',

+'				},',

+'',

+'				setCurrent: function() {',

+'					if (isIe) {',

+'						addClass(this.spanInUnwrappedPre, "currentmatch");',

+'						addClass(this.spanInWrappedDiv, "currentmatch");',

+'						// Scroll the visible one into view',

+'						var elementToScroll = $("wrap").checked ? this.spanInWrappedDiv : this.spanInUnwrappedPre;',

+'						scrollIntoView(elementToScroll);',

+'					} else {',

+'						addClass(this.spanInMainDiv, "currentmatch");',

+'						scrollIntoView(this.spanInMainDiv);',

+'					}',

+'				},',

+'',

+'				belongsTo: function(logEntry) {',

+'					if (isIe) {',

+'						return isDescendant(this.spanInUnwrappedPre, logEntry.unwrappedPre);',

+'					} else {',

+'						return isDescendant(this.spanInMainDiv, logEntry.mainDiv);',

+'					}',

+'				},',

+'',

+'				setNotCurrent: function() {',

+'					if (isIe) {',

+'						removeClass(this.spanInUnwrappedPre, "currentmatch");',

+'						removeClass(this.spanInWrappedDiv, "currentmatch");',

+'					} else {',

+'						removeClass(this.spanInMainDiv, "currentmatch");',

+'					}',

+'				},',

+'',

+'				isOrphan: function() {',

+'					return isOrphan(this.mainSpan);',

+'				},',

+'',

+'				isVisible: function() {',

+'					return getCheckBox(this.logEntryLevel).checked;',

+'				},',

+'',

+'				remove: function() {',

+'					if (isIe) {',

+'						this.spanInUnwrappedPre = null;',

+'						this.spanInWrappedDiv = null;',

+'					} else {',

+'						this.spanInMainDiv = null;',

+'					}',

+'				}',

+'			};',

+'',

+'			var currentSearch = null;',

+'			var currentMatchIndex = null;',

+'',

+'			function doSearch() {',

+'				var searchBox = $("searchBox");',

+'				var searchTerm = searchBox.value;',

+'				var isRegex = $("searchRegex").checked;',

+'				var isCaseSensitive = $("searchCaseSensitive").checked;',

+'				var i;',

+'',

+'				if (searchTerm === "") {',

+'					$("searchReset").disabled = true;',

+'					$("searchNav").style.display = "none";',

+'					removeClass(document.body, "searching");',

+'					removeClass(searchBox, "hasmatches");',

+'					removeClass(searchBox, "nomatches");',

+'					for (i = 0; i < logEntries.length; i++) {',

+'						logEntries[i].clearSearch();',

+'						logEntries[i].setContent(logEntries[i].formattedMessage, logEntries[i].formattedMessage);',

+'					}',

+'					currentSearch = null;',

+'					setLogContainerHeight();',

+'				} else {',

+'					$("searchReset").disabled = false;',

+'					$("searchNav").style.display = "block";',

+'					var searchRegex;',

+'					var regexValid;',

+'					if (isRegex) {',

+'						try {',

+'							searchRegex = isCaseSensitive ? new RegExp(searchTerm, "g") : new RegExp(searchTerm, "gi");',

+'							regexValid = true;',

+'							replaceClass(searchBox, "validregex", "invalidregex");',

+'							searchBox.title = "Valid regex";',

+'						} catch (ex) {',

+'							regexValid = false;',

+'							replaceClass(searchBox, "invalidregex", "validregex");',

+'							searchBox.title = "Invalid regex: " + (ex.message ? ex.message : (ex.description ? ex.description : "unknown error"));',

+'							return;',

+'						}',

+'					} else {',

+'						searchBox.title = "";',

+'						removeClass(searchBox, "validregex");',

+'						removeClass(searchBox, "invalidregex");',

+'					}',

+'					addClass(document.body, "searching");',

+'					currentSearch = new Search(searchTerm, isRegex, searchRegex, isCaseSensitive);',

+'					for (i = 0; i < logEntries.length; i++) {',

+'						currentSearch.applyTo(logEntries[i]);',

+'					}',

+'					setLogContainerHeight();',

+'',

+'					// Highlight the first search match',

+'					if (currentSearch.hasVisibleMatches()) {',

+'						setCurrentMatchIndex(0);',

+'						displayMatches();',

+'					} else {',

+'						displayNoMatches();',

+'					}',

+'				}',

+'			}',

+'',

+'			function updateSearchFromFilters() {',

+'				if (currentSearch) {',

+'					if (currentSearch.hasMatches()) {',

+'						if (currentMatchIndex === null) {',

+'							currentMatchIndex = 0;',

+'						}',

+'						var currentMatch = currentSearch.matches[currentMatchIndex];',

+'						if (currentMatch.isVisible()) {',

+'							displayMatches();',

+'							setCurrentMatchIndex(currentMatchIndex);',

+'						} else {',

+'							currentMatch.setNotCurrent();',

+'							// Find the next visible match, if one exists',

+'							var nextVisibleMatchIndex = currentSearch.getNextVisibleMatchIndex();',

+'							if (nextVisibleMatchIndex > -1) {',

+'								setCurrentMatchIndex(nextVisibleMatchIndex);',

+'								displayMatches();',

+'							} else {',

+'								displayNoMatches();',

+'							}',

+'						}',

+'					} else {',

+'						displayNoMatches();',

+'					}',

+'				}',

+'			}',

+'',

+'			function refreshCurrentMatch() {',

+'				if (currentSearch && currentSearch.hasVisibleMatches()) {',

+'					setCurrentMatchIndex(currentMatchIndex);',

+'				}',

+'			}',

+'',

+'			function displayMatches() {',

+'				replaceClass($("searchBox"), "hasmatches", "nomatches");',

+'				$("searchBox").title = "" + currentSearch.matches.length + " matches found";',

+'				$("searchNav").style.display = "block";',

+'				setLogContainerHeight();',

+'			}',

+'',

+'			function displayNoMatches() {',

+'				replaceClass($("searchBox"), "nomatches", "hasmatches");',

+'				$("searchBox").title = "No matches found";',

+'				$("searchNav").style.display = "none";',

+'				setLogContainerHeight();',

+'			}',

+'',

+'			function toggleSearchEnabled(enable) {',

+'				enable = (typeof enable == "undefined") ? !$("searchDisable").checked : enable;',

+'				$("searchBox").disabled = !enable;',

+'				$("searchReset").disabled = !enable;',

+'				$("searchRegex").disabled = !enable;',

+'				$("searchNext").disabled = !enable;',

+'				$("searchPrevious").disabled = !enable;',

+'				$("searchCaseSensitive").disabled = !enable;',

+'				$("searchNav").style.display = (enable && ($("searchBox").value !== "") &&',

+'						currentSearch && currentSearch.hasVisibleMatches()) ?',

+'					"block" : "none";',

+'				if (enable) {',

+'					removeClass($("search"), "greyedout");',

+'					addClass(document.body, "searching");',

+'					if ($("searchHighlight").checked) {',

+'						addClass(logMainContainer, "searchhighlight");',

+'					} else {',

+'						removeClass(logMainContainer, "searchhighlight");',

+'					}',

+'					if ($("searchFilter").checked) {',

+'						addClass(logMainContainer, "searchfilter");',

+'					} else {',

+'						removeClass(logMainContainer, "searchfilter");',

+'					}',

+'					$("searchDisable").checked = !enable;',

+'				} else {',

+'					addClass($("search"), "greyedout");',

+'					removeClass(document.body, "searching");',

+'					removeClass(logMainContainer, "searchhighlight");',

+'					removeClass(logMainContainer, "searchfilter");',

+'				}',

+'				setLogContainerHeight();',

+'			}',

+'',

+'			function toggleSearchFilter() {',

+'				var enable = $("searchFilter").checked;',

+'				if (enable) {',

+'					addClass(logMainContainer, "searchfilter");',

+'				} else {',

+'					removeClass(logMainContainer, "searchfilter");',

+'				}',

+'				refreshCurrentMatch();',

+'			}',

+'',

+'			function toggleSearchHighlight() {',

+'				var enable = $("searchHighlight").checked;',

+'				if (enable) {',

+'					addClass(logMainContainer, "searchhighlight");',

+'				} else {',

+'					removeClass(logMainContainer, "searchhighlight");',

+'				}',

+'			}',

+'',

+'			function clearSearch() {',

+'				$("searchBox").value = "";',

+'				doSearch();',

+'			}',

+'',

+'			function searchNext() {',

+'				if (currentSearch !== null && currentMatchIndex !== null) {',

+'					currentSearch.matches[currentMatchIndex].setNotCurrent();',

+'					var nextMatchIndex = currentSearch.getNextVisibleMatchIndex();',

+'					if (nextMatchIndex > currentMatchIndex || confirm("Reached the end of the page. Start from the top?")) {',

+'						setCurrentMatchIndex(nextMatchIndex);',

+'					}',

+'				}',

+'			}',

+'',

+'			function searchPrevious() {',

+'				if (currentSearch !== null && currentMatchIndex !== null) {',

+'					currentSearch.matches[currentMatchIndex].setNotCurrent();',

+'					var previousMatchIndex = currentSearch.getPreviousVisibleMatchIndex();',

+'					if (previousMatchIndex < currentMatchIndex || confirm("Reached the start of the page. Continue from the bottom?")) {',

+'						setCurrentMatchIndex(previousMatchIndex);',

+'					}',

+'				}',

+'			}',

+'',

+'			function setCurrentMatchIndex(index) {',

+'				currentMatchIndex = index;',

+'				currentSearch.matches[currentMatchIndex].setCurrent();',

+'			}',

+'',

+'			/* ------------------------------------------------------------------------- */',

+'',

+'			// CSS Utilities',

+'',

+'			function addClass(el, cssClass) {',

+'				if (!hasClass(el, cssClass)) {',

+'					if (el.className) {',

+'						el.className += " " + cssClass;',

+'					} else {',

+'						el.className = cssClass;',

+'					}',

+'				}',

+'			}',

+'',

+'			function hasClass(el, cssClass) {',

+'				if (el.className) {',

+'					var classNames = el.className.split(" ");',

+'					return array_contains(classNames, cssClass);',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function removeClass(el, cssClass) {',

+'				if (hasClass(el, cssClass)) {',

+'					// Rebuild the className property',

+'					var existingClasses = el.className.split(" ");',

+'					var newClasses = [];',

+'					for (var i = 0, len = existingClasses.length; i < len; i++) {',

+'						if (existingClasses[i] != cssClass) {',

+'							newClasses[newClasses.length] = existingClasses[i];',

+'						}',

+'					}',

+'					el.className = newClasses.join(" ");',

+'				}',

+'			}',

+'',

+'			function replaceClass(el, newCssClass, oldCssClass) {',

+'				removeClass(el, oldCssClass);',

+'				addClass(el, newCssClass);',

+'			}',

+'',

+'			/* ------------------------------------------------------------------------- */',

+'',

+'			// Other utility functions',

+'',

+'			function getElementsByClass(el, cssClass, tagName) {',

+'				var elements = el.getElementsByTagName(tagName);',

+'				var matches = [];',

+'				for (var i = 0, len = elements.length; i < len; i++) {',

+'					if (hasClass(elements[i], cssClass)) {',

+'						matches.push(elements[i]);',

+'					}',

+'				}',

+'				return matches;',

+'			}',

+'',

+'			// Syntax borrowed from Prototype library',

+'			function $(id) {',

+'				return document.getElementById(id);',

+'			}',

+'',

+'			function isDescendant(node, ancestorNode) {',

+'				while (node != null) {',

+'					if (node === ancestorNode) {',

+'						return true;',

+'					}',

+'					node = node.parentNode;',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function isOrphan(node) {',

+'				var currentNode = node;',

+'				while (currentNode) {',

+'					if (currentNode == document.body) {',

+'						return false;',

+'					}',

+'					currentNode = currentNode.parentNode;',

+'				}',

+'				return true;',

+'			}',

+'',

+'			function escapeHtml(str) {',

+'				return str.replace(/&/g, "&amp;").replace(/[<]/g, "&lt;").replace(/>/g, "&gt;");',

+'			}',

+'',

+'			function getWindowWidth() {',

+'				if (window.innerWidth) {',

+'					return window.innerWidth;',

+'				} else if (document.documentElement && document.documentElement.clientWidth) {',

+'					return document.documentElement.clientWidth;',

+'				} else if (document.body) {',

+'					return document.body.clientWidth;',

+'				}',

+'				return 0;',

+'			}',

+'',

+'			function getWindowHeight() {',

+'				if (window.innerHeight) {',

+'					return window.innerHeight;',

+'				} else if (document.documentElement && document.documentElement.clientHeight) {',

+'					return document.documentElement.clientHeight;',

+'				} else if (document.body) {',

+'					return document.body.clientHeight;',

+'				}',

+'				return 0;',

+'			}',

+'',

+'			function getToolBarsHeight() {',

+'				return $("switches").offsetHeight;',

+'			}',

+'',

+'			function getChromeHeight() {',

+'				var height = getToolBarsHeight();',

+'				if (showCommandLine) {',

+'					height += $("commandLine").offsetHeight;',

+'				}',

+'				return height;',

+'			}',

+'',

+'			function setLogContainerHeight() {',

+'				if (logMainContainer) {',

+'					var windowHeight = getWindowHeight();',

+'					$("body").style.height = getWindowHeight() + "px";',

+'					logMainContainer.style.height = "" +',

+'						Math.max(0, windowHeight - getChromeHeight()) + "px";',

+'				}',

+'			}',

+'',

+'			function setCommandInputWidth() {',

+'				if (showCommandLine) {',

+'					$("command").style.width = "" + Math.max(0, $("commandLineContainer").offsetWidth -',

+'						($("evaluateButton").offsetWidth + 13)) + "px";',

+'				}',

+'			}',

+'',

+'			window.onresize = function() {',

+'				setCommandInputWidth();',

+'				setLogContainerHeight();',

+'			};',

+'',

+'			if (!Array.prototype.push) {',

+'				Array.prototype.push = function() {',

+'			        for (var i = 0, len = arguments.length; i < len; i++){',

+'			            this[this.length] = arguments[i];',

+'			        }',

+'			        return this.length;',

+'				};',

+'			}',

+'',

+'			if (!Array.prototype.pop) {',

+'				Array.prototype.pop = function() {',

+'					if (this.length > 0) {',

+'						var val = this[this.length - 1];',

+'						this.length = this.length - 1;',

+'						return val;',

+'					}',

+'				};',

+'			}',

+'',

+'			if (!Array.prototype.shift) {',

+'				Array.prototype.shift = function() {',

+'					if (this.length > 0) {',

+'						var firstItem = this[0];',

+'						for (var i = 0, len = this.length - 1; i < len; i++) {',

+'							this[i] = this[i + 1];',

+'						}',

+'						this.length = this.length - 1;',

+'						return firstItem;',

+'					}',

+'				};',

+'			}',

+'',

+'			if (!Array.prototype.splice) {',

+'				Array.prototype.splice = function(startIndex, deleteCount) {',

+'					var itemsAfterDeleted = this.slice(startIndex + deleteCount);',

+'					var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);',

+'					this.length = startIndex;',

+'					// Copy the arguments into a proper Array object',

+'					var argumentsArray = [];',

+'					for (var i = 0, len = arguments.length; i < len; i++) {',

+'						argumentsArray[i] = arguments[i];',

+'					}',

+'					var itemsToAppend = (argumentsArray.length > 2) ?',

+'						itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;',

+'					for (i = 0, len = itemsToAppend.length; i < len; i++) {',

+'						this.push(itemsToAppend[i]);',

+'					}',

+'					return itemsDeleted;',

+'				};',

+'			}',

+'',

+'			function array_remove(arr, val) {',

+'				var index = -1;',

+'				for (var i = 0, len = arr.length; i < len; i++) {',

+'					if (arr[i] === val) {',

+'						index = i;',

+'						break;',

+'					}',

+'				}',

+'				if (index >= 0) {',

+'					arr.splice(index, 1);',

+'					return index;',

+'				} else {',

+'					return false;',

+'				}',

+'			}',

+'',

+'			function array_removeFromStart(array, numberToRemove) {',

+'				if (Array.prototype.splice) {',

+'					array.splice(0, numberToRemove);',

+'				} else {',

+'					for (var i = numberToRemove, len = array.length; i < len; i++) {',

+'						array[i - numberToRemove] = array[i];',

+'					}',

+'					array.length = array.length - numberToRemove;',

+'				}',

+'				return array;',

+'			}',

+'',

+'			function array_contains(arr, val) {',

+'				for (var i = 0, len = arr.length; i < len; i++) {',

+'					if (arr[i] == val) {',

+'						return true;',

+'					}',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function getErrorMessage(ex) {',

+'				if (ex.message) {',

+'					return ex.message;',

+'				} else if (ex.description) {',

+'					return ex.description;',

+'				}',

+'				return "" + ex;',

+'			}',

+'',

+'			function moveCaretToEnd(input) {',

+'				if (input.setSelectionRange) {',

+'					input.focus();',

+'					var length = input.value.length;',

+'					input.setSelectionRange(length, length);',

+'				} else if (input.createTextRange) {',

+'					var range = input.createTextRange();',

+'					range.collapse(false);',

+'					range.select();',

+'				}',

+'				input.focus();',

+'			}',

+'',

+'			function stopPropagation(evt) {',

+'				if (evt.stopPropagation) {',

+'					evt.stopPropagation();',

+'				} else if (typeof evt.cancelBubble != "undefined") {',

+'					evt.cancelBubble = true;',

+'				}',

+'			}',

+'',

+'			function getEvent(evt) {',

+'				return evt ? evt : event;',

+'			}',

+'',

+'			function getTarget(evt) {',

+'				return evt.target ? evt.target : evt.srcElement;',

+'			}',

+'',

+'			function getRelatedTarget(evt) {',

+'				if (evt.relatedTarget) {',

+'					return evt.relatedTarget;',

+'				} else if (evt.srcElement) {',

+'					switch(evt.type) {',

+'						case "mouseover":',

+'							return evt.fromElement;',

+'						case "mouseout":',

+'							return evt.toElement;',

+'						default:',

+'							return evt.srcElement;',

+'					}',

+'				}',

+'			}',

+'',

+'			function cancelKeyEvent(evt) {',

+'				evt.returnValue = false;',

+'				stopPropagation(evt);',

+'			}',

+'',

+'			function evalCommandLine() {',

+'				var expr = $("command").value;',

+'				evalCommand(expr);',

+'				$("command").value = "";',

+'			}',

+'',

+'			function evalLastCommand() {',

+'				if (lastCommand != null) {',

+'					evalCommand(lastCommand);',

+'				}',

+'			}',

+'',

+'			var lastCommand = null;',

+'			var commandHistory = [];',

+'			var currentCommandIndex = 0;',

+'',

+'			function evalCommand(expr) {',

+'				if (appender) {',

+'					appender.evalCommandAndAppend(expr);',

+'				} else {',

+'					var prefix = ">>> " + expr + "\\r\\n";',

+'					try {',

+'						log("INFO", prefix + eval(expr));',

+'					} catch (ex) {',

+'						log("ERROR", prefix + "Error: " + getErrorMessage(ex));',

+'					}',

+'				}',

+'				// Update command history',

+'				if (expr != commandHistory[commandHistory.length - 1]) {',

+'					commandHistory.push(expr);',

+'					// Update the appender',

+'					if (appender) {',

+'						appender.storeCommandHistory(commandHistory);',

+'					}',

+'				}',

+'				currentCommandIndex = (expr == commandHistory[currentCommandIndex]) ? currentCommandIndex + 1 : commandHistory.length;',

+'				lastCommand = expr;',

+'			}',

+'			//]]>',

+'		</script>',

+'		<style type="text/css">',

+'			body {',

+'				background-color: white;',

+'				color: black;',

+'				padding: 0;',

+'				margin: 0;',

+'				font-family: tahoma, verdana, arial, helvetica, sans-serif;',

+'				overflow: hidden;',

+'			}',

+'',

+'			div#switchesContainer input {',

+'				margin-bottom: 0;',

+'			}',

+'',

+'			div.toolbar {',

+'				border-top: solid #ffffff 1px;',

+'				border-bottom: solid #aca899 1px;',

+'				background-color: #f1efe7;',

+'				padding: 3px 5px;',

+'				font-size: 68.75%;',

+'			}',

+'',

+'			div.toolbar, div#search input {',

+'				font-family: tahoma, verdana, arial, helvetica, sans-serif;',

+'			}',

+'',

+'			div.toolbar input.button {',

+'				padding: 0 5px;',

+'				font-size: 100%;',

+'			}',

+'',

+'			div.toolbar input.hidden {',

+'				display: none;',

+'			}',

+'',

+'			div#switches input#clearButton {',

+'				margin-left: 20px;',

+'			}',

+'',

+'			div#levels label {',

+'				font-weight: bold;',

+'			}',

+'',

+'			div#levels label, div#options label {',

+'				margin-right: 5px;',

+'			}',

+'',

+'			div#levels label#wrapLabel {',

+'				font-weight: normal;',

+'			}',

+'',

+'			div#search label {',

+'				margin-right: 10px;',

+'			}',

+'',

+'			div#search label.searchboxlabel {',

+'				margin-right: 0;',

+'			}',

+'',

+'			div#search input {',

+'				font-size: 100%;',

+'			}',

+'',

+'			div#search input.validregex {',

+'				color: green;',

+'			}',

+'',

+'			div#search input.invalidregex {',

+'				color: red;',

+'			}',

+'',

+'			div#search input.nomatches {',

+'				color: white;',

+'				background-color: #ff6666;',

+'			}',

+'',

+'			div#search input.nomatches {',

+'				color: white;',

+'				background-color: #ff6666;',

+'			}',

+'',

+'			div#searchNav {',

+'				display: none;',

+'			}',

+'',

+'			div#commandLine {',

+'				display: none;',

+'			}',

+'',

+'			div#commandLine input#command {',

+'				font-size: 100%;',

+'				font-family: Courier New, Courier;',

+'			}',

+'',

+'			div#commandLine input#evaluateButton {',

+'			}',

+'',

+'			*.greyedout {',

+'				color: gray !important;',

+'				border-color: gray !important;',

+'			}',

+'',

+'			*.greyedout *.alwaysenabled { color: black; }',

+'',

+'			*.unselectable {',

+'				-khtml-user-select: none;',

+'				-moz-user-select: none;',

+'				user-select: none;',

+'			}',

+'',

+'			div#log {',

+'				font-family: Courier New, Courier;',

+'				font-size: 75%;',

+'				width: 100%;',

+'				overflow: auto;',

+'				clear: both;',

+'				position: relative;',

+'			}',

+'',

+'			div.group {',

+'				border-color: #cccccc;',

+'				border-style: solid;',

+'				border-width: 1px 0 1px 1px;',

+'				overflow: visible;',

+'			}',

+'',

+'			div.oldIe div.group, div.oldIe div.group *, div.oldIe *.logentry {',

+'				height: 1%;',

+'			}',

+'',

+'			div.group div.groupheading span.expander {',

+'				border: solid black 1px;',

+'				font-family: Courier New, Courier;',

+'				font-size: 0.833em;',

+'				background-color: #eeeeee;',

+'				position: relative;',

+'				top: -1px;',

+'				color: black;',

+'				padding: 0 2px;',

+'				cursor: pointer;',

+'				cursor: hand;',

+'				height: 1%;',

+'			}',

+'',

+'			div.group div.groupcontent {',

+'				margin-left: 10px;',

+'				padding-bottom: 2px;',

+'				overflow: visible;',

+'			}',

+'',

+'			div.group div.expanded {',

+'				display: block;',

+'			}',

+'',

+'			div.group div.collapsed {',

+'				display: none;',

+'			}',

+'',

+'			*.logentry {',

+'				overflow: visible;',

+'				display: none;',

+'				white-space: pre;',

+'			}',

+'',

+'			span.pre {',

+'				white-space: pre;',

+'			}',

+'			',

+'			pre.unwrapped {',

+'				display: inline !important;',

+'			}',

+'',

+'			pre.unwrapped pre.pre, div.wrapped pre.pre {',

+'				display: inline;',

+'			}',

+'',

+'			div.wrapped pre.pre {',

+'				white-space: normal;',

+'			}',

+'',

+'			div.wrapped {',

+'				display: none;',

+'			}',

+'',

+'			body.searching *.logentry span.currentmatch {',

+'				color: white !important;',

+'				background-color: green !important;',

+'			}',

+'',

+'			body.searching div.searchhighlight *.logentry span.searchterm {',

+'				color: black;',

+'				background-color: yellow;',

+'			}',

+'',

+'			div.wrap *.logentry {',

+'				white-space: normal !important;',

+'				border-width: 0 0 1px 0;',

+'				border-color: #dddddd;',

+'				border-style: dotted;',

+'			}',

+'',

+'			div.wrap #log_wrapped, #log_unwrapped {',

+'				display: block;',

+'			}',

+'',

+'			div.wrap #log_unwrapped, #log_wrapped {',

+'				display: none;',

+'			}',

+'',

+'			div.wrap *.logentry span.pre {',

+'				overflow: visible;',

+'				white-space: normal;',

+'			}',

+'',

+'			div.wrap *.logentry pre.unwrapped {',

+'				display: none;',

+'			}',

+'',

+'			div.wrap *.logentry span.wrapped {',

+'				display: inline;',

+'			}',

+'',

+'			div.searchfilter *.searchnonmatch {',

+'				display: none !important;',

+'			}',

+'',

+'			div#log *.TRACE, label#label_TRACE {',

+'				color: #666666;',

+'			}',

+'',

+'			div#log *.DEBUG, label#label_DEBUG {',

+'				color: green;',

+'			}',

+'',

+'			div#log *.INFO, label#label_INFO {',

+'				color: #000099;',

+'			}',

+'',

+'			div#log *.WARN, label#label_WARN {',

+'				color: #999900;',

+'			}',

+'',

+'			div#log *.ERROR, label#label_ERROR {',

+'				color: red;',

+'			}',

+'',

+'			div#log *.FATAL, label#label_FATAL {',

+'				color: #660066;',

+'			}',

+'',

+'			div.TRACE#log *.TRACE,',

+'			div.DEBUG#log *.DEBUG,',

+'			div.INFO#log *.INFO,',

+'			div.WARN#log *.WARN,',

+'			div.ERROR#log *.ERROR,',

+'			div.FATAL#log *.FATAL {',

+'				display: block;',

+'			}',

+'',

+'			div#log div.separator {',

+'				background-color: #cccccc;',

+'				margin: 5px 0;',

+'				line-height: 1px;',

+'			}',

+'		</style>',

+'	</head>',

+'',

+'	<body id="body">',

+'		<div id="switchesContainer">',

+'			<div id="switches">',

+'				<div id="levels" class="toolbar">',

+'					Filters:',

+'					<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>',

+'					<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>',

+'					<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>',

+'					<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>',

+'					<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>',

+'					<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>',

+'					<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>',

+'				</div>',

+'				<div id="search" class="toolbar">',

+'					<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />',

+'					<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />',

+'					<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>',

+'					<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>',

+'					<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>',

+'					<div id="searchNav">',

+'						<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />',

+'						<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />',

+'						<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>',

+'						<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>',

+'					</div>',

+'				</div>',

+'				<div id="options" class="toolbar">',

+'					Options:',

+'					<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>',

+'					<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>',

+'					<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>',

+'					<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>',

+'					<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />',

+'					<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />',

+'					<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />',

+'				</div>',

+'			</div>',

+'		</div>',

+'		<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>',

+'		<div id="commandLine" class="toolbar">',

+'			<div id="commandLineContainer">',

+'				<input type="text" id="command" title="Enter a JavaScript command here and hit return or press \'Evaluate\'" />',

+'				<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />',

+'			</div>',

+'		</div>',

+'	</body>',

+'</html>',

+''

+];

+		};

+

+		var defaultCommandLineFunctions = [];

+

+		ConsoleAppender = function() {};

+

+		var consoleAppenderIdCounter = 1;

+		ConsoleAppender.prototype = new Appender();

+

+		ConsoleAppender.prototype.create = function(inPage, container,

+				lazyInit, initiallyMinimized, useDocumentWrite, width, height, focusConsoleWindow) {

+			var appender = this;

+

+			// Common properties

+			var initialized = false;

+			var consoleWindowCreated = false;

+			var consoleWindowLoaded = false;

+			var consoleClosed = false;

+

+			var queuedLoggingEvents = [];

+			var isSupported = true;

+			var consoleAppenderId = consoleAppenderIdCounter++;

+

+			// Local variables

+			initiallyMinimized = extractBooleanFromParam(initiallyMinimized, this.defaults.initiallyMinimized);

+			lazyInit = extractBooleanFromParam(lazyInit, this.defaults.lazyInit);

+			useDocumentWrite = extractBooleanFromParam(useDocumentWrite, this.defaults.useDocumentWrite);

+			var newestMessageAtTop = this.defaults.newestMessageAtTop;

+			var scrollToLatestMessage = this.defaults.scrollToLatestMessage;

+			width = width ? width : this.defaults.width;

+			height = height ? height : this.defaults.height;

+			var maxMessages = this.defaults.maxMessages;

+			var showCommandLine = this.defaults.showCommandLine;

+			var commandLineObjectExpansionDepth = this.defaults.commandLineObjectExpansionDepth;

+			var showHideButton = this.defaults.showHideButton;

+            var showCloseButton = this.defaults.showCloseButton;

+            var showLogEntryDeleteButtons = this.defaults.showLogEntryDeleteButtons;

+

+			this.setLayout(this.defaults.layout);

+

+			// Functions whose implementations vary between subclasses

+			var init, createWindow, safeToAppend, getConsoleWindow, open;

+

+			// Configuration methods. The function scope is used to prevent

+			// direct alteration to the appender configuration properties.

+			var appenderName = inPage ? "InPageAppender" : "PopUpAppender";

+			var checkCanConfigure = function(configOptionName) {

+				if (consoleWindowCreated) {

+					handleError(appenderName + ": configuration option '" + configOptionName + "' may not be set after the appender has been initialized");

+					return false;

+				}

+				return true;

+			};

+

+			var consoleWindowExists = function() {

+				return (consoleWindowLoaded && isSupported && !consoleClosed);

+			};

+

+			this.isNewestMessageAtTop = function() { return newestMessageAtTop; };

+			this.setNewestMessageAtTop = function(newestMessageAtTopParam) {

+				newestMessageAtTop = bool(newestMessageAtTopParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setNewestAtTop(newestMessageAtTop);

+				}

+			};

+

+			this.isScrollToLatestMessage = function() { return scrollToLatestMessage; };

+			this.setScrollToLatestMessage = function(scrollToLatestMessageParam) {

+				scrollToLatestMessage = bool(scrollToLatestMessageParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setScrollToLatest(scrollToLatestMessage);

+				}

+			};

+

+			this.getWidth = function() { return width; };

+			this.setWidth = function(widthParam) {

+				if (checkCanConfigure("width")) {

+					width = extractStringFromParam(widthParam, width);

+				}

+			};

+

+			this.getHeight = function() { return height; };

+			this.setHeight = function(heightParam) {

+				if (checkCanConfigure("height")) {

+					height = extractStringFromParam(heightParam, height);

+				}

+			};

+

+			this.getMaxMessages = function() { return maxMessages; };

+			this.setMaxMessages = function(maxMessagesParam) {

+				maxMessages = extractIntFromParam(maxMessagesParam, maxMessages);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setMaxMessages(maxMessages);

+				}

+			};

+

+			this.isShowCommandLine = function() { return showCommandLine; };

+			this.setShowCommandLine = function(showCommandLineParam) {

+				showCommandLine = bool(showCommandLineParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setShowCommandLine(showCommandLine);

+				}

+			};

+

+			this.isShowHideButton = function() { return showHideButton; };

+			this.setShowHideButton = function(showHideButtonParam) {

+				showHideButton = bool(showHideButtonParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setShowHideButton(showHideButton);

+				}

+			};

+

+			this.isShowCloseButton = function() { return showCloseButton; };

+			this.setShowCloseButton = function(showCloseButtonParam) {

+				showCloseButton = bool(showCloseButtonParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setShowCloseButton(showCloseButton);

+				}

+			};

+

+			this.getCommandLineObjectExpansionDepth = function() { return commandLineObjectExpansionDepth; };

+			this.setCommandLineObjectExpansionDepth = function(commandLineObjectExpansionDepthParam) {

+				commandLineObjectExpansionDepth = extractIntFromParam(commandLineObjectExpansionDepthParam, commandLineObjectExpansionDepth);

+			};

+

+			var minimized = initiallyMinimized;

+			this.isInitiallyMinimized = function() { return initiallyMinimized; };

+			this.setInitiallyMinimized = function(initiallyMinimizedParam) {

+				if (checkCanConfigure("initiallyMinimized")) {

+					initiallyMinimized = bool(initiallyMinimizedParam);

+					minimized = initiallyMinimized;

+				}

+			};

+

+			this.isUseDocumentWrite = function() { return useDocumentWrite; };

+			this.setUseDocumentWrite = function(useDocumentWriteParam) {

+				if (checkCanConfigure("useDocumentWrite")) {

+					useDocumentWrite = bool(useDocumentWriteParam);

+				}

+			};

+

+			// Common methods

+			function QueuedLoggingEvent(loggingEvent, formattedMessage) {

+				this.loggingEvent = loggingEvent;

+				this.levelName = loggingEvent.level.name;

+				this.formattedMessage = formattedMessage;

+			}

+

+			QueuedLoggingEvent.prototype.append = function() {

+				getConsoleWindow().log(this.levelName, this.formattedMessage);

+			};

+

+			function QueuedGroup(name, initiallyExpanded) {

+				this.name = name;

+				this.initiallyExpanded = initiallyExpanded;

+			}

+

+			QueuedGroup.prototype.append = function() {

+				getConsoleWindow().group(this.name, this.initiallyExpanded);

+			};

+

+			function QueuedGroupEnd() {}

+

+			QueuedGroupEnd.prototype.append = function() {

+				getConsoleWindow().groupEnd();

+			};

+

+			var checkAndAppend = function() {

+				// Next line forces a check of whether the window has been closed

+				safeToAppend();

+				if (!initialized) {

+					init();

+				} else if (consoleClosed && reopenWhenClosed) {

+					createWindow();

+				}

+				if (safeToAppend()) {

+					appendQueuedLoggingEvents();

+				}

+			};

+

+			this.append = function(loggingEvent) {

+				if (isSupported) {

+					// Format the message

+					var formattedMessage = appender.getLayout().format(loggingEvent);

+					if (this.getLayout().ignoresThrowable()) {

+						formattedMessage += loggingEvent.getThrowableStrRep();

+					}

+					queuedLoggingEvents.push(new QueuedLoggingEvent(loggingEvent, formattedMessage));

+					checkAndAppend();

+				}

+			};

+

+            this.group = function(name, initiallyExpanded) {

+				if (isSupported) {

+					queuedLoggingEvents.push(new QueuedGroup(name, initiallyExpanded));

+					checkAndAppend();

+				}

+			};

+

+            this.groupEnd = function() {

+				if (isSupported) {

+					queuedLoggingEvents.push(new QueuedGroupEnd());

+					checkAndAppend();

+				}

+			};

+

+			var appendQueuedLoggingEvents = function() {

+				var currentLoggingEvent;

+				while (queuedLoggingEvents.length > 0) {

+					queuedLoggingEvents.shift().append();

+				}

+				if (focusConsoleWindow) {

+					getConsoleWindow().focus();

+				}

+			};

+

+			this.setAddedToLogger = function(logger) {

+				this.loggers.push(logger);

+				if (enabled && !lazyInit) {

+					init();

+				}

+			};

+

+			this.clear = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().clearLog();

+				}

+				queuedLoggingEvents.length = 0;

+			};

+

+			this.focus = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().focus();

+				}

+			};

+

+			this.focusCommandLine = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().focusCommandLine();

+				}

+			};

+

+			this.focusSearch = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().focusSearch();

+				}

+			};

+

+			var commandWindow = window;

+

+			this.getCommandWindow = function() { return commandWindow; };

+			this.setCommandWindow = function(commandWindowParam) {

+				commandWindow = commandWindowParam;

+			};

+

+			this.executeLastCommand = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().evalLastCommand();

+				}

+			};

+

+			var commandLayout = new PatternLayout("%m");

+			this.getCommandLayout = function() { return commandLayout; };

+			this.setCommandLayout = function(commandLayoutParam) {

+				commandLayout = commandLayoutParam;

+			};

+

+			this.evalCommandAndAppend = function(expr) {

+				var commandReturnValue = { appendResult: true, isError: false };

+				var commandOutput = "";

+				// Evaluate the command

+				try {

+					var result, i;

+					// The next three lines constitute a workaround for IE. Bizarrely, iframes seem to have no

+					// eval method on the window object initially, but once execScript has been called on

+					// it once then the eval method magically appears. See http://www.thismuchiknow.co.uk/?p=25

+					if (!commandWindow.eval && commandWindow.execScript) {

+						commandWindow.execScript("null");

+					}

+

+					var commandLineFunctionsHash = {};

+					for (i = 0, len = commandLineFunctions.length; i < len; i++) {

+						commandLineFunctionsHash[commandLineFunctions[i][0]] = commandLineFunctions[i][1];

+					}

+

+					// Keep an array of variables that are being changed in the command window so that they

+					// can be restored to their original values afterwards

+					var objectsToRestore = [];

+					var addObjectToRestore = function(name) {

+						objectsToRestore.push([name, commandWindow[name]]);

+					};

+

+					addObjectToRestore("appender");

+					commandWindow.appender = appender;

+

+					addObjectToRestore("commandReturnValue");

+					commandWindow.commandReturnValue = commandReturnValue;

+

+					addObjectToRestore("commandLineFunctionsHash");

+					commandWindow.commandLineFunctionsHash = commandLineFunctionsHash;

+

+					var addFunctionToWindow = function(name) {

+						addObjectToRestore(name);

+						commandWindow[name] = function() {

+							return this.commandLineFunctionsHash[name](appender, arguments, commandReturnValue);

+						};

+					};

+

+					for (i = 0, len = commandLineFunctions.length; i < len; i++) {

+						addFunctionToWindow(commandLineFunctions[i][0]);

+					}

+

+					// Another bizarre workaround to get IE to eval in the global scope

+					if (commandWindow === window && commandWindow.execScript) {

+						addObjectToRestore("evalExpr");

+						addObjectToRestore("result");

+						window.evalExpr = expr;

+						commandWindow.execScript("window.result=eval(window.evalExpr);");

+						result = window.result;

+ 					} else {

+ 						result = commandWindow.eval(expr);

+ 					}

+					commandOutput = isUndefined(result) ? result : formatObjectExpansion(result, commandLineObjectExpansionDepth);

+

+					// Restore variables in the command window to their original state

+					for (i = 0, len = objectsToRestore.length; i < len; i++) {

+						commandWindow[objectsToRestore[i][0]] = objectsToRestore[i][1];

+					}

+				} catch (ex) {

+					commandOutput = "Error evaluating command: " + getExceptionStringRep(ex);

+					commandReturnValue.isError = true;

+				}

+				// Append command output

+				if (commandReturnValue.appendResult) {

+					var message = ">>> " + expr;

+					if (!isUndefined(commandOutput)) {

+						message += newLine + commandOutput;

+					}

+					var level = commandReturnValue.isError ? Level.ERROR : Level.INFO;

+					var loggingEvent = new LoggingEvent(null, new Date(), level, [message], null);

+					var mainLayout = this.getLayout();

+					this.setLayout(commandLayout);

+					this.append(loggingEvent);

+					this.setLayout(mainLayout);

+				}

+			};

+

+			var commandLineFunctions = defaultCommandLineFunctions.concat([]);

+

+			this.addCommandLineFunction = function(functionName, commandLineFunction) {

+				commandLineFunctions.push([functionName, commandLineFunction]);

+			};

+

+			var commandHistoryCookieName = "log4javascriptCommandHistory";

+			this.storeCommandHistory = function(commandHistory) {

+				setCookie(commandHistoryCookieName, commandHistory.join(","));

+			};

+

+			var writeHtml = function(doc) {

+				var lines = getConsoleHtmlLines();

+				doc.open();

+				for (var i = 0, len = lines.length; i < len; i++) {

+					doc.writeln(lines[i]);

+				}

+				doc.close();

+			};

+

+			// Set up event listeners

+			this.setEventTypes(["load", "unload"]);

+

+			var consoleWindowLoadHandler = function() {

+				var win = getConsoleWindow();

+				win.setAppender(appender);

+				win.setNewestAtTop(newestMessageAtTop);

+				win.setScrollToLatest(scrollToLatestMessage);

+				win.setMaxMessages(maxMessages);

+				win.setShowCommandLine(showCommandLine);

+				win.setShowHideButton(showHideButton);

+				win.setShowCloseButton(showCloseButton);

+				win.setMainWindow(window);

+

+				// Restore command history stored in cookie

+				var storedValue = getCookie(commandHistoryCookieName);

+				if (storedValue) {

+					win.commandHistory = storedValue.split(",");

+					win.currentCommandIndex = win.commandHistory.length;

+				}

+

+				appender.dispatchEvent("load", { "win" : win });

+			};

+

+			this.unload = function() {

+				logLog.debug("unload " + this + ", caller: " + this.unload.caller);

+				if (!consoleClosed) {

+					logLog.debug("really doing unload " + this);

+					consoleClosed = true;

+					consoleWindowLoaded = false;

+					consoleWindowCreated = false;

+					appender.dispatchEvent("unload", {});

+				}

+			};

+

+			var pollConsoleWindow = function(windowTest, interval, successCallback, errorMessage) {

+				function doPoll() {

+					try {

+						// Test if the console has been closed while polling

+						if (consoleClosed) {

+							clearInterval(poll);

+						}

+						if (windowTest(getConsoleWindow())) {

+							clearInterval(poll);

+							successCallback();

+						}

+					} catch (ex) {

+						clearInterval(poll);

+						isSupported = false;

+						handleError(errorMessage, ex);

+					}

+				}

+

+				// Poll the pop-up since the onload event is not reliable

+				var poll = setInterval(doPoll, interval);

+			};

+

+			var getConsoleUrl = function() {

+				var documentDomainSet = (document.domain != location.hostname);

+				return useDocumentWrite ? "" : getBaseUrl() + "console_uncompressed.html" +

+											   (documentDomainSet ? "?log4javascript_domain=" + escape(document.domain) : "");

+			};

+

+			// Define methods and properties that vary between subclasses

+			if (inPage) {

+				// InPageAppender

+

+				var containerElement = null;

+

+				// Configuration methods. The function scope is used to prevent

+				// direct alteration to the appender configuration properties.

+				var cssProperties = [];

+				this.addCssProperty = function(name, value) {

+					if (checkCanConfigure("cssProperties")) {

+						cssProperties.push([name, value]);

+					}

+				};

+

+				// Define useful variables

+				var windowCreationStarted = false;

+				var iframeContainerDiv;

+				var iframeId = uniqueId + "_InPageAppender_" + consoleAppenderId;

+

+				this.hide = function() {

+					if (initialized && consoleWindowCreated) {

+						if (consoleWindowExists()) {

+							getConsoleWindow().$("command").blur();

+						}

+						iframeContainerDiv.style.display = "none";

+						minimized = true;

+					}

+				};

+

+				this.show = function() {

+					if (initialized) {

+						if (consoleWindowCreated) {

+							iframeContainerDiv.style.display = "block";

+							this.setShowCommandLine(showCommandLine); // Force IE to update

+							minimized = false;

+						} else if (!windowCreationStarted) {

+							createWindow(true);

+						}

+					}

+				};

+

+				this.isVisible = function() {

+					return !minimized && !consoleClosed;

+				};

+

+				this.close = function(fromButton) {

+					if (!consoleClosed && (!fromButton || confirm("This will permanently remove the console from the page. No more messages will be logged. Do you wish to continue?"))) {

+						iframeContainerDiv.parentNode.removeChild(iframeContainerDiv);

+						this.unload();

+					}

+				};

+

+				// Create open, init, getConsoleWindow and safeToAppend functions

+				open = function() {

+					var initErrorMessage = "InPageAppender.open: unable to create console iframe";

+

+					function finalInit() {

+						try {

+							if (!initiallyMinimized) {

+								appender.show();

+							}

+							consoleWindowLoadHandler();

+							consoleWindowLoaded = true;

+							appendQueuedLoggingEvents();

+						} catch (ex) {

+							isSupported = false;

+							handleError(initErrorMessage, ex);

+						}

+					}

+

+					function writeToDocument() {

+						try {

+							var windowTest = function(win) { return isLoaded(win); };

+							if (useDocumentWrite) {

+								writeHtml(getConsoleWindow().document);

+							}

+							if (windowTest(getConsoleWindow())) {

+								finalInit();

+							} else {

+								pollConsoleWindow(windowTest, 100, finalInit, initErrorMessage);

+							}

+						} catch (ex) {

+							isSupported = false;

+							handleError(initErrorMessage, ex);

+						}

+					}

+

+					minimized = false;

+					iframeContainerDiv = containerElement.appendChild(document.createElement("div"));

+

+					iframeContainerDiv.style.width = width;

+					iframeContainerDiv.style.height = height;

+					iframeContainerDiv.style.border = "solid gray 1px";

+

+					for (var i = 0, len = cssProperties.length; i < len; i++) {

+						iframeContainerDiv.style[cssProperties[i][0]] = cssProperties[i][1];

+					}

+

+					var iframeSrc = useDocumentWrite ? "" : " src='" + getConsoleUrl() + "'";

+

+					// Adding an iframe using the DOM would be preferable, but it doesn't work

+					// in IE5 on Windows, or in Konqueror prior to version 3.5 - in Konqueror

+					// it creates the iframe fine but I haven't been able to find a way to obtain

+					// the iframe's window object

+					iframeContainerDiv.innerHTML = "<iframe id='" + iframeId + "' name='" + iframeId +

+						"' width='100%' height='100%' frameborder='0'" + iframeSrc +

+						" scrolling='no'></iframe>";

+					consoleClosed = false;

+

+					// Write the console HTML to the iframe

+					var iframeDocumentExistsTest = function(win) {

+						try {

+							return bool(win) && bool(win.document);

+						} catch (ex) {

+							return false;

+						}

+					};

+					if (iframeDocumentExistsTest(getConsoleWindow())) {

+						writeToDocument();

+					} else {

+						pollConsoleWindow(iframeDocumentExistsTest, 100, writeToDocument, initErrorMessage);

+					}

+					consoleWindowCreated = true;

+				};

+

+				createWindow = function(show) {

+					if (show || !initiallyMinimized) {

+						var pageLoadHandler = function() {

+							if (!container) {

+								// Set up default container element

+								containerElement = document.createElement("div");

+								containerElement.style.position = "fixed";

+								containerElement.style.left = "0";

+								containerElement.style.right = "0";

+								containerElement.style.bottom = "0";

+								document.body.appendChild(containerElement);

+								appender.addCssProperty("borderWidth", "1px 0 0 0");

+								appender.addCssProperty("zIndex", 1000000); // Can't find anything authoritative that says how big z-index can be

+								open();

+							} else {

+								try {

+									var el = document.getElementById(container);

+									if (el.nodeType == 1) {

+										containerElement = el;

+									}

+									open();

+								} catch (ex) {

+									handleError("InPageAppender.init: invalid container element '" + container + "' supplied", ex);

+								}

+							}

+						};

+

+						// Test the type of the container supplied. First, check if it's an element

+						if (pageLoaded && container && container.appendChild) {

+							containerElement = container;

+							open();

+						} else if (pageLoaded) {

+							pageLoadHandler();

+						} else {

+							log4javascript.addEventListener("load", pageLoadHandler);

+						}

+						windowCreationStarted = true;

+					}

+				};

+

+				init = function() {

+					createWindow();

+					initialized = true;

+				};

+

+				getConsoleWindow = function() {

+					var iframe = window.frames[iframeId];

+					if (iframe) {

+						return iframe;

+					}

+				};

+

+				safeToAppend = function() {

+					if (isSupported && !consoleClosed) {

+						if (consoleWindowCreated && !consoleWindowLoaded && getConsoleWindow() && isLoaded(getConsoleWindow())) {

+							consoleWindowLoaded = true;

+						}

+						return consoleWindowLoaded;

+					}

+					return false;

+				};

+			} else {

+				// PopUpAppender

+

+				// Extract params

+				var useOldPopUp = appender.defaults.useOldPopUp;

+				var complainAboutPopUpBlocking = appender.defaults.complainAboutPopUpBlocking;

+				var reopenWhenClosed = this.defaults.reopenWhenClosed;

+

+				// Configuration methods. The function scope is used to prevent

+				// direct alteration to the appender configuration properties.

+				this.isUseOldPopUp = function() { return useOldPopUp; };

+				this.setUseOldPopUp = function(useOldPopUpParam) {

+					if (checkCanConfigure("useOldPopUp")) {

+						useOldPopUp = bool(useOldPopUpParam);

+					}

+				};

+

+				this.isComplainAboutPopUpBlocking = function() { return complainAboutPopUpBlocking; };

+				this.setComplainAboutPopUpBlocking = function(complainAboutPopUpBlockingParam) {

+					if (checkCanConfigure("complainAboutPopUpBlocking")) {

+						complainAboutPopUpBlocking = bool(complainAboutPopUpBlockingParam);

+					}

+				};

+

+				this.isFocusPopUp = function() { return focusConsoleWindow; };

+				this.setFocusPopUp = function(focusPopUpParam) {

+					// This property can be safely altered after logging has started

+					focusConsoleWindow = bool(focusPopUpParam);

+				};

+

+				this.isReopenWhenClosed = function() { return reopenWhenClosed; };

+				this.setReopenWhenClosed = function(reopenWhenClosedParam) {

+					// This property can be safely altered after logging has started

+					reopenWhenClosed = bool(reopenWhenClosedParam);

+				};

+

+				this.close = function() {

+					logLog.debug("close " + this);

+					try {

+						popUp.close();

+						this.unload();

+					} catch (ex) {

+						// Do nothing

+					}

+				};

+

+				this.hide = function() {

+					logLog.debug("hide " + this);

+					if (consoleWindowExists()) {

+						this.close();

+					}

+				};

+

+				this.show = function() {

+					logLog.debug("show " + this);

+					if (!consoleWindowCreated) {

+						open();

+					}

+				};

+

+				this.isVisible = function() {

+					return safeToAppend();

+				};

+

+				// Define useful variables

+				var popUp;

+

+				// Create open, init, getConsoleWindow and safeToAppend functions

+				open = function() {

+					var windowProperties = "width=" + width + ",height=" + height + ",status,resizable";

+					var frameInfo = "";

+					try {

+						var frameEl = window.frameElement;

+						if (frameEl) {

+							frameInfo = "_" + frameEl.tagName + "_" + (frameEl.name || frameEl.id || "");

+						}

+					} catch (e) {

+						frameInfo = "_inaccessibleParentFrame";

+					}

+					var windowName = "PopUp_" + location.host.replace(/[^a-z0-9]/gi, "_") + "_" + consoleAppenderId + frameInfo;

+					if (!useOldPopUp || !useDocumentWrite) {

+						// Ensure a previous window isn't used by using a unique name

+						windowName = windowName + "_" + uniqueId;

+					}

+

+					var checkPopUpClosed = function(win) {

+						if (consoleClosed) {

+							return true;

+						} else {

+							try {

+								return bool(win) && win.closed;

+							} catch(ex) {}

+						}

+						return false;

+					};

+

+					var popUpClosedCallback = function() {

+						if (!consoleClosed) {

+							appender.unload();

+						}

+					};

+

+					function finalInit() {

+						getConsoleWindow().setCloseIfOpenerCloses(!useOldPopUp || !useDocumentWrite);

+						consoleWindowLoadHandler();

+						consoleWindowLoaded = true;

+						appendQueuedLoggingEvents();

+						pollConsoleWindow(checkPopUpClosed, 500, popUpClosedCallback,

+								"PopUpAppender.checkPopUpClosed: error checking pop-up window");

+					}

+

+					try {

+						popUp = window.open(getConsoleUrl(), windowName, windowProperties);

+						consoleClosed = false;

+						consoleWindowCreated = true;

+						if (popUp && popUp.document) {

+							if (useDocumentWrite && useOldPopUp && isLoaded(popUp)) {

+								popUp.mainPageReloaded();

+								finalInit();

+							} else {

+								if (useDocumentWrite) {

+									writeHtml(popUp.document);

+								}

+								// Check if the pop-up window object is available

+								var popUpLoadedTest = function(win) { return bool(win) && isLoaded(win); };

+								if (isLoaded(popUp)) {

+									finalInit();

+								} else {

+									pollConsoleWindow(popUpLoadedTest, 100, finalInit,

+											"PopUpAppender.init: unable to create console window");

+								}

+							}

+						} else {

+							isSupported = false;

+							logLog.warn("PopUpAppender.init: pop-ups blocked, please unblock to use PopUpAppender");

+							if (complainAboutPopUpBlocking) {

+								handleError("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");

+							}

+						}

+					} catch (ex) {

+						handleError("PopUpAppender.init: error creating pop-up", ex);

+					}

+				};

+

+				createWindow = function() {

+					if (!initiallyMinimized) {

+						open();

+					}

+				};

+

+				init = function() {

+					createWindow();

+					initialized = true;

+				};

+

+				getConsoleWindow = function() {

+					return popUp;

+				};

+

+				safeToAppend = function() {

+					if (isSupported && !isUndefined(popUp) && !consoleClosed) {

+						if (popUp.closed ||

+								(consoleWindowLoaded && isUndefined(popUp.closed))) { // Extra check for Opera

+							appender.unload();

+							logLog.debug("PopUpAppender: pop-up closed");

+							return false;

+						}

+						if (!consoleWindowLoaded && isLoaded(popUp)) {

+							consoleWindowLoaded = true;

+						}

+					}

+					return isSupported && consoleWindowLoaded && !consoleClosed;

+				};

+			}

+

+			// Expose getConsoleWindow so that automated tests can check the DOM

+			this.getConsoleWindow = getConsoleWindow;

+		};

+

+		ConsoleAppender.addGlobalCommandLineFunction = function(functionName, commandLineFunction) {

+			defaultCommandLineFunctions.push([functionName, commandLineFunction]);

+		};

+

+		/* ------------------------------------------------------------------ */

+

+		function PopUpAppender(lazyInit, initiallyMinimized, useDocumentWrite,

+							   width, height) {

+			this.create(false, null, lazyInit, initiallyMinimized,

+					useDocumentWrite, width, height, this.defaults.focusPopUp);

+		}

+

+		PopUpAppender.prototype = new ConsoleAppender();

+

+		PopUpAppender.prototype.defaults = {

+			layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),

+			initiallyMinimized: false,

+			focusPopUp: false,

+			lazyInit: true,

+			useOldPopUp: true,

+			complainAboutPopUpBlocking: true,

+			newestMessageAtTop: false,

+			scrollToLatestMessage: true,

+			width: "600",

+			height: "400",

+			reopenWhenClosed: false,

+			maxMessages: null,

+			showCommandLine: true,

+			commandLineObjectExpansionDepth: 1,

+			showHideButton: false,

+			showCloseButton: true,

+            showLogEntryDeleteButtons: true,

+            useDocumentWrite: true

+		};

+

+		PopUpAppender.prototype.toString = function() {

+			return "PopUpAppender";

+		};

+

+		log4javascript.PopUpAppender = PopUpAppender;

+

+		/* ------------------------------------------------------------------ */

+

+		function InPageAppender(container, lazyInit, initiallyMinimized,

+								useDocumentWrite, width, height) {

+			this.create(true, container, lazyInit, initiallyMinimized,

+					useDocumentWrite, width, height, false);

+		}

+

+		InPageAppender.prototype = new ConsoleAppender();

+

+		InPageAppender.prototype.defaults = {

+			layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),

+			initiallyMinimized: false,

+			lazyInit: true,

+			newestMessageAtTop: false,

+			scrollToLatestMessage: true,

+			width: "100%",

+			height: "220px",

+			maxMessages: null,

+			showCommandLine: true,

+			commandLineObjectExpansionDepth: 1,

+			showHideButton: false,

+			showCloseButton: false,

+            showLogEntryDeleteButtons: true,

+            useDocumentWrite: true

+		};

+

+		InPageAppender.prototype.toString = function() {

+			return "InPageAppender";

+		};

+

+		log4javascript.InPageAppender = InPageAppender;

+

+		// Next line for backwards compatibility

+		log4javascript.InlineAppender = InPageAppender;

+	})();

+	/* ---------------------------------------------------------------------- */

+	// Console extension functions

+

+	function padWithSpaces(str, len) {

+		if (str.length < len) {

+			var spaces = [];

+			var numberOfSpaces = Math.max(0, len - str.length);

+			for (var i = 0; i < numberOfSpaces; i++) {

+				spaces[i] = " ";

+			}

+			str += spaces.join("");

+		}

+		return str;

+	}

+

+	(function() {

+		function dir(obj) {

+			var maxLen = 0;

+			// Obtain the length of the longest property name

+			for (var p in obj) {

+				maxLen = Math.max(toStr(p).length, maxLen);

+			}

+			// Create the nicely formatted property list

+			var propList = [];

+			for (p in obj) {

+				var propNameStr = "  " + padWithSpaces(toStr(p), maxLen + 2);

+				var propVal;

+				try {

+					propVal = splitIntoLines(toStr(obj[p])).join(padWithSpaces(newLine, maxLen + 6));

+				} catch (ex) {

+					propVal = "[Error obtaining property. Details: " + getExceptionMessage(ex) + "]";

+				}

+				propList.push(propNameStr + propVal);

+			}

+			return propList.join(newLine);

+		}

+

+		var nodeTypes = {

+			ELEMENT_NODE: 1,

+			ATTRIBUTE_NODE: 2,

+			TEXT_NODE: 3,

+			CDATA_SECTION_NODE: 4,

+			ENTITY_REFERENCE_NODE: 5,

+			ENTITY_NODE: 6,

+			PROCESSING_INSTRUCTION_NODE: 7,

+			COMMENT_NODE: 8,

+			DOCUMENT_NODE: 9,

+			DOCUMENT_TYPE_NODE: 10,

+			DOCUMENT_FRAGMENT_NODE: 11,

+			NOTATION_NODE: 12

+		};

+

+		var preFormattedElements = ["script", "pre"];

+

+		// This should be the definitive list, as specified by the XHTML 1.0 Transitional DTD

+		var emptyElements = ["br", "img", "hr", "param", "link", "area", "input", "col", "base", "meta"];

+		var indentationUnit = "  ";

+

+		// Create and return an XHTML string from the node specified

+		function getXhtml(rootNode, includeRootNode, indentation, startNewLine, preformatted) {

+			includeRootNode = (typeof includeRootNode == "undefined") ? true : !!includeRootNode;

+			if (typeof indentation != "string") {

+				indentation = "";

+			}

+			startNewLine = !!startNewLine;

+			preformatted = !!preformatted;

+			var xhtml;

+

+			function isWhitespace(node) {

+				return ((node.nodeType == nodeTypes.TEXT_NODE) && /^[ \t\r\n]*$/.test(node.nodeValue));

+			}

+

+			function fixAttributeValue(attrValue) {

+				return attrValue.toString().replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/"/g, "&quot;");

+			}

+

+			function getStyleAttributeValue(el) {

+				var stylePairs = el.style.cssText.split(";");

+				var styleValue = "";

+				var isFirst = true;

+				for (var j = 0, len = stylePairs.length; j < len; j++) {

+					var nameValueBits = stylePairs[j].split(":");

+					var props = [];

+					if (!/^\s*$/.test(nameValueBits[0])) {

+						props.push(trim(nameValueBits[0]).toLowerCase() + ":" + trim(nameValueBits[1]));

+					}

+					styleValue = props.join(";");

+				}

+				return styleValue;

+			}

+

+			function getNamespace(el) {

+				if (el.prefix) {

+					return el.prefix;

+				} else if (el.outerHTML) {

+					var regex = new RegExp("<([^:]+):" + el.tagName + "[^>]*>", "i");

+					if (regex.test(el.outerHTML)) {

+						return RegExp.$1.toLowerCase();

+					}

+				}

+                return "";

+			}

+

+			var lt = "<";

+			var gt = ">";

+

+			if (includeRootNode && rootNode.nodeType != nodeTypes.DOCUMENT_FRAGMENT_NODE) {

+				switch (rootNode.nodeType) {

+					case nodeTypes.ELEMENT_NODE:

+						var tagName = rootNode.tagName.toLowerCase();

+						xhtml = startNewLine ? newLine + indentation : "";

+						xhtml += lt;

+						// Allow for namespaces, where present

+						var prefix = getNamespace(rootNode);

+						var hasPrefix = !!prefix;

+						if (hasPrefix) {

+							xhtml += prefix + ":";

+						}

+						xhtml += tagName;

+						for (i = 0, len = rootNode.attributes.length; i < len; i++) {

+							var currentAttr = rootNode.attributes[i];

+							// Check the attribute is valid.

+							if (!	currentAttr.specified ||

+									currentAttr.nodeValue === null ||

+									currentAttr.nodeName.toLowerCase() === "style" ||

+									typeof currentAttr.nodeValue !== "string" ||

+									currentAttr.nodeName.indexOf("_moz") === 0) {

+								continue;

+							}

+							xhtml += " " + currentAttr.nodeName.toLowerCase() + "=\"";

+							xhtml += fixAttributeValue(currentAttr.nodeValue);

+							xhtml += "\"";

+						}

+						// Style needs to be done separately as it is not reported as an

+						// attribute in IE

+						if (rootNode.style.cssText) {

+							var styleValue = getStyleAttributeValue(rootNode);

+							if (styleValue !== "") {

+								xhtml += " style=\"" + getStyleAttributeValue(rootNode) + "\"";

+							}

+						}

+						if (array_contains(emptyElements, tagName) ||

+								(hasPrefix && !rootNode.hasChildNodes())) {

+							xhtml += "/" + gt;

+						} else {

+							xhtml += gt;

+							// Add output for childNodes collection (which doesn't include attribute nodes)

+							var childStartNewLine = !(rootNode.childNodes.length === 1 &&

+								rootNode.childNodes[0].nodeType === nodeTypes.TEXT_NODE);

+							var childPreformatted = array_contains(preFormattedElements, tagName);

+							for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {

+								xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit,

+									childStartNewLine, childPreformatted);

+							}

+							// Add the end tag

+							var endTag = lt + "/" + tagName + gt;

+							xhtml += childStartNewLine ? newLine + indentation + endTag : endTag;

+						}

+						return xhtml;

+					case nodeTypes.TEXT_NODE:

+						if (isWhitespace(rootNode)) {

+							xhtml = "";

+						} else {

+							if (preformatted) {

+								xhtml = rootNode.nodeValue;

+							} else {

+								// Trim whitespace from each line of the text node

+								var lines = splitIntoLines(trim(rootNode.nodeValue));

+								var trimmedLines = [];

+								for (var i = 0, len = lines.length; i < len; i++) {

+									trimmedLines[i] = trim(lines[i]);

+								}

+								xhtml = trimmedLines.join(newLine + indentation);

+							}

+							if (startNewLine) {

+								xhtml = newLine + indentation + xhtml;

+							}

+						}

+						return xhtml;

+					case nodeTypes.CDATA_SECTION_NODE:

+						return "<![CDA" + "TA[" + rootNode.nodeValue + "]" + "]>" + newLine;

+					case nodeTypes.DOCUMENT_NODE:

+						xhtml = "";

+						// Add output for childNodes collection (which doesn't include attribute nodes)

+						for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {

+							xhtml += getXhtml(rootNode.childNodes[i], true, indentation);

+						}

+						return xhtml;

+					default:

+						return "";

+				}

+			} else {

+				xhtml = "";

+				// Add output for childNodes collection (which doesn't include attribute nodes)

+				for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {

+					xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit);

+				}

+				return xhtml;

+			}

+		}

+

+		function createCommandLineFunctions() {

+			ConsoleAppender.addGlobalCommandLineFunction("$", function(appender, args, returnValue) {

+				return document.getElementById(args[0]);

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("dir", function(appender, args, returnValue) {

+				var lines = [];

+				for (var i = 0, len = args.length; i < len; i++) {

+					lines[i] = dir(args[i]);

+				}

+				return lines.join(newLine + newLine);

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("dirxml", function(appender, args, returnValue) {

+				var lines = [];

+				for (var i = 0, len = args.length; i < len; i++) {

+					var win = appender.getCommandWindow();

+					lines[i] = getXhtml(args[i]);

+				}

+				return lines.join(newLine + newLine);

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("cd", function(appender, args, returnValue) {

+				var win, message;

+				if (args.length === 0 || args[0] === "") {

+					win = window;

+					message = "Command line set to run in main window";

+				} else {

+					if (args[0].window == args[0]) {

+						win = args[0];

+						message = "Command line set to run in frame '" + args[0].name + "'";

+					} else {

+						win = window.frames[args[0]];

+						if (win) {

+							message = "Command line set to run in frame '" + args[0] + "'";

+						} else {

+							returnValue.isError = true;

+							message = "Frame '" + args[0] + "' does not exist";

+							win = appender.getCommandWindow();

+						}

+					}

+				}

+				appender.setCommandWindow(win);

+				return message;

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("clear", function(appender, args, returnValue) {

+				returnValue.appendResult = false;

+				appender.clear();

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("keys", function(appender, args, returnValue) {

+				var keys = [];

+				for (var k in args[0]) {

+					keys.push(k);

+				}

+				return keys;

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("values", function(appender, args, returnValue) {

+				var values = [];

+				for (var k in args[0]) {

+					try {

+						values.push(args[0][k]);

+					} catch (ex) {

+						logLog.warn("values(): Unable to obtain value for key " + k + ". Details: " + getExceptionMessage(ex));

+					}

+				}

+				return values;

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("expansionDepth", function(appender, args, returnValue) {

+				var expansionDepth = parseInt(args[0], 10);

+				if (isNaN(expansionDepth) || expansionDepth < 0) {

+					returnValue.isError = true;

+					return "" + args[0] + " is not a valid expansion depth";

+				} else {

+					appender.setCommandLineObjectExpansionDepth(expansionDepth);

+					return "Object expansion depth set to " + expansionDepth;

+				}

+			});

+		}

+

+		function init() {

+			// Add command line functions

+			createCommandLineFunctions();

+		}

+

+		/* ------------------------------------------------------------------ */

+

+		init();

+	})();

+

+	/* ---------------------------------------------------------------------- */

+	// Main load

+

+   log4javascript.setDocumentReady = function() {

+       pageLoaded = true;

+       log4javascript.dispatchEvent("load", {});

+   };

+

+    if (window.addEventListener) {

+        window.addEventListener("load", log4javascript.setDocumentReady, false);

+    } else if (window.attachEvent) {

+        window.attachEvent("onload", log4javascript.setDocumentReady);

+    } else {

+        var oldOnload = window.onload;

+        if (typeof window.onload != "function") {

+            window.onload = log4javascript.setDocumentReady;

+        } else {

+            window.onload = function(evt) {

+                if (oldOnload) {

+                    oldOnload(evt);

+                }

+                log4javascript.setDocumentReady();

+            };

+        }

+    }

+

+    // Ensure that the log4javascript object is available in the window. This

+    // is necessary for log4javascript to be available in IE if loaded using

+    // Dojo's module system

+    window.log4javascript = log4javascript;

+

+    return log4javascript;

+})();
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript.js b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript.js
new file mode 100644
index 0000000..eae582b
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript.js
@@ -0,0 +1,23 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+var log4javascript_stub=(function(){var log4javascript;function ff(){return function(){};}

+function copy(obj,props){for(var i in props){obj[i]=props[i];}}

+var f=ff();var Logger=ff();copy(Logger.prototype,{addChild:f,getEffectiveAppenders:f,invalidateAppenderCache:f,getAdditivity:f,setAdditivity:f,addAppender:f,removeAppender:f,removeAllAppenders:f,log:f,setLevel:f,getLevel:f,getEffectiveLevel:f,trace:f,debug:f,info:f,warn:f,error:f,fatal:f,isEnabledFor:f,isTraceEnabled:f,isDebugEnabled:f,isInfoEnabled:f,isWarnEnabled:f,isErrorEnabled:f,isFatalEnabled:f,callAppenders:f,group:f,groupEnd:f,time:f,timeEnd:f,assert:f,parent:new Logger()});var getLogger=function(){return new Logger();};function EventSupport(){}

+copy(EventSupport.prototype,{setEventTypes:f,addEventListener:f,removeEventListener:f,dispatchEvent:f,eventTypes:[],eventListeners:{}});function Log4JavaScript(){}

+Log4JavaScript.prototype=new EventSupport();log4javascript=new Log4JavaScript();log4javascript={isStub:true,version:"1.4.6",edition:"log4javascript",setDocumentReady:f,setEventTypes:f,addEventListener:f,removeEventListener:f,dispatchEvent:f,eventTypes:[],eventListeners:{},logLog:{setQuietMode:f,setAlertAllErrors:f,debug:f,displayDebug:f,warn:f,error:f},handleError:f,setEnabled:f,isEnabled:f,setTimeStampsInMilliseconds:f,isTimeStampsInMilliseconds:f,evalInScope:f,setShowStackTraces:f,getLogger:getLogger,getDefaultLogger:getLogger,getNullLogger:getLogger,getRootLogger:getLogger,resetConfiguration:f,Level:ff(),LoggingEvent:ff(),Layout:ff(),Appender:ff()};log4javascript.LoggingEvent.prototype={getThrowableStrRep:f,getCombinedMessages:f};log4javascript.Level.prototype={toString:f,equals:f,isGreaterOrEqual:f};var level=new log4javascript.Level();copy(log4javascript.Level,{ALL:level,TRACE:level,DEBUG:level,INFO:level,WARN:level,ERROR:level,FATAL:level,OFF:level});log4javascript.Layout.prototype={defaults:{},format:f,ignoresThrowable:f,getContentType:f,allowBatching:f,getDataValues:f,setKeys:f,setCustomField:f,hasCustomFields:f,setTimeStampsInMilliseconds:f,isTimeStampsInMilliseconds:f,getTimeStampValue:f,toString:f};log4javascript.SimpleDateFormat=ff();log4javascript.SimpleDateFormat.prototype={setMinimalDaysInFirstWeek:f,getMinimalDaysInFirstWeek:f,format:f};log4javascript.PatternLayout=ff();log4javascript.PatternLayout.prototype=new log4javascript.Layout();log4javascript.Appender=ff();log4javascript.Appender.prototype=new EventSupport();copy(log4javascript.Appender.prototype,{layout:new log4javascript.PatternLayout(),threshold:log4javascript.Level.ALL,loggers:[],doAppend:f,append:f,setLayout:f,getLayout:f,setThreshold:f,getThreshold:f,setAddedToLogger:f,setRemovedFromLogger:f,group:f,groupEnd:f,toString:f});log4javascript.SimpleLayout=ff();log4javascript.SimpleLayout.prototype=new log4javascript.Layout();log4javascript.NullLayout=ff();log4javascript.NullLayout.prototype=new log4javascript.Layout();log4javascript.XmlLayout=ff();log4javascript.XmlLayout.prototype=new log4javascript.Layout();copy(log4javascript.XmlLayout.prototype,{escapeCdata:f,isCombinedMessages:f});log4javascript.JsonLayout=ff();log4javascript.JsonLayout.prototype=new log4javascript.Layout();copy(log4javascript.JsonLayout.prototype,{isReadable:f,isCombinedMessages:f});log4javascript.HttpPostDataLayout=ff();log4javascript.HttpPostDataLayout.prototype=new log4javascript.Layout();log4javascript.PatternLayout=ff();log4javascript.PatternLayout.prototype=new log4javascript.Layout();log4javascript.AlertAppender=ff();log4javascript.AlertAppender.prototype=new log4javascript.Appender();log4javascript.BrowserConsoleAppender=ff();log4javascript.BrowserConsoleAppender.prototype=new log4javascript.Appender();log4javascript.AjaxAppender=ff();log4javascript.AjaxAppender.prototype=new log4javascript.Appender();copy(log4javascript.AjaxAppender.prototype,{getSessionId:f,setSessionId:f,isTimed:f,setTimed:f,getTimerInterval:f,setTimerInterval:f,isWaitForResponse:f,setWaitForResponse:f,getBatchSize:f,setBatchSize:f,isSendAllOnUnload:f,setSendAllOnUnload:f,setRequestSuccessCallback:f,setFailCallback:f,getPostVarName:f,setPostVarName:f,sendAll:f,sendAllRemaining:f,defaults:{requestSuccessCallback:null,failCallback:null}});function ConsoleAppender(){}

+ConsoleAppender.prototype=new log4javascript.Appender();copy(ConsoleAppender.prototype,{create:f,isNewestMessageAtTop:f,setNewestMessageAtTop:f,isScrollToLatestMessage:f,setScrollToLatestMessage:f,getWidth:f,setWidth:f,getHeight:f,setHeight:f,getMaxMessages:f,setMaxMessages:f,isShowCommandLine:f,setShowCommandLine:f,isShowHideButton:f,setShowHideButton:f,isShowCloseButton:f,setShowCloseButton:f,getCommandLineObjectExpansionDepth:f,setCommandLineObjectExpansionDepth:f,isInitiallyMinimized:f,setInitiallyMinimized:f,isUseDocumentWrite:f,setUseDocumentWrite:f,group:f,groupEnd:f,clear:f,focus:f,focusCommandLine:f,focusSearch:f,getCommandWindow:f,setCommandWindow:f,executeLastCommand:f,getCommandLayout:f,setCommandLayout:f,evalCommandAndAppend:f,addCommandLineFunction:f,storeCommandHistory:f,unload:f});ConsoleAppender.addGlobalCommandLineFunction=f;log4javascript.InPageAppender=ff();log4javascript.InPageAppender.prototype=new ConsoleAppender();copy(log4javascript.InPageAppender.prototype,{addCssProperty:f,hide:f,show:f,isVisible:f,close:f,defaults:{layout:new log4javascript.PatternLayout(),maxMessages:null}});log4javascript.InlineAppender=log4javascript.InPageAppender;log4javascript.PopUpAppender=ff();log4javascript.PopUpAppender.prototype=new ConsoleAppender();copy(log4javascript.PopUpAppender.prototype,{isUseOldPopUp:f,setUseOldPopUp:f,isComplainAboutPopUpBlocking:f,setComplainAboutPopUpBlocking:f,isFocusPopUp:f,setFocusPopUp:f,isReopenWhenClosed:f,setReopenWhenClosed:f,close:f,hide:f,show:f,defaults:{layout:new log4javascript.PatternLayout(),maxMessages:null}});return log4javascript;})();if(typeof window.log4javascript=="undefined"){var log4javascript=log4javascript_stub;}

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite.js b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite.js
new file mode 100644
index 0000000..7d2ea14
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite.js
@@ -0,0 +1,21 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+var log4javascript_stub=(function(){var log4javascript;function ff(){return function(){};}

+function copy(obj,props){for(var i in props){obj[i]=props[i];}}

+var f=ff();var Logger=ff();copy(Logger.prototype,{setLevel:f,getLevel:f,trace:f,debug:f,info:f,warn:f,error:f,fatal:f,isEnabledFor:f,isTraceEnabled:f,isDebugEnabled:f,isInfoEnabled:f,isWarnEnabled:f,isErrorEnabled:f,isFatalEnabled:f});var getLogger=function(){return new Logger();};function Log4JavaScript(){}

+log4javascript=new Log4JavaScript();log4javascript={isStub:true,version:"1.4.6",edition:"log4javascript_lite",setEnabled:f,isEnabled:f,setShowStackTraces:f,getDefaultLogger:getLogger,getLogger:getLogger,getNullLogger:getLogger,Level:ff(),LoggingEvent:ff(),Appender:ff()};log4javascript.LoggingEvent.prototype={getThrowableStrRep:f,getCombinedMessages:f};log4javascript.Level.prototype={toString:f,equals:f,isGreaterOrEqual:f};var level=new log4javascript.Level();copy(log4javascript.Level,{ALL:level,TRACE:level,DEBUG:level,INFO:level,WARN:level,ERROR:level,FATAL:level,OFF:level});log4javascript.Appender.prototype.append=f;return log4javascript;})();if(typeof window.log4javascript=="undefined"){var log4javascript=log4javascript_stub;}

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite_uncompressed.js
new file mode 100644
index 0000000..afb9ba7
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_lite_uncompressed.js
@@ -0,0 +1,102 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+var log4javascript_stub = (function() {

+	var log4javascript;

+

+	function ff() {

+		return function() {};

+	}

+	function copy(obj, props) {

+		for (var i in props) {

+			obj[i] = props[i];

+		}

+	}

+	var f = ff();

+

+	// Loggers

+	var Logger = ff();

+	copy(Logger.prototype, {

+		setLevel: f,

+		getLevel: f,

+		trace: f,

+		debug: f,

+		info: f,

+		warn: f,

+		error: f,

+		fatal: f,

+		isEnabledFor: f,

+		isTraceEnabled: f,

+		isDebugEnabled: f,

+		isInfoEnabled: f,

+		isWarnEnabled: f,

+		isErrorEnabled: f,

+		isFatalEnabled: f

+	});

+

+	var getLogger = function() {

+		return new Logger();

+	};

+

+	function Log4JavaScript() {}

+	log4javascript = new Log4JavaScript();

+

+	log4javascript = {

+		isStub: true,

+		version: "1.4.6",

+		edition: "log4javascript_lite",

+		setEnabled: f,

+		isEnabled: f,

+		setShowStackTraces: f,

+		getDefaultLogger: getLogger,

+		getLogger: getLogger,

+		getNullLogger: getLogger,

+		Level: ff(),

+		LoggingEvent: ff(),

+		Appender: ff()

+	};

+

+	// LoggingEvents

+	log4javascript.LoggingEvent.prototype = {

+		getThrowableStrRep: f,

+		getCombinedMessages: f

+	};

+

+	// Levels

+	log4javascript.Level.prototype = {

+		toString: f,

+		equals: f,

+		isGreaterOrEqual: f

+	};

+	var level = new log4javascript.Level();

+	copy(log4javascript.Level, {

+		ALL: level,

+		TRACE: level,

+		DEBUG: level,

+		INFO: level,

+		WARN: level,

+		ERROR: level,

+		FATAL: level,

+		OFF: level

+	});

+	

+	log4javascript.Appender.prototype.append = f;

+

+	return log4javascript;

+})();

+if (typeof window.log4javascript == "undefined") {

+	var log4javascript = log4javascript_stub;

+}

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production.js b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production.js
new file mode 100644
index 0000000..69a90a8
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production.js
@@ -0,0 +1,22 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+var log4javascript_stub=(function(){var log4javascript;function ff(){return function(){};}

+function copy(obj,props){for(var i in props){obj[i]=props[i];}}

+var f=ff();var Logger=ff();copy(Logger.prototype,{addChild:f,getEffectiveAppenders:f,invalidateAppenderCache:f,getAdditivity:f,setAdditivity:f,addAppender:f,removeAppender:f,removeAllAppenders:f,log:f,setLevel:f,getLevel:f,getEffectiveLevel:f,trace:f,debug:f,info:f,warn:f,error:f,fatal:f,isEnabledFor:f,isTraceEnabled:f,isDebugEnabled:f,isInfoEnabled:f,isWarnEnabled:f,isErrorEnabled:f,isFatalEnabled:f,callAppenders:f,group:f,groupEnd:f,time:f,timeEnd:f,assert:f,parent:new Logger()});var getLogger=function(){return new Logger();};function EventSupport(){}

+copy(EventSupport.prototype,{setEventTypes:f,addEventListener:f,removeEventListener:f,dispatchEvent:f,eventTypes:[],eventListeners:{}});function Log4JavaScript(){}

+Log4JavaScript.prototype=new EventSupport();log4javascript=new Log4JavaScript();log4javascript={isStub:true,version:"1.4.6",edition:"log4javascript_production",setDocumentReady:f,setEventTypes:f,addEventListener:f,removeEventListener:f,dispatchEvent:f,eventTypes:[],eventListeners:{},logLog:{setQuietMode:f,setAlertAllErrors:f,debug:f,displayDebug:f,warn:f,error:f},handleError:f,setEnabled:f,isEnabled:f,setTimeStampsInMilliseconds:f,isTimeStampsInMilliseconds:f,evalInScope:f,setShowStackTraces:f,getLogger:getLogger,getDefaultLogger:getLogger,getNullLogger:getLogger,getRootLogger:getLogger,resetConfiguration:f,Level:ff(),LoggingEvent:ff(),Layout:ff(),Appender:ff()};log4javascript.LoggingEvent.prototype={getThrowableStrRep:f,getCombinedMessages:f};log4javascript.Level.prototype={toString:f,equals:f,isGreaterOrEqual:f};var level=new log4javascript.Level();copy(log4javascript.Level,{ALL:level,TRACE:level,DEBUG:level,INFO:level,WARN:level,ERROR:level,FATAL:level,OFF:level});log4javascript.Layout.prototype={defaults:{},format:f,ignoresThrowable:f,getContentType:f,allowBatching:f,getDataValues:f,setKeys:f,setCustomField:f,hasCustomFields:f,setTimeStampsInMilliseconds:f,isTimeStampsInMilliseconds:f,getTimeStampValue:f,toString:f};log4javascript.SimpleDateFormat=ff();log4javascript.SimpleDateFormat.prototype={setMinimalDaysInFirstWeek:f,getMinimalDaysInFirstWeek:f,format:f};log4javascript.PatternLayout=ff();log4javascript.PatternLayout.prototype=new log4javascript.Layout();log4javascript.Appender=ff();log4javascript.Appender.prototype=new EventSupport();copy(log4javascript.Appender.prototype,{layout:new log4javascript.PatternLayout(),threshold:log4javascript.Level.ALL,loggers:[],doAppend:f,append:f,setLayout:f,getLayout:f,setThreshold:f,getThreshold:f,setAddedToLogger:f,setRemovedFromLogger:f,group:f,groupEnd:f,toString:f});log4javascript.SimpleLayout=ff();log4javascript.SimpleLayout.prototype=new log4javascript.Layout();log4javascript.NullLayout=ff();log4javascript.NullLayout.prototype=new log4javascript.Layout();log4javascript.XmlLayout=ff();log4javascript.XmlLayout.prototype=new log4javascript.Layout();copy(log4javascript.XmlLayout.prototype,{escapeCdata:f,isCombinedMessages:f});log4javascript.JsonLayout=ff();log4javascript.JsonLayout.prototype=new log4javascript.Layout();copy(log4javascript.JsonLayout.prototype,{isReadable:f,isCombinedMessages:f});log4javascript.HttpPostDataLayout=ff();log4javascript.HttpPostDataLayout.prototype=new log4javascript.Layout();log4javascript.PatternLayout=ff();log4javascript.PatternLayout.prototype=new log4javascript.Layout();log4javascript.AjaxAppender=ff();log4javascript.AjaxAppender.prototype=new log4javascript.Appender();copy(log4javascript.AjaxAppender.prototype,{getSessionId:f,setSessionId:f,isTimed:f,setTimed:f,getTimerInterval:f,setTimerInterval:f,isWaitForResponse:f,setWaitForResponse:f,getBatchSize:f,setBatchSize:f,isSendAllOnUnload:f,setSendAllOnUnload:f,setRequestSuccessCallback:f,setFailCallback:f,getPostVarName:f,setPostVarName:f,sendAll:f,sendAllRemaining:f,defaults:{requestSuccessCallback:null,failCallback:null}});return log4javascript;})();if(typeof window.log4javascript=="undefined"){var log4javascript=log4javascript_stub;}

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production_uncompressed.js
new file mode 100644
index 0000000..79eb7ca
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_production_uncompressed.js
@@ -0,0 +1,253 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+var log4javascript_stub = (function() {

+	var log4javascript;

+

+	function ff() {

+		return function() {};

+	}

+	function copy(obj, props) {

+		for (var i in props) {

+			obj[i] = props[i];

+		}

+	}

+	var f = ff();

+

+	// Loggers

+	var Logger = ff();

+	copy(Logger.prototype, {

+		addChild: f,

+		getEffectiveAppenders: f,

+		invalidateAppenderCache: f,

+		getAdditivity: f,

+		setAdditivity: f,

+		addAppender: f,

+		removeAppender: f,

+		removeAllAppenders: f,

+		log: f,

+		setLevel: f,

+		getLevel: f,

+		getEffectiveLevel: f,

+		trace: f,

+		debug: f,

+		info: f,

+		warn: f,

+		error: f,

+		fatal: f,

+		isEnabledFor: f,

+		isTraceEnabled: f,

+		isDebugEnabled: f,

+		isInfoEnabled: f,

+		isWarnEnabled: f,

+		isErrorEnabled: f,

+		isFatalEnabled: f,

+		callAppenders: f,

+		group: f,

+		groupEnd: f,

+		time: f,

+		timeEnd: f,

+		assert: f,

+		parent: new Logger()

+	});

+

+	var getLogger = function() {

+		return new Logger();

+	};

+

+	function EventSupport() {}

+

+	copy(EventSupport.prototype, {

+		setEventTypes: f,

+		addEventListener: f,

+		removeEventListener: f,

+		dispatchEvent: f,

+		eventTypes: [],

+		eventListeners: {}

+	});

+

+	function Log4JavaScript() {}

+	Log4JavaScript.prototype = new EventSupport();

+	log4javascript = new Log4JavaScript();

+

+	log4javascript = {

+		isStub: true,

+		version: "1.4.6",

+		edition: "log4javascript_production",

+        setDocumentReady: f,

+		setEventTypes: f,

+		addEventListener: f,

+		removeEventListener: f,

+		dispatchEvent: f,

+		eventTypes: [],

+		eventListeners: {},

+		logLog: {

+			setQuietMode: f,

+			setAlertAllErrors: f,

+			debug: f,

+			displayDebug: f,

+			warn: f,

+			error: f

+		},

+		handleError: f,

+		setEnabled: f,

+		isEnabled: f,

+		setTimeStampsInMilliseconds: f,

+		isTimeStampsInMilliseconds: f,

+		evalInScope: f,

+		setShowStackTraces: f,

+		getLogger: getLogger,

+		getDefaultLogger: getLogger,

+		getNullLogger: getLogger,

+		getRootLogger: getLogger,

+		resetConfiguration: f,

+		Level: ff(),

+		LoggingEvent: ff(),

+		Layout: ff(),

+		Appender: ff()

+	};

+

+	// LoggingEvents

+	log4javascript.LoggingEvent.prototype = {

+		getThrowableStrRep: f,

+		getCombinedMessages: f

+	};

+

+	// Levels

+	log4javascript.Level.prototype = {

+		toString: f,

+		equals: f,

+		isGreaterOrEqual: f

+	};

+	var level = new log4javascript.Level();

+	copy(log4javascript.Level, {

+		ALL: level,

+		TRACE: level,

+		DEBUG: level,

+		INFO: level,

+		WARN: level,

+		ERROR: level,

+		FATAL: level,

+		OFF: level

+	});

+

+	// Layouts

+	log4javascript.Layout.prototype = {

+		defaults: {},

+		format: f,

+		ignoresThrowable: f,

+		getContentType: f,

+		allowBatching: f,

+		getDataValues: f,

+		setKeys: f,

+		setCustomField: f,

+		hasCustomFields: f,

+		setTimeStampsInMilliseconds: f,

+		isTimeStampsInMilliseconds: f,

+		getTimeStampValue: f,

+		toString: f

+	};

+

+	// PatternLayout related

+	log4javascript.SimpleDateFormat = ff();

+	log4javascript.SimpleDateFormat.prototype = {

+		setMinimalDaysInFirstWeek: f,

+		getMinimalDaysInFirstWeek: f,

+		format: f

+	};

+

+	// PatternLayout

+	log4javascript.PatternLayout = ff();

+	log4javascript.PatternLayout.prototype = new log4javascript.Layout();

+

+	// Appenders

+	log4javascript.Appender = ff();

+	log4javascript.Appender.prototype = new EventSupport();

+

+	copy(log4javascript.Appender.prototype, {

+		layout: new log4javascript.PatternLayout(),

+		threshold: log4javascript.Level.ALL,

+		loggers: [],

+		doAppend: f,

+		append: f,

+		setLayout: f,

+		getLayout: f,

+		setThreshold: f,

+		getThreshold: f,

+		setAddedToLogger: f,

+		setRemovedFromLogger: f,

+		group: f,

+		groupEnd: f,

+		toString: f

+	});

+	// SimpleLayout

+	log4javascript.SimpleLayout = ff();

+	log4javascript.SimpleLayout.prototype = new log4javascript.Layout();

+	// NullLayout

+	log4javascript.NullLayout = ff();

+	log4javascript.NullLayout.prototype = new log4javascript.Layout();

+	// ZmlLayout

+	log4javascript.XmlLayout = ff();

+	log4javascript.XmlLayout.prototype = new log4javascript.Layout();

+	copy(log4javascript.XmlLayout.prototype, {

+		escapeCdata: f,

+		isCombinedMessages: f

+	});

+	// JsonLayout

+	log4javascript.JsonLayout = ff();

+	log4javascript.JsonLayout.prototype = new log4javascript.Layout();

+	copy(log4javascript.JsonLayout.prototype, {

+		isReadable: f,

+		isCombinedMessages: f

+	});

+	// HttpPostDataLayout 

+	log4javascript.HttpPostDataLayout = ff();

+	log4javascript.HttpPostDataLayout.prototype = new log4javascript.Layout();

+	// PatternLayout

+	log4javascript.PatternLayout = ff();

+	log4javascript.PatternLayout.prototype = new log4javascript.Layout();

+	// AjaxAppender

+	log4javascript.AjaxAppender = ff();

+	log4javascript.AjaxAppender.prototype = new log4javascript.Appender();

+	copy(log4javascript.AjaxAppender.prototype, {

+		getSessionId: f,

+		setSessionId: f,

+		isTimed: f,

+		setTimed: f,

+		getTimerInterval: f,

+		setTimerInterval: f,

+		isWaitForResponse: f,

+		setWaitForResponse: f,

+		getBatchSize: f,

+		setBatchSize: f,

+		isSendAllOnUnload: f,

+		setSendAllOnUnload: f,

+		setRequestSuccessCallback: f,

+		setFailCallback: f,

+		getPostVarName: f,

+		setPostVarName: f,

+		sendAll: f,

+		sendAllRemaining: f,

+		defaults: {

+			requestSuccessCallback: null,

+			failCallback: null

+		}

+	});

+	return log4javascript;

+})();

+if (typeof window.log4javascript == "undefined") {

+	var log4javascript = log4javascript_stub;

+}

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_uncompressed.js
new file mode 100644
index 0000000..1976fbc
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/stubs/log4javascript_uncompressed.js
@@ -0,0 +1,341 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+var log4javascript_stub = (function() {

+	var log4javascript;

+

+	function ff() {

+		return function() {};

+	}

+	function copy(obj, props) {

+		for (var i in props) {

+			obj[i] = props[i];

+		}

+	}

+	var f = ff();

+

+	// Loggers

+	var Logger = ff();

+	copy(Logger.prototype, {

+		addChild: f,

+		getEffectiveAppenders: f,

+		invalidateAppenderCache: f,

+		getAdditivity: f,

+		setAdditivity: f,

+		addAppender: f,

+		removeAppender: f,

+		removeAllAppenders: f,

+		log: f,

+		setLevel: f,

+		getLevel: f,

+		getEffectiveLevel: f,

+		trace: f,

+		debug: f,

+		info: f,

+		warn: f,

+		error: f,

+		fatal: f,

+		isEnabledFor: f,

+		isTraceEnabled: f,

+		isDebugEnabled: f,

+		isInfoEnabled: f,

+		isWarnEnabled: f,

+		isErrorEnabled: f,

+		isFatalEnabled: f,

+		callAppenders: f,

+		group: f,

+		groupEnd: f,

+		time: f,

+		timeEnd: f,

+		assert: f,

+		parent: new Logger()

+	});

+

+	var getLogger = function() {

+		return new Logger();

+	};

+

+	function EventSupport() {}

+

+	copy(EventSupport.prototype, {

+		setEventTypes: f,

+		addEventListener: f,

+		removeEventListener: f,

+		dispatchEvent: f,

+		eventTypes: [],

+		eventListeners: {}

+	});

+

+	function Log4JavaScript() {}

+	Log4JavaScript.prototype = new EventSupport();

+	log4javascript = new Log4JavaScript();

+

+	log4javascript = {

+		isStub: true,

+		version: "1.4.6",

+		edition: "log4javascript",

+        setDocumentReady: f,

+		setEventTypes: f,

+		addEventListener: f,

+		removeEventListener: f,

+		dispatchEvent: f,

+		eventTypes: [],

+		eventListeners: {},

+		logLog: {

+			setQuietMode: f,

+			setAlertAllErrors: f,

+			debug: f,

+			displayDebug: f,

+			warn: f,

+			error: f

+		},

+		handleError: f,

+		setEnabled: f,

+		isEnabled: f,

+		setTimeStampsInMilliseconds: f,

+		isTimeStampsInMilliseconds: f,

+		evalInScope: f,

+		setShowStackTraces: f,

+		getLogger: getLogger,

+		getDefaultLogger: getLogger,

+		getNullLogger: getLogger,

+		getRootLogger: getLogger,

+		resetConfiguration: f,

+		Level: ff(),

+		LoggingEvent: ff(),

+		Layout: ff(),

+		Appender: ff()

+	};

+

+	// LoggingEvents

+	log4javascript.LoggingEvent.prototype = {

+		getThrowableStrRep: f,

+		getCombinedMessages: f

+	};

+

+	// Levels

+	log4javascript.Level.prototype = {

+		toString: f,

+		equals: f,

+		isGreaterOrEqual: f

+	};

+	var level = new log4javascript.Level();

+	copy(log4javascript.Level, {

+		ALL: level,

+		TRACE: level,

+		DEBUG: level,

+		INFO: level,

+		WARN: level,

+		ERROR: level,

+		FATAL: level,

+		OFF: level

+	});

+

+	// Layouts

+	log4javascript.Layout.prototype = {

+		defaults: {},

+		format: f,

+		ignoresThrowable: f,

+		getContentType: f,

+		allowBatching: f,

+		getDataValues: f,

+		setKeys: f,

+		setCustomField: f,

+		hasCustomFields: f,

+		setTimeStampsInMilliseconds: f,

+		isTimeStampsInMilliseconds: f,

+		getTimeStampValue: f,

+		toString: f

+	};

+

+	// PatternLayout related

+	log4javascript.SimpleDateFormat = ff();

+	log4javascript.SimpleDateFormat.prototype = {

+		setMinimalDaysInFirstWeek: f,

+		getMinimalDaysInFirstWeek: f,

+		format: f

+	};

+

+	// PatternLayout

+	log4javascript.PatternLayout = ff();

+	log4javascript.PatternLayout.prototype = new log4javascript.Layout();

+

+	// Appenders

+	log4javascript.Appender = ff();

+	log4javascript.Appender.prototype = new EventSupport();

+

+	copy(log4javascript.Appender.prototype, {

+		layout: new log4javascript.PatternLayout(),

+		threshold: log4javascript.Level.ALL,

+		loggers: [],

+		doAppend: f,

+		append: f,

+		setLayout: f,

+		getLayout: f,

+		setThreshold: f,

+		getThreshold: f,

+		setAddedToLogger: f,

+		setRemovedFromLogger: f,

+		group: f,

+		groupEnd: f,

+		toString: f

+	});

+	// SimpleLayout

+	log4javascript.SimpleLayout = ff();

+	log4javascript.SimpleLayout.prototype = new log4javascript.Layout();

+	// NullLayout

+	log4javascript.NullLayout = ff();

+	log4javascript.NullLayout.prototype = new log4javascript.Layout();

+	// ZmlLayout

+	log4javascript.XmlLayout = ff();

+	log4javascript.XmlLayout.prototype = new log4javascript.Layout();

+	copy(log4javascript.XmlLayout.prototype, {

+		escapeCdata: f,

+		isCombinedMessages: f

+	});

+	// JsonLayout

+	log4javascript.JsonLayout = ff();

+	log4javascript.JsonLayout.prototype = new log4javascript.Layout();

+	copy(log4javascript.JsonLayout.prototype, {

+		isReadable: f,

+		isCombinedMessages: f

+	});

+	// HttpPostDataLayout 

+	log4javascript.HttpPostDataLayout = ff();

+	log4javascript.HttpPostDataLayout.prototype = new log4javascript.Layout();

+	// PatternLayout

+	log4javascript.PatternLayout = ff();

+	log4javascript.PatternLayout.prototype = new log4javascript.Layout();

+	// AlertAppender

+	log4javascript.AlertAppender = ff();

+	log4javascript.AlertAppender.prototype = new log4javascript.Appender();

+	// BrowserConsoleAppender

+	log4javascript.BrowserConsoleAppender = ff();

+	log4javascript.BrowserConsoleAppender.prototype = new log4javascript.Appender();

+	// AjaxAppender

+	log4javascript.AjaxAppender = ff();

+	log4javascript.AjaxAppender.prototype = new log4javascript.Appender();

+	copy(log4javascript.AjaxAppender.prototype, {

+		getSessionId: f,

+		setSessionId: f,

+		isTimed: f,

+		setTimed: f,

+		getTimerInterval: f,

+		setTimerInterval: f,

+		isWaitForResponse: f,

+		setWaitForResponse: f,

+		getBatchSize: f,

+		setBatchSize: f,

+		isSendAllOnUnload: f,

+		setSendAllOnUnload: f,

+		setRequestSuccessCallback: f,

+		setFailCallback: f,

+		getPostVarName: f,

+		setPostVarName: f,

+		sendAll: f,

+		sendAllRemaining: f,

+		defaults: {

+			requestSuccessCallback: null,

+			failCallback: null

+		}

+	});

+	// ConsoleAppender

+	function ConsoleAppender() {}

+	ConsoleAppender.prototype = new log4javascript.Appender();

+	copy(ConsoleAppender.prototype, {

+		create: f,

+		isNewestMessageAtTop: f,

+		setNewestMessageAtTop: f,

+		isScrollToLatestMessage: f,

+		setScrollToLatestMessage: f,

+		getWidth: f,

+		setWidth: f,

+		getHeight: f,

+		setHeight: f,

+		getMaxMessages: f,

+		setMaxMessages: f,

+		isShowCommandLine: f,

+		setShowCommandLine: f,

+		isShowHideButton: f,

+		setShowHideButton: f,

+		isShowCloseButton: f,

+		setShowCloseButton: f,

+		getCommandLineObjectExpansionDepth: f,

+		setCommandLineObjectExpansionDepth: f,

+		isInitiallyMinimized: f,

+		setInitiallyMinimized: f,

+		isUseDocumentWrite: f,

+		setUseDocumentWrite: f,

+		group: f,

+		groupEnd: f,

+		clear: f,

+		focus: f,

+		focusCommandLine: f,

+		focusSearch: f,

+		getCommandWindow: f,

+		setCommandWindow: f,

+		executeLastCommand: f,

+		getCommandLayout: f,

+		setCommandLayout: f,

+		evalCommandAndAppend: f,

+		addCommandLineFunction: f,

+		storeCommandHistory: f,

+		unload: f

+	});

+

+	ConsoleAppender.addGlobalCommandLineFunction = f;

+

+	// InPageAppender

+	log4javascript.InPageAppender = ff();

+	log4javascript.InPageAppender.prototype = new ConsoleAppender();

+	copy(log4javascript.InPageAppender.prototype, {

+		addCssProperty: f,

+		hide: f,

+		show: f,

+		isVisible: f,

+		close: f,

+		defaults: {

+			layout: new log4javascript.PatternLayout(),

+			maxMessages: null

+		}

+	});

+	log4javascript.InlineAppender = log4javascript.InPageAppender;

+

+	// PopUpAppender

+	log4javascript.PopUpAppender = ff();

+	log4javascript.PopUpAppender.prototype = new ConsoleAppender();

+	copy(log4javascript.PopUpAppender.prototype, {

+		isUseOldPopUp: f,

+		setUseOldPopUp: f,

+		isComplainAboutPopUpBlocking: f,

+		setComplainAboutPopUpBlocking: f,

+		isFocusPopUp: f,

+		setFocusPopUp: f,

+		isReopenWhenClosed: f,

+		setReopenWhenClosed: f,

+		close: f,

+		hide: f,

+		show: f,

+		defaults: {

+			layout: new log4javascript.PatternLayout(),

+			maxMessages: null

+		}

+	});

+	return log4javascript;

+})();

+if (typeof window.log4javascript == "undefined") {

+	var log4javascript = log4javascript_stub;

+}

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript.js b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript.js
new file mode 100644
index 0000000..89fd903
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript.js
@@ -0,0 +1,32 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+function array_contains(arr,val){for(var i=0;i<arr.length;i++){if(arr[i]==val){return true;}}

+return false;}

+function compareObjectInterface(obj1,obj1_name,obj2,obj2_name,namePrefix){if(!namePrefix){namePrefix="";}

+var obj1PropertyNames=new Array();for(var i in obj1){if(i!="prototype"&&i!="arguments"){obj1PropertyNames.push(i);}}

+if(obj1&&obj1.prototype&&!array_contains(obj1PropertyNames,"prototype")){}

+for(var j=0;j<obj1PropertyNames.length;j++){var propertyName=obj1PropertyNames[j];if((typeof obj1[propertyName]=="function"||typeof obj1[propertyName]=="object")&&!(obj1[propertyName]instanceof Array)){var propertyFullyQualifiedName=(namePrefix=="")?propertyName:namePrefix+"."+propertyName;try{if(typeof obj2[propertyName]=="undefined"){throw new Error(obj2_name+" does not contain "+propertyFullyQualifiedName+" in "+obj1_name);}else if(typeof obj2[propertyName]!=typeof obj1[propertyName]){throw new Error(obj2_name+"'s "+propertyFullyQualifiedName+" is of the wrong type: "+typeof obj2[propertyName]+" when it is type "+typeof obj1[propertyName]+" in "+obj1_name);}else if(obj1[propertyName]!=Function.prototype.apply){if(!compareObjectInterface(obj1[propertyName],obj1_name,obj2[propertyName],obj2_name,propertyFullyQualifiedName)){throw new Error("Interfaces don't match");}}}catch(ex){throw new Error("Exception while checking property name "+propertyFullyQualifiedName+" in "+obj2_name+": "+ex.message);}}}

+return true;};var testLayoutWithVariables=function(layout,t){var emptyObject={};var emptyArray=[];var emptyString="";var localUndefined=emptyArray[0];var oneLevelObject={"name":"One-level object"};var twoLevelObject={"name":"Two-level object","data":oneLevelObject};var threeLevelObject={"name":"Three-level object","data":twoLevelObject};var anArray=[3,"stuff",true,false,0,null,localUndefined,3.14,function(p){return"I'm a function";},[1,"things"]];var arrayOfTestItems=[emptyObject,emptyString,emptyString,localUndefined,oneLevelObject,twoLevelObject,threeLevelObject,anArray];t.log("Testing layout "+layout)

+for(var i=0;i<arrayOfTestItems.length;i++){var ex=new Error("Test error");var loggingEvent=new log4javascript.LoggingEvent(t.logger,new Date(),log4javascript.Level.INFO,[arrayOfTestItems[i]],null);t.log("Formatting",arrayOfTestItems[i],result);var result=layout.format(loggingEvent);loggingEvent.exception=ex;t.log("Formatting with exception",arrayOfTestItems[i],result);result=layout.format(loggingEvent);}};xn.test.enableTestDebug=true;xn.test.enable_log4javascript=false;xn.test.suite("log4javascript tests",function(s){log4javascript.logLog.setQuietMode(true);var ArrayAppender=function(layout){if(layout){this.setLayout(layout);}

+this.logMessages=[];};ArrayAppender.prototype=new log4javascript.Appender();ArrayAppender.prototype.layout=new log4javascript.NullLayout();ArrayAppender.prototype.append=function(loggingEvent){var formattedMessage=this.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();}

+this.logMessages.push(formattedMessage);};ArrayAppender.prototype.toString=function(){return"[ArrayAppender]";};s.setUp=function(t){t.logger=log4javascript.getLogger("test");t.logger.removeAllAppenders();t.appender=new ArrayAppender();t.logger.addAppender(t.appender);};s.tearDown=function(t){t.logger.removeAppender(t.appender);log4javascript.resetConfiguration();};s.test("Stub script interface test",function(t){try{compareObjectInterface(log4javascript,"log4javascript",log4javascript_stub,"log4javascript_stub");}catch(ex){t.fail(ex);}});s.test("Disable log4javascript test",function(t){log4javascript.setEnabled(false);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,0);log4javascript.setEnabled(true);});s.test("Array.splice test 1",function(t){var a=["Marlon","Ashley","Darius","Lloyd"];var deletedItems=a.splice(1,2);t.assertEquals(a.join(","),"Marlon,Lloyd");t.assertEquals(deletedItems.join(","),"Ashley,Darius");});s.test("Array.splice test 2",function(t){var a=["Marlon","Ashley","Darius","Lloyd"];var deletedItems=a.splice(1,1,"Malky","Jay");t.assertEquals(a.join(","),"Marlon,Malky,Jay,Darius,Lloyd");t.assertEquals(deletedItems.join(","),"Ashley");});s.test("array_remove test",function(t){var array_remove=log4javascript.evalInScope("array_remove");var a=["Marlon","Ashley","Darius"];array_remove(a,"Darius");t.assertEquals(a.join(","),"Marlon,Ashley");});s.test("array_remove with empty array test",function(t){var array_remove=log4javascript.evalInScope("array_remove");var a=[];array_remove(a,"Darius");t.assertEquals(a.join(","),"");});s.test("Logger logging test",function(t){t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,1);});s.test("Logger levels test",function(t){var originalLevel=t.logger.getEffectiveLevel();t.logger.setLevel(log4javascript.Level.INFO);t.logger.debug("TEST");t.logger.setLevel(originalLevel);t.assertEquals(t.appender.logMessages.length,0);});s.test("Logger getEffectiveLevel inheritance test 1",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");parentLogger.setLevel(log4javascript.Level.ERROR);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.ERROR);});s.test("Logger getEffectiveLevel inheritance test 2",function(t){var grandParentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2.test3");grandParentLogger.setLevel(log4javascript.Level.ERROR);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.ERROR);});s.test("Logger getEffectiveLevel inheritance test 3",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");parentLogger.setLevel(log4javascript.Level.ERROR);childLogger.setLevel(log4javascript.Level.INFO);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.INFO);});s.test("Logger getEffectiveLevel root inheritance test",function(t){var rootLogger=log4javascript.getRootLogger();var childLogger=log4javascript.getLogger("test1.test2.test3");rootLogger.setLevel(log4javascript.Level.WARN);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.WARN);});s.test("Logger null level test",function(t){t.logger.setLevel(null);t.assertEquals(t.logger.getEffectiveLevel(),log4javascript.Level.DEBUG);});s.test("Logger appender additivity test 1",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");var parentLoggerAppender=new ArrayAppender();var childLoggerAppender=new ArrayAppender();parentLogger.addAppender(parentLoggerAppender);childLogger.addAppender(childLoggerAppender);parentLogger.info("Parent logger test message");childLogger.info("Child logger test message");t.assertEquals(parentLoggerAppender.logMessages.length,2);t.assertEquals(childLoggerAppender.logMessages.length,1);});s.test("Logger appender additivity test 2",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");var parentLoggerAppender=new ArrayAppender();var childLoggerAppender=new ArrayAppender();parentLogger.addAppender(parentLoggerAppender);childLogger.addAppender(childLoggerAppender);childLogger.setAdditivity(false);parentLogger.info("Parent logger test message");childLogger.info("Child logger test message");t.assertEquals(parentLoggerAppender.logMessages.length,1);t.assertEquals(childLoggerAppender.logMessages.length,1);});s.test("Logger appender additivity test 3",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");var parentLoggerAppender=new ArrayAppender();var childLoggerAppender=new ArrayAppender();parentLogger.addAppender(parentLoggerAppender);childLogger.addAppender(childLoggerAppender);childLogger.setAdditivity(false);parentLogger.info("Parent logger test message");childLogger.info("Child logger test message");childLogger.setAdditivity(true);childLogger.info("Child logger test message 2");t.assertEquals(parentLoggerAppender.logMessages.length,2);t.assertEquals(childLoggerAppender.logMessages.length,2);});s.test("Appender threshold test",function(t){t.appender.setThreshold(log4javascript.Level.INFO);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,0);});s.test("Basic appender / layout test",function(t){t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"TEST");});s.test("Appender uniqueness within logger test",function(t){t.logger.addAppender(t.appender);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,1);});s.test("Logger remove appender test",function(t){t.logger.debug("TEST");t.logger.removeAppender(t.appender);t.logger.debug("TEST AGAIN");t.assertEquals(t.appender.logMessages.length,1);});s.test("",function(t){t.logger.debug("TEST");t.logger.removeAppender(t.appender);t.logger.debug("TEST AGAIN");t.assertEquals(t.appender.logMessages.length,1);});s.test("SimpleLayout format test",function(t){var layout=new log4javascript.SimpleLayout();testLayoutWithVariables(layout,t);});s.test("SimpleLayout test",function(t){t.appender.setLayout(new log4javascript.SimpleLayout());t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"DEBUG - TEST");});s.test("NullLayout format test",function(t){var layout=new log4javascript.NullLayout();testLayoutWithVariables(layout,t);});s.test("NullLayout test",function(t){t.appender.setLayout(new log4javascript.NullLayout());t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"TEST");});s.test("XmlLayout format test",function(t){var layout=new log4javascript.XmlLayout();testLayoutWithVariables(layout,t);});s.test("XmlLayout test",function(t){t.appender.setLayout(new log4javascript.XmlLayout());t.logger.debug("TEST");t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<\/log4javascript:event>\s*$/,t.appender.logMessages[0]);});s.test("XmlLayout with exception test",function(t){t.appender.setLayout(new log4javascript.XmlLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<log4javascript:exception>\s*<!\[CDATA\[.*\]\]><\/log4javascript:exception>\s*<\/log4javascript:event>\s*$/,t.appender.logMessages[0]);});var setUpXmlLayoutMillisecondsTest=function(t){t.date=new Date();t.timeInMilliseconds=t.date.getTime();t.timeInSeconds=Math.floor(t.timeInMilliseconds/1000);t.milliseconds=t.date.getMilliseconds();t.loggingEvent=new log4javascript.LoggingEvent(t.logger,t.date,log4javascript.Level.DEBUG,["TEST"],null);t.layout=new log4javascript.XmlLayout();}

+s.test("XmlLayout seconds/milliseconds test 1",function(t){setUpXmlLayoutMillisecondsTest(t);var regex=new RegExp('^<log4javascript:event logger="test" timestamp="'+t.timeInMilliseconds+'" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');t.assertRegexMatches(regex,t.layout.format(t.loggingEvent));});s.test("XmlLayout seconds/milliseconds test 2",function(t){setUpXmlLayoutMillisecondsTest(t);log4javascript.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);log4javascript.setTimeStampsInMilliseconds(true);var regex=new RegExp('^<log4javascript:event logger="test" timestamp="'+t.timeInSeconds+'" milliseconds="'+t.milliseconds+'" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');t.assertRegexMatches(regex,formatted);});s.test("XmlLayout seconds/milliseconds test 3",function(t){setUpXmlLayoutMillisecondsTest(t);t.layout.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);var regex=new RegExp('^<log4javascript:event logger="test" timestamp="'+t.timeInSeconds+'" milliseconds="'+t.milliseconds+'" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');t.assertRegexMatches(regex,formatted);});s.test("escapeNewLines test",function(t){var escapeNewLines=log4javascript.evalInScope("escapeNewLines");var str="1\r2\n3\n4\r\n5\r6\r\n7";t.assertEquals(escapeNewLines(str),"1\\r\\n2\\r\\n3\\r\\n4\\r\\n5\\r\\n6\\r\\n7");});s.test("JsonLayout format test",function(t){var layout=new log4javascript.JsonLayout();testLayoutWithVariables(layout,t);});s.test("JsonLayout test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST");t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST"}$/,t.appender.logMessages[0]);});s.test("JsonLayout JSON validity test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST");eval("var o = "+t.appender.logMessages[0]);t.assertEquals(o.message,"TEST");});s.test("JsonLayout with number type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug(15);t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":15}$/,t.appender.logMessages[0]);});s.test("JsonLayout with object type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug({});t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"\[object Object\]"}$/,t.appender.logMessages[0]);});s.test("JsonLayout with boolean type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug(false);t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":false}$/,t.appender.logMessages[0]);});s.test("JsonLayout with quote test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TE\"S\"T");t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TE\\"S\\"T"}$/,t.appender.logMessages[0]);});s.test("JsonLayout with exception test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST","exception":.*}$/,t.appender.logMessages[0]);});var setUpJsonLayoutMillisecondsTest=function(t){t.date=new Date();t.timeInMilliseconds=t.date.getTime();t.timeInSeconds=Math.floor(t.timeInMilliseconds/1000);t.milliseconds=t.date.getMilliseconds();t.loggingEvent=new log4javascript.LoggingEvent(t.logger,t.date,log4javascript.Level.DEBUG,["TEST"],null);t.layout=new log4javascript.JsonLayout();};s.test("JsonLayout seconds/milliseconds test 1",function(t){setUpJsonLayoutMillisecondsTest(t);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInMilliseconds+',"level":"DEBUG","url":".*","message":"TEST"}$');t.assertRegexMatches(regex,t.layout.format(t.loggingEvent));});s.test("JsonLayout seconds/milliseconds test 2",function(t){setUpJsonLayoutMillisecondsTest(t);log4javascript.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);log4javascript.setTimeStampsInMilliseconds(true);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInSeconds+',"level":"DEBUG","url":".*","message":"TEST","milliseconds":'+t.milliseconds+'}$');t.assertRegexMatches(regex,formatted);});s.test("JsonLayout seconds/milliseconds test 3",function(t){setUpJsonLayoutMillisecondsTest(t);t.layout.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInSeconds+',"level":"DEBUG","url":".*","message":"TEST","milliseconds":'+t.milliseconds+'}$');t.assertRegexMatches(regex,formatted);});s.test("HttpPostDataLayout format test",function(t){var layout=new log4javascript.HttpPostDataLayout();testLayoutWithVariables(layout,t);});s.test("HttpPostDataLayout test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST");t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST$/,t.appender.logMessages[0]);});s.test("HttpPostDataLayout URL encoding test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST +\"1\"");t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST%20%2B%221%22$/,t.appender.logMessages[0]);});s.test("HttpPostDataLayout with exception test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST&exception=.*$/,t.appender.logMessages[0]);});(function(){var formatObjectExpansion=log4javascript.evalInScope("formatObjectExpansion");var newLine=log4javascript.evalInScope("newLine");var arr=[null,undefined,1.2,"A string",[1,"test"],{a:{b:1}}];s.test("Basic formatObjectExpansion array test (depth: 1)",function(t){t.assertEquals(formatObjectExpansion(arr,1),"["+newLine+"  null,"+newLine+"  undefined,"+newLine+"  1.2,"+newLine+"  A string,"+newLine+"  1,test,"+newLine+"  [object Object]"+newLine+"]");});s.test("Basic formatObjectExpansion array test (depth: 2)",function(t){t.assertEquals(formatObjectExpansion(arr,2),"["+newLine+"  null,"+newLine+"  undefined,"+newLine+"  1.2,"+newLine+"  A string,"+newLine+"  ["+newLine+"    1,"+newLine+"    test"+newLine+"  ],"+newLine+"  {"+newLine+"    a: [object Object]"+newLine+"  }"+newLine+"]");});s.test("formatObjectExpansion simple object test",function(t){var obj={STRING:"A string"};t.assertEquals(formatObjectExpansion(obj,1),"{"+newLine+"  STRING: A string"+newLine+"}");});s.test("formatObjectExpansion simple circular object test",function(t){var obj={};obj.a=obj;t.assertEquals(formatObjectExpansion(obj,2),"{"+newLine+"  a: [object Object] [already expanded]"+newLine+"}");});})();var getSampleDate=function(){var date=new Date();date.setFullYear(2006);date.setMonth(7);date.setDate(30);date.setHours(15);date.setMinutes(38);date.setSeconds(45);return date;};s.test("String.replace test",function(t){t.assertEquals("Hello world".replace(/o/g,"Z"),"HellZ wZrld");});s.test("PatternLayout format test",function(t){var layout=new log4javascript.PatternLayout();testLayoutWithVariables(layout,t);});s.test("PatternLayout dates test",function(t){var layout=new log4javascript.PatternLayout("%d %d{DATE} %d{HH:ss}");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertRegexMatches(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2},\d{3} \d{2}:\d{2}$/,t.appender.logMessages[0]);});s.test("PatternLayout modifiers test",function(t){var layout=new log4javascript.PatternLayout("%m|%3m|%-3m|%6m|%-6m|%.2m|%1.2m|%6.8m|%-1.2m|%-6.8m|");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"TEST|TEST|TEST|  TEST|TEST  |ST|ST|  TEST|ST|TEST  |");});s.test("PatternLayout conversion characters test",function(t){var layout=new log4javascript.PatternLayout("%c %n %p %r literal %%");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertRegexMatches(/^test \s+ DEBUG \d+ literal %$/,t.appender.logMessages[0]);});s.test("PatternLayout message test",function(t){var layout=new log4javascript.PatternLayout("%m{1} %m{2}");t.appender.setLayout(layout);var testObj={strikers:{quick:"Marlon"}};t.logger.debug(testObj);t.assertEquals("{\r\n  strikers: [object Object]\r\n} {\r\n\  strikers: {\r\n    quick: Marlon\r\n  }\r\n}",t.appender.logMessages[0]);});s.test("Logging/grouping test",function(t){var browserConsoleAppender=new log4javascript.BrowserConsoleAppender();t.logger.addAppender(browserConsoleAppender);t.logger.trace("TEST TRACE");t.logger.debug("TEST DEBUG");t.logger.info("TEST INFO");t.logger.warn("TEST WARN");t.logger.error("TEST ERROR");t.logger.fatal("TEST FATAL");t.logger.fatal("TEST FATAL",new Error("Fake error"));t.logger.info("TEST INFO","Second message",["a","b","c"]);t.logger.group("TEST GROUP");t.logger.info("TEST INFO");t.logger.groupEnd("TEST GROUP");t.logger.info("TEST INFO");t.logger.removeAppender(browserConsoleAppender);});var testConsoleAppender=function(t,appender){var timeoutCallback=function(){return(windowLoaded?"Timed out while waiting for messages to appear":"Timed out while waiting for window to load")+". Debug messages: "+

+log4javascript.logLog.debugMessages.join("\r\n");}

+t.async(60000,timeoutCallback);var windowLoaded=false;var domChecked=false;var onLoadHandler=function(){log4javascript.logLog.debug("onLoadHandler");windowLoaded=true;var win=appender.getConsoleWindow();if(win&&win.loaded){var checkDom=function(){log4javascript.logLog.debug("checkDom");domChecked=true;var logContainer=win.logMainContainer;if(logContainer.hasChildNodes()){if(logContainer.innerHTML.indexOf("TEST MESSAGE")==-1){appender.close();t.fail("Log message not correctly logged (log container innerHTML: "+logContainer.innerHTML+")");}else{t.assert(appender.isVisible());appender.close();t.assert(!appender.isVisible());t.succeed();}}else{appender.close();t.fail("Console has no log messages");}}

+window.setTimeout(checkDom,300);}else{appender.close();t.fail("Console mistakenly raised load event");}}

+appender.addEventListener("load",onLoadHandler);t.logger.addAppender(appender);t.logger.debug("TEST MESSAGE");};s.test("InlineAppender test",function(t){var inlineAppender=new log4javascript.InlineAppender();inlineAppender.setInitiallyMinimized(false);inlineAppender.setNewestMessageAtTop(false);inlineAppender.setScrollToLatestMessage(true);inlineAppender.setWidth(600);inlineAppender.setHeight(200);testConsoleAppender(t,inlineAppender);});s.test("InPageAppender with separate console HTML file test",function(t){var inPageAppender=new log4javascript.InPageAppender();inPageAppender.setInitiallyMinimized(false);inPageAppender.setNewestMessageAtTop(false);inPageAppender.setScrollToLatestMessage(true);inPageAppender.setUseDocumentWrite(false);inPageAppender.setWidth(600);inPageAppender.setHeight(200);testConsoleAppender(t,inPageAppender);});s.test("PopUpAppender test",function(t){var popUpAppender=new log4javascript.PopUpAppender();popUpAppender.setFocusPopUp(true);popUpAppender.setUseOldPopUp(false);popUpAppender.setNewestMessageAtTop(false);popUpAppender.setScrollToLatestMessage(true);popUpAppender.setComplainAboutPopUpBlocking(false);popUpAppender.setWidth(600);popUpAppender.setHeight(200);testConsoleAppender(t,popUpAppender);});s.test("PopUpAppender with separate console HTML file test",function(t){var popUpAppender=new log4javascript.PopUpAppender();popUpAppender.setFocusPopUp(true);popUpAppender.setUseOldPopUp(false);popUpAppender.setNewestMessageAtTop(false);popUpAppender.setScrollToLatestMessage(true);popUpAppender.setComplainAboutPopUpBlocking(false);popUpAppender.setUseDocumentWrite(false);popUpAppender.setWidth(600);popUpAppender.setHeight(200);testConsoleAppender(t,popUpAppender);});});

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite.js b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite.js
new file mode 100644
index 0000000..b9eb6b7
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite.js
@@ -0,0 +1,16 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite_uncompressed.js
new file mode 100644
index 0000000..b9eb6b7
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_lite_uncompressed.js
@@ -0,0 +1,16 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_production.js b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_production.js
new file mode 100644
index 0000000..f5d1090
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_production.js
@@ -0,0 +1,28 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+function array_contains(arr,val){for(var i=0;i<arr.length;i++){if(arr[i]==val){return true;}}

+return false;}

+function compareObjectInterface(obj1,obj1_name,obj2,obj2_name,namePrefix){if(!namePrefix){namePrefix="";}

+var obj1PropertyNames=new Array();for(var i in obj1){if(i!="prototype"&&i!="arguments"){obj1PropertyNames.push(i);}}

+if(obj1&&obj1.prototype&&!array_contains(obj1PropertyNames,"prototype")){}

+for(var j=0;j<obj1PropertyNames.length;j++){var propertyName=obj1PropertyNames[j];if((typeof obj1[propertyName]=="function"||typeof obj1[propertyName]=="object")&&!(obj1[propertyName]instanceof Array)){var propertyFullyQualifiedName=(namePrefix=="")?propertyName:namePrefix+"."+propertyName;try{if(typeof obj2[propertyName]=="undefined"){throw new Error(obj2_name+" does not contain "+propertyFullyQualifiedName+" in "+obj1_name);}else if(typeof obj2[propertyName]!=typeof obj1[propertyName]){throw new Error(obj2_name+"'s "+propertyFullyQualifiedName+" is of the wrong type: "+typeof obj2[propertyName]+" when it is type "+typeof obj1[propertyName]+" in "+obj1_name);}else if(obj1[propertyName]!=Function.prototype.apply){if(!compareObjectInterface(obj1[propertyName],obj1_name,obj2[propertyName],obj2_name,propertyFullyQualifiedName)){throw new Error("Interfaces don't match");}}}catch(ex){throw new Error("Exception while checking property name "+propertyFullyQualifiedName+" in "+obj2_name+": "+ex.message);}}}

+return true;};var testLayoutWithVariables=function(layout,t){var emptyObject={};var emptyArray=[];var emptyString="";var localUndefined=emptyArray[0];var oneLevelObject={"name":"One-level object"};var twoLevelObject={"name":"Two-level object","data":oneLevelObject};var threeLevelObject={"name":"Three-level object","data":twoLevelObject};var anArray=[3,"stuff",true,false,0,null,localUndefined,3.14,function(p){return"I'm a function";},[1,"things"]];var arrayOfTestItems=[emptyObject,emptyString,emptyString,localUndefined,oneLevelObject,twoLevelObject,threeLevelObject,anArray];t.log("Testing layout "+layout)

+for(var i=0;i<arrayOfTestItems.length;i++){var ex=new Error("Test error");var loggingEvent=new log4javascript.LoggingEvent(t.logger,new Date(),log4javascript.Level.INFO,[arrayOfTestItems[i]],null);t.log("Formatting",arrayOfTestItems[i],result);var result=layout.format(loggingEvent);loggingEvent.exception=ex;t.log("Formatting with exception",arrayOfTestItems[i],result);result=layout.format(loggingEvent);}};xn.test.enableTestDebug=true;xn.test.enable_log4javascript=false;xn.test.suite("log4javascript tests",function(s){log4javascript.logLog.setQuietMode(true);var ArrayAppender=function(layout){if(layout){this.setLayout(layout);}

+this.logMessages=[];};ArrayAppender.prototype=new log4javascript.Appender();ArrayAppender.prototype.layout=new log4javascript.NullLayout();ArrayAppender.prototype.append=function(loggingEvent){var formattedMessage=this.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();}

+this.logMessages.push(formattedMessage);};ArrayAppender.prototype.toString=function(){return"[ArrayAppender]";};s.setUp=function(t){t.logger=log4javascript.getLogger("test");t.logger.removeAllAppenders();t.appender=new ArrayAppender();t.logger.addAppender(t.appender);};s.tearDown=function(t){t.logger.removeAppender(t.appender);log4javascript.resetConfiguration();};s.test("Stub script interface test",function(t){try{compareObjectInterface(log4javascript,"log4javascript",log4javascript_stub,"log4javascript_stub");}catch(ex){t.fail(ex);}});s.test("Disable log4javascript test",function(t){log4javascript.setEnabled(false);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,0);log4javascript.setEnabled(true);});s.test("Array.splice test 1",function(t){var a=["Marlon","Ashley","Darius","Lloyd"];var deletedItems=a.splice(1,2);t.assertEquals(a.join(","),"Marlon,Lloyd");t.assertEquals(deletedItems.join(","),"Ashley,Darius");});s.test("Array.splice test 2",function(t){var a=["Marlon","Ashley","Darius","Lloyd"];var deletedItems=a.splice(1,1,"Malky","Jay");t.assertEquals(a.join(","),"Marlon,Malky,Jay,Darius,Lloyd");t.assertEquals(deletedItems.join(","),"Ashley");});s.test("array_remove test",function(t){var array_remove=log4javascript.evalInScope("array_remove");var a=["Marlon","Ashley","Darius"];array_remove(a,"Darius");t.assertEquals(a.join(","),"Marlon,Ashley");});s.test("array_remove with empty array test",function(t){var array_remove=log4javascript.evalInScope("array_remove");var a=[];array_remove(a,"Darius");t.assertEquals(a.join(","),"");});s.test("Logger logging test",function(t){t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,1);});s.test("Logger levels test",function(t){var originalLevel=t.logger.getEffectiveLevel();t.logger.setLevel(log4javascript.Level.INFO);t.logger.debug("TEST");t.logger.setLevel(originalLevel);t.assertEquals(t.appender.logMessages.length,0);});s.test("Logger getEffectiveLevel inheritance test 1",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");parentLogger.setLevel(log4javascript.Level.ERROR);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.ERROR);});s.test("Logger getEffectiveLevel inheritance test 2",function(t){var grandParentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2.test3");grandParentLogger.setLevel(log4javascript.Level.ERROR);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.ERROR);});s.test("Logger getEffectiveLevel inheritance test 3",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");parentLogger.setLevel(log4javascript.Level.ERROR);childLogger.setLevel(log4javascript.Level.INFO);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.INFO);});s.test("Logger getEffectiveLevel root inheritance test",function(t){var rootLogger=log4javascript.getRootLogger();var childLogger=log4javascript.getLogger("test1.test2.test3");rootLogger.setLevel(log4javascript.Level.WARN);t.assertEquals(childLogger.getEffectiveLevel(),log4javascript.Level.WARN);});s.test("Logger null level test",function(t){t.logger.setLevel(null);t.assertEquals(t.logger.getEffectiveLevel(),log4javascript.Level.DEBUG);});s.test("Logger appender additivity test 1",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");var parentLoggerAppender=new ArrayAppender();var childLoggerAppender=new ArrayAppender();parentLogger.addAppender(parentLoggerAppender);childLogger.addAppender(childLoggerAppender);parentLogger.info("Parent logger test message");childLogger.info("Child logger test message");t.assertEquals(parentLoggerAppender.logMessages.length,2);t.assertEquals(childLoggerAppender.logMessages.length,1);});s.test("Logger appender additivity test 2",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");var parentLoggerAppender=new ArrayAppender();var childLoggerAppender=new ArrayAppender();parentLogger.addAppender(parentLoggerAppender);childLogger.addAppender(childLoggerAppender);childLogger.setAdditivity(false);parentLogger.info("Parent logger test message");childLogger.info("Child logger test message");t.assertEquals(parentLoggerAppender.logMessages.length,1);t.assertEquals(childLoggerAppender.logMessages.length,1);});s.test("Logger appender additivity test 3",function(t){var parentLogger=log4javascript.getLogger("test1");var childLogger=log4javascript.getLogger("test1.test2");var parentLoggerAppender=new ArrayAppender();var childLoggerAppender=new ArrayAppender();parentLogger.addAppender(parentLoggerAppender);childLogger.addAppender(childLoggerAppender);childLogger.setAdditivity(false);parentLogger.info("Parent logger test message");childLogger.info("Child logger test message");childLogger.setAdditivity(true);childLogger.info("Child logger test message 2");t.assertEquals(parentLoggerAppender.logMessages.length,2);t.assertEquals(childLoggerAppender.logMessages.length,2);});s.test("Appender threshold test",function(t){t.appender.setThreshold(log4javascript.Level.INFO);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,0);});s.test("Basic appender / layout test",function(t){t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"TEST");});s.test("Appender uniqueness within logger test",function(t){t.logger.addAppender(t.appender);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages.length,1);});s.test("Logger remove appender test",function(t){t.logger.debug("TEST");t.logger.removeAppender(t.appender);t.logger.debug("TEST AGAIN");t.assertEquals(t.appender.logMessages.length,1);});s.test("",function(t){t.logger.debug("TEST");t.logger.removeAppender(t.appender);t.logger.debug("TEST AGAIN");t.assertEquals(t.appender.logMessages.length,1);});s.test("SimpleLayout format test",function(t){var layout=new log4javascript.SimpleLayout();testLayoutWithVariables(layout,t);});s.test("SimpleLayout test",function(t){t.appender.setLayout(new log4javascript.SimpleLayout());t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"DEBUG - TEST");});s.test("NullLayout format test",function(t){var layout=new log4javascript.NullLayout();testLayoutWithVariables(layout,t);});s.test("NullLayout test",function(t){t.appender.setLayout(new log4javascript.NullLayout());t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"TEST");});s.test("XmlLayout format test",function(t){var layout=new log4javascript.XmlLayout();testLayoutWithVariables(layout,t);});s.test("XmlLayout test",function(t){t.appender.setLayout(new log4javascript.XmlLayout());t.logger.debug("TEST");t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<\/log4javascript:event>\s*$/,t.appender.logMessages[0]);});s.test("XmlLayout with exception test",function(t){t.appender.setLayout(new log4javascript.XmlLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<log4javascript:exception>\s*<!\[CDATA\[.*\]\]><\/log4javascript:exception>\s*<\/log4javascript:event>\s*$/,t.appender.logMessages[0]);});var setUpXmlLayoutMillisecondsTest=function(t){t.date=new Date();t.timeInMilliseconds=t.date.getTime();t.timeInSeconds=Math.floor(t.timeInMilliseconds/1000);t.milliseconds=t.date.getMilliseconds();t.loggingEvent=new log4javascript.LoggingEvent(t.logger,t.date,log4javascript.Level.DEBUG,["TEST"],null);t.layout=new log4javascript.XmlLayout();}

+s.test("XmlLayout seconds/milliseconds test 1",function(t){setUpXmlLayoutMillisecondsTest(t);var regex=new RegExp('^<log4javascript:event logger="test" timestamp="'+t.timeInMilliseconds+'" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');t.assertRegexMatches(regex,t.layout.format(t.loggingEvent));});s.test("XmlLayout seconds/milliseconds test 2",function(t){setUpXmlLayoutMillisecondsTest(t);log4javascript.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);log4javascript.setTimeStampsInMilliseconds(true);var regex=new RegExp('^<log4javascript:event logger="test" timestamp="'+t.timeInSeconds+'" milliseconds="'+t.milliseconds+'" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');t.assertRegexMatches(regex,formatted);});s.test("XmlLayout seconds/milliseconds test 3",function(t){setUpXmlLayoutMillisecondsTest(t);t.layout.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);var regex=new RegExp('^<log4javascript:event logger="test" timestamp="'+t.timeInSeconds+'" milliseconds="'+t.milliseconds+'" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');t.assertRegexMatches(regex,formatted);});s.test("escapeNewLines test",function(t){var escapeNewLines=log4javascript.evalInScope("escapeNewLines");var str="1\r2\n3\n4\r\n5\r6\r\n7";t.assertEquals(escapeNewLines(str),"1\\r\\n2\\r\\n3\\r\\n4\\r\\n5\\r\\n6\\r\\n7");});s.test("JsonLayout format test",function(t){var layout=new log4javascript.JsonLayout();testLayoutWithVariables(layout,t);});s.test("JsonLayout test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST");t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST"}$/,t.appender.logMessages[0]);});s.test("JsonLayout JSON validity test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST");eval("var o = "+t.appender.logMessages[0]);t.assertEquals(o.message,"TEST");});s.test("JsonLayout with number type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug(15);t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":15}$/,t.appender.logMessages[0]);});s.test("JsonLayout with object type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug({});t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"\[object Object\]"}$/,t.appender.logMessages[0]);});s.test("JsonLayout with boolean type message test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug(false);t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":false}$/,t.appender.logMessages[0]);});s.test("JsonLayout with quote test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TE\"S\"T");t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TE\\"S\\"T"}$/,t.appender.logMessages[0]);});s.test("JsonLayout with exception test",function(t){t.appender.setLayout(new log4javascript.JsonLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST","exception":.*}$/,t.appender.logMessages[0]);});var setUpJsonLayoutMillisecondsTest=function(t){t.date=new Date();t.timeInMilliseconds=t.date.getTime();t.timeInSeconds=Math.floor(t.timeInMilliseconds/1000);t.milliseconds=t.date.getMilliseconds();t.loggingEvent=new log4javascript.LoggingEvent(t.logger,t.date,log4javascript.Level.DEBUG,["TEST"],null);t.layout=new log4javascript.JsonLayout();};s.test("JsonLayout seconds/milliseconds test 1",function(t){setUpJsonLayoutMillisecondsTest(t);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInMilliseconds+',"level":"DEBUG","url":".*","message":"TEST"}$');t.assertRegexMatches(regex,t.layout.format(t.loggingEvent));});s.test("JsonLayout seconds/milliseconds test 2",function(t){setUpJsonLayoutMillisecondsTest(t);log4javascript.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);log4javascript.setTimeStampsInMilliseconds(true);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInSeconds+',"level":"DEBUG","url":".*","message":"TEST","milliseconds":'+t.milliseconds+'}$');t.assertRegexMatches(regex,formatted);});s.test("JsonLayout seconds/milliseconds test 3",function(t){setUpJsonLayoutMillisecondsTest(t);t.layout.setTimeStampsInMilliseconds(false);var formatted=t.layout.format(t.loggingEvent);var regex=new RegExp('^{"logger":"test","timestamp":'+t.timeInSeconds+',"level":"DEBUG","url":".*","message":"TEST","milliseconds":'+t.milliseconds+'}$');t.assertRegexMatches(regex,formatted);});s.test("HttpPostDataLayout format test",function(t){var layout=new log4javascript.HttpPostDataLayout();testLayoutWithVariables(layout,t);});s.test("HttpPostDataLayout test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST");t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST$/,t.appender.logMessages[0]);});s.test("HttpPostDataLayout URL encoding test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST +\"1\"");t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST%20%2B%221%22$/,t.appender.logMessages[0]);});s.test("HttpPostDataLayout with exception test",function(t){t.appender.setLayout(new log4javascript.HttpPostDataLayout());t.logger.debug("TEST",new Error("Test error"));t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST&exception=.*$/,t.appender.logMessages[0]);});(function(){var formatObjectExpansion=log4javascript.evalInScope("formatObjectExpansion");var newLine=log4javascript.evalInScope("newLine");var arr=[null,undefined,1.2,"A string",[1,"test"],{a:{b:1}}];s.test("Basic formatObjectExpansion array test (depth: 1)",function(t){t.assertEquals(formatObjectExpansion(arr,1),"["+newLine+"  null,"+newLine+"  undefined,"+newLine+"  1.2,"+newLine+"  A string,"+newLine+"  1,test,"+newLine+"  [object Object]"+newLine+"]");});s.test("Basic formatObjectExpansion array test (depth: 2)",function(t){t.assertEquals(formatObjectExpansion(arr,2),"["+newLine+"  null,"+newLine+"  undefined,"+newLine+"  1.2,"+newLine+"  A string,"+newLine+"  ["+newLine+"    1,"+newLine+"    test"+newLine+"  ],"+newLine+"  {"+newLine+"    a: [object Object]"+newLine+"  }"+newLine+"]");});s.test("formatObjectExpansion simple object test",function(t){var obj={STRING:"A string"};t.assertEquals(formatObjectExpansion(obj,1),"{"+newLine+"  STRING: A string"+newLine+"}");});s.test("formatObjectExpansion simple circular object test",function(t){var obj={};obj.a=obj;t.assertEquals(formatObjectExpansion(obj,2),"{"+newLine+"  a: [object Object] [already expanded]"+newLine+"}");});})();var getSampleDate=function(){var date=new Date();date.setFullYear(2006);date.setMonth(7);date.setDate(30);date.setHours(15);date.setMinutes(38);date.setSeconds(45);return date;};s.test("String.replace test",function(t){t.assertEquals("Hello world".replace(/o/g,"Z"),"HellZ wZrld");});s.test("PatternLayout format test",function(t){var layout=new log4javascript.PatternLayout();testLayoutWithVariables(layout,t);});s.test("PatternLayout dates test",function(t){var layout=new log4javascript.PatternLayout("%d %d{DATE} %d{HH:ss}");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertRegexMatches(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2},\d{3} \d{2}:\d{2}$/,t.appender.logMessages[0]);});s.test("PatternLayout modifiers test",function(t){var layout=new log4javascript.PatternLayout("%m|%3m|%-3m|%6m|%-6m|%.2m|%1.2m|%6.8m|%-1.2m|%-6.8m|");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertEquals(t.appender.logMessages[0],"TEST|TEST|TEST|  TEST|TEST  |ST|ST|  TEST|ST|TEST  |");});s.test("PatternLayout conversion characters test",function(t){var layout=new log4javascript.PatternLayout("%c %n %p %r literal %%");t.appender.setLayout(layout);t.logger.debug("TEST");t.assertRegexMatches(/^test \s+ DEBUG \d+ literal %$/,t.appender.logMessages[0]);});s.test("PatternLayout message test",function(t){var layout=new log4javascript.PatternLayout("%m{1} %m{2}");t.appender.setLayout(layout);var testObj={strikers:{quick:"Marlon"}};t.logger.debug(testObj);t.assertEquals("{\r\n  strikers: [object Object]\r\n} {\r\n\  strikers: {\r\n    quick: Marlon\r\n  }\r\n}",t.appender.logMessages[0]);});});

diff --git a/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_production_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_production_uncompressed.js
new file mode 100644
index 0000000..e64990f
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_production_uncompressed.js
@@ -0,0 +1,728 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+function array_contains(arr, val) {

+	for (var i = 0; i < arr.length; i++) {

+		if (arr[i] == val) {

+			return true;

+		}

+	}

+	return false;

+}

+

+// Recursively checks that obj2's interface contains all of obj1's

+// interface (functions and objects only)

+function compareObjectInterface(obj1, obj1_name, obj2, obj2_name, namePrefix) {

+	if (!namePrefix) {

+		namePrefix = "";

+	}

+	var obj1PropertyNames = new Array();

+	for (var i in obj1) {

+		if (i != "prototype" && i != "arguments") {

+			obj1PropertyNames.push(i);

+		}

+	}

+	if (obj1 && obj1.prototype && !array_contains(obj1PropertyNames, "prototype")) {

+		//obj1PropertyNames.push("prototype");

+	}

+	for (var j = 0; j < obj1PropertyNames.length; j++) {

+		var propertyName = obj1PropertyNames[j];

+		if ((typeof obj1[propertyName] == "function" || typeof obj1[propertyName] == "object") && !(obj1[propertyName] instanceof Array)) {

+			var propertyFullyQualifiedName = (namePrefix == "") ? propertyName : namePrefix + "." + propertyName;

+			try {

+				if (typeof obj2[propertyName] == "undefined") {

+					throw new Error(obj2_name + " does not contain " + propertyFullyQualifiedName + " in " + obj1_name);

+				} else if (typeof obj2[propertyName] != typeof obj1[propertyName]){

+					throw new Error(obj2_name + "'s " + propertyFullyQualifiedName + " is of the wrong type: " + typeof obj2[propertyName] + " when it is type " + typeof obj1[propertyName] + " in " + obj1_name);

+				} else if (obj1[propertyName] != Function.prototype.apply) {

+					if (!compareObjectInterface(obj1[propertyName], obj1_name, obj2[propertyName], obj2_name, propertyFullyQualifiedName)) {

+						throw new Error("Interfaces don't match");

+					}

+				}

+			} catch(ex) {

+				throw new Error("Exception while checking property name " + propertyFullyQualifiedName + " in " + obj2_name + ": " + ex.message);

+			}

+		}

+	}

+	return true;

+};

+

+// Simply tests a layout for exceptions when formatting

+var testLayoutWithVariables = function(layout, t) {

+	var emptyObject = {};

+	var emptyArray = [];

+	var emptyString = "";

+	var localUndefined = emptyArray[0];

+	var oneLevelObject = {

+		"name": "One-level object"

+	};

+	var twoLevelObject = {

+		"name": "Two-level object",

+		"data": oneLevelObject

+	};

+	var threeLevelObject = {

+		"name": "Three-level object",

+		"data": twoLevelObject

+	};

+	var anArray = [

+		3,

+		"stuff",

+		true,

+		false,

+		0,

+		null,

+		localUndefined,

+		3.14,

+		function(p) { return "I'm a function"; },

+		[1, "things"]

+	];

+	var arrayOfTestItems = [emptyObject, emptyString, emptyString, localUndefined, oneLevelObject,

+			twoLevelObject, threeLevelObject, anArray];

+

+	t.log("Testing layout " + layout)

+	for (var i = 0; i < arrayOfTestItems.length; i++) {

+		var ex = new Error("Test error");

+		var loggingEvent = new log4javascript.LoggingEvent(t.logger, new Date(), log4javascript.Level.INFO,

+				[arrayOfTestItems[i]], null);

+		t.log("Formatting", arrayOfTestItems[i], result);

+		var result = layout.format(loggingEvent);

+		// Now try with an exception

+		loggingEvent.exception = ex;

+		t.log("Formatting with exception", arrayOfTestItems[i], result);

+		result = layout.format(loggingEvent);

+	}

+};

+

+xn.test.enableTestDebug = true;

+xn.test.enable_log4javascript = false;

+

+xn.test.suite("log4javascript tests", function(s) {

+	log4javascript.logLog.setQuietMode(true);

+	var ArrayAppender = function(layout) {

+		if (layout) {

+			this.setLayout(layout);

+		}

+		this.logMessages = [];

+	};

+

+	ArrayAppender.prototype = new log4javascript.Appender();

+

+	ArrayAppender.prototype.layout = new log4javascript.NullLayout();

+

+	ArrayAppender.prototype.append = function(loggingEvent) {

+		var formattedMessage = this.getLayout().format(loggingEvent);

+		if (this.getLayout().ignoresThrowable()) {

+			formattedMessage += loggingEvent.getThrowableStrRep();

+		}

+		this.logMessages.push(formattedMessage);

+	};

+

+	ArrayAppender.prototype.toString = function() {

+		return "[ArrayAppender]";

+	};

+

+    s.setUp = function(t) {

+        t.logger = log4javascript.getLogger("test");

+		t.logger.removeAllAppenders();

+		t.appender = new ArrayAppender();

+        t.logger.addAppender(t.appender);

+    };

+

+    s.tearDown = function(t) {

+        t.logger.removeAppender(t.appender);

+		log4javascript.resetConfiguration();

+	};

+

+    s.test("Stub script interface test", function(t) {

+        try {

+            compareObjectInterface(log4javascript, "log4javascript", log4javascript_stub, "log4javascript_stub");

+        } catch (ex) {

+            t.fail(ex);

+        }

+    });

+

+	s.test("Disable log4javascript test", function(t) {

+		log4javascript.setEnabled(false);

+		t.logger.debug("TEST");

+		t.assertEquals(t.appender.logMessages.length, 0);

+		log4javascript.setEnabled(true);

+	});

+

+    s.test("Array.splice test 1", function(t) {

+        var a = ["Marlon", "Ashley", "Darius", "Lloyd"];

+        var deletedItems = a.splice(1, 2);

+        t.assertEquals(a.join(","), "Marlon,Lloyd");

+        t.assertEquals(deletedItems.join(","), "Ashley,Darius");

+    });

+

+    s.test("Array.splice test 2", function(t) {

+        var a = ["Marlon", "Ashley", "Darius", "Lloyd"];

+        var deletedItems = a.splice(1, 1, "Malky", "Jay");

+        t.assertEquals(a.join(","), "Marlon,Malky,Jay,Darius,Lloyd");

+        t.assertEquals(deletedItems.join(","), "Ashley");

+    });

+

+    s.test("array_remove test", function(t) {

+        var array_remove = log4javascript.evalInScope("array_remove");

+        var a = ["Marlon", "Ashley", "Darius"];

+        array_remove(a, "Darius");

+        t.assertEquals(a.join(","), "Marlon,Ashley");

+    });

+

+	s.test("array_remove with empty array test", function(t) {

+		var array_remove = log4javascript.evalInScope("array_remove");

+		var a = [];

+		array_remove(a, "Darius");

+		t.assertEquals(a.join(","), "");

+	});

+

+    s.test("Logger logging test", function(t) {

+        // Should log since the default level for loggers is DEBUG and

+        // the default threshold for appenders is ALL

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages.length, 1);

+    });

+

+    s.test("Logger levels test", function(t) {

+        var originalLevel = t.logger.getEffectiveLevel();

+        t.logger.setLevel(log4javascript.Level.INFO);

+        t.logger.debug("TEST");

+		t.logger.setLevel(originalLevel);

+        t.assertEquals(t.appender.logMessages.length, 0);

+    });

+

+	s.test("Logger getEffectiveLevel inheritance test 1", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		parentLogger.setLevel(log4javascript.Level.ERROR);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.ERROR);

+	});

+

+	s.test("Logger getEffectiveLevel inheritance test 2", function(t) {

+		var grandParentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2.test3");

+		grandParentLogger.setLevel(log4javascript.Level.ERROR);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.ERROR);

+	});

+

+	s.test("Logger getEffectiveLevel inheritance test 3", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		parentLogger.setLevel(log4javascript.Level.ERROR);

+		childLogger.setLevel(log4javascript.Level.INFO);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.INFO);

+	});

+

+	s.test("Logger getEffectiveLevel root inheritance test", function(t) {

+		var rootLogger = log4javascript.getRootLogger();

+		var childLogger = log4javascript.getLogger("test1.test2.test3");

+		rootLogger.setLevel(log4javascript.Level.WARN);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.WARN);

+	});

+

+	s.test("Logger null level test", function(t) {

+		t.logger.setLevel(null);

+		// Should default to root logger level, which is DEBUG

+		t.assertEquals(t.logger.getEffectiveLevel(), log4javascript.Level.DEBUG);

+	});

+

+	s.test("Logger appender additivity test 1", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		var parentLoggerAppender = new ArrayAppender();

+		var childLoggerAppender = new ArrayAppender();

+

+		parentLogger.addAppender(parentLoggerAppender);

+		childLogger.addAppender(childLoggerAppender);

+

+		parentLogger.info("Parent logger test message");

+		childLogger.info("Child logger test message");

+

+		t.assertEquals(parentLoggerAppender.logMessages.length, 2);

+		t.assertEquals(childLoggerAppender.logMessages.length, 1);

+	});

+

+	s.test("Logger appender additivity test 2", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		var parentLoggerAppender = new ArrayAppender();

+		var childLoggerAppender = new ArrayAppender();

+

+		parentLogger.addAppender(parentLoggerAppender);

+		childLogger.addAppender(childLoggerAppender);

+

+		childLogger.setAdditivity(false);

+

+		parentLogger.info("Parent logger test message");

+		childLogger.info("Child logger test message");

+

+		t.assertEquals(parentLoggerAppender.logMessages.length, 1);

+		t.assertEquals(childLoggerAppender.logMessages.length, 1);

+	});

+

+	s.test("Logger appender additivity test 3", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		var parentLoggerAppender = new ArrayAppender();

+		var childLoggerAppender = new ArrayAppender();

+

+		parentLogger.addAppender(parentLoggerAppender);

+		childLogger.addAppender(childLoggerAppender);

+

+		childLogger.setAdditivity(false);

+

+		parentLogger.info("Parent logger test message");

+		childLogger.info("Child logger test message");

+

+		childLogger.setAdditivity(true);

+

+		childLogger.info("Child logger test message 2");

+

+		t.assertEquals(parentLoggerAppender.logMessages.length, 2);

+		t.assertEquals(childLoggerAppender.logMessages.length, 2);

+	});

+

+	s.test("Appender threshold test", function(t) {

+        t.appender.setThreshold(log4javascript.Level.INFO);

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages.length, 0);

+    });

+

+    s.test("Basic appender / layout test", function(t) {

+        t.logger.debug("TEST");

+		t.assertEquals(t.appender.logMessages[0], "TEST");

+    });

+

+	s.test("Appender uniqueness within logger test", function(t) {

+		// Add the same appender to the logger for a second time

+		t.logger.addAppender(t.appender);

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages.length, 1);

+    });

+

+	s.test("Logger remove appender test", function(t) {

+		t.logger.debug("TEST");

+		t.logger.removeAppender(t.appender);

+		t.logger.debug("TEST AGAIN");

+		t.assertEquals(t.appender.logMessages.length, 1);

+	});

+

+	s.test("", function(t) {

+		t.logger.debug("TEST");

+		t.logger.removeAppender(t.appender);

+		t.logger.debug("TEST AGAIN");

+		t.assertEquals(t.appender.logMessages.length, 1);

+	});

+	s.test("SimpleLayout format test", function(t) {

+		var layout = new log4javascript.SimpleLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("SimpleLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.SimpleLayout());

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages[0], "DEBUG - TEST");

+    });

+	s.test("NullLayout format test", function(t) {

+		var layout = new log4javascript.NullLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("NullLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.NullLayout());

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages[0], "TEST");

+    });

+	s.test("XmlLayout format test", function(t) {

+		var layout = new log4javascript.XmlLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("XmlLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.XmlLayout());

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<\/log4javascript:event>\s*$/, t.appender.logMessages[0]);

+    });

+

+    s.test("XmlLayout with exception test", function(t) {

+        t.appender.setLayout(new log4javascript.XmlLayout());

+        t.logger.debug("TEST", new Error("Test error"));

+        t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<log4javascript:exception>\s*<!\[CDATA\[.*\]\]><\/log4javascript:exception>\s*<\/log4javascript:event>\s*$/, t.appender.logMessages[0]);

+    });

+

+	var setUpXmlLayoutMillisecondsTest = function(t) {

+		t.date = new Date();

+		t.timeInMilliseconds = t.date.getTime();

+		t.timeInSeconds = Math.floor(t.timeInMilliseconds / 1000);

+		t.milliseconds = t.date.getMilliseconds();

+		

+		t.loggingEvent = new log4javascript.LoggingEvent(t.logger, t.date, log4javascript.Level.DEBUG, ["TEST"], null);

+		t.layout = new log4javascript.XmlLayout();

+	}

+

+	s.test("XmlLayout seconds/milliseconds test 1", function(t) {

+		setUpXmlLayoutMillisecondsTest(t);

+

+		// Test default (i.e. timestamps in milliseconds) first

+        var regex = new RegExp('^<log4javascript:event logger="test" timestamp="' + t.timeInMilliseconds + '" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');

+        t.assertRegexMatches(regex, t.layout.format(t.loggingEvent));

+	});

+	

+	s.test("XmlLayout seconds/milliseconds test 2", function(t) {

+		setUpXmlLayoutMillisecondsTest(t);

+

+        // Change the global setting

+        log4javascript.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        log4javascript.setTimeStampsInMilliseconds(true);

+        var regex = new RegExp('^<log4javascript:event logger="test" timestamp="' + t.timeInSeconds + '" milliseconds="' + t.milliseconds + '" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');

+        t.assertRegexMatches(regex, formatted);

+	});

+

+	s.test("XmlLayout seconds/milliseconds test 3", function(t) {

+		setUpXmlLayoutMillisecondsTest(t);

+

+        // Change the layout setting

+        t.layout.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        var regex = new RegExp('^<log4javascript:event logger="test" timestamp="' + t.timeInSeconds + '" milliseconds="' + t.milliseconds + '" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');

+        t.assertRegexMatches(regex, formatted);

+	});

+	s.test("escapeNewLines test", function(t) {

+		var escapeNewLines = log4javascript.evalInScope("escapeNewLines");

+		var str = "1\r2\n3\n4\r\n5\r6\r\n7";

+		t.assertEquals(escapeNewLines(str), "1\\r\\n2\\r\\n3\\r\\n4\\r\\n5\\r\\n6\\r\\n7");

+	});

+

+	s.test("JsonLayout format test", function(t) {

+		var layout = new log4javascript.JsonLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("JsonLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST"}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout JSON validity test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TEST");

+        eval("var o = " + t.appender.logMessages[0]);

+        t.assertEquals(o.message, "TEST");

+    });

+

+    s.test("JsonLayout with number type message test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug(15);

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":15}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with object type message test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug({});

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"\[object Object\]"}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with boolean type message test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug(false);

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":false}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with quote test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TE\"S\"T");

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TE\\"S\\"T"}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with exception test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TEST", new Error("Test error"));

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST","exception":.*}$/, t.appender.logMessages[0]);

+    });

+

+	var setUpJsonLayoutMillisecondsTest = function(t) {

+		t.date = new Date();

+		t.timeInMilliseconds = t.date.getTime();

+		t.timeInSeconds = Math.floor(t.timeInMilliseconds / 1000);

+		t.milliseconds = t.date.getMilliseconds();

+		

+		t.loggingEvent = new log4javascript.LoggingEvent(t.logger, t.date, log4javascript.Level.DEBUG, ["TEST"], null);

+		t.layout = new log4javascript.JsonLayout();

+	};

+

+	s.test("JsonLayout seconds/milliseconds test 1", function(t) {

+		setUpJsonLayoutMillisecondsTest(t);

+

+		// Test default (i.e. timestamps in milliseconds) first

+        var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInMilliseconds + ',"level":"DEBUG","url":".*","message":"TEST"}$');

+        t.assertRegexMatches(regex, t.layout.format(t.loggingEvent));

+	});

+	

+	s.test("JsonLayout seconds/milliseconds test 2", function(t) {

+		setUpJsonLayoutMillisecondsTest(t);

+

+        // Change the global setting

+        log4javascript.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        log4javascript.setTimeStampsInMilliseconds(true);

+        var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInSeconds + ',"level":"DEBUG","url":".*","message":"TEST","milliseconds":' + t.milliseconds + '}$');

+        t.assertRegexMatches(regex, formatted);

+	});

+

+	s.test("JsonLayout seconds/milliseconds test 3", function(t) {

+		setUpJsonLayoutMillisecondsTest(t);

+

+        // Change the layout setting

+        t.layout.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInSeconds + ',"level":"DEBUG","url":".*","message":"TEST","milliseconds":' + t.milliseconds + '}$');

+        t.assertRegexMatches(regex, formatted);

+	});

+	s.test("HttpPostDataLayout format test", function(t) {

+		var layout = new log4javascript.HttpPostDataLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("HttpPostDataLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.HttpPostDataLayout());

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST$/, t.appender.logMessages[0]);

+    });

+

+    s.test("HttpPostDataLayout URL encoding test", function(t) {

+        t.appender.setLayout(new log4javascript.HttpPostDataLayout());

+        t.logger.debug("TEST +\"1\"");

+        t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST%20%2B%221%22$/, t.appender.logMessages[0]);

+    });

+

+    s.test("HttpPostDataLayout with exception test", function(t) {

+        t.appender.setLayout(new log4javascript.HttpPostDataLayout());

+        t.logger.debug("TEST", new Error("Test error"));

+        t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST&exception=.*$/, t.appender.logMessages[0]);

+    });

+

+	(function() {

+		var formatObjectExpansion = log4javascript.evalInScope("formatObjectExpansion");

+		var newLine = log4javascript.evalInScope("newLine");

+		var arr = [

+			null,

+			undefined,

+			1.2,

+			"A string",

+			[1, "test"],

+			{

+				a: {

+					b: 1

+				}

+			}

+		];

+

+		s.test("Basic formatObjectExpansion array test (depth: 1)", function(t) {

+			t.assertEquals(formatObjectExpansion(arr, 1),

+				"[" + newLine +

+				"  null," + newLine +

+				"  undefined," + newLine +

+				"  1.2," + newLine +

+				"  A string," + newLine +

+				"  1,test," + newLine +

+				"  [object Object]" + newLine +

+				"]"

+			);

+		});

+

+		s.test("Basic formatObjectExpansion array test (depth: 2)", function(t) {

+			t.assertEquals(formatObjectExpansion(arr, 2),

+				"[" + newLine +

+				"  null," + newLine +

+				"  undefined," + newLine +

+				"  1.2," + newLine +

+				"  A string," + newLine +

+				"  [" + newLine +

+				"    1," + newLine +

+				"    test" + newLine +

+				"  ]," + newLine +

+				"  {" + newLine +

+				"    a: [object Object]" + newLine +

+				"  }" + newLine +

+				"]"

+			);

+		});

+

+		s.test("formatObjectExpansion simple object test", function(t) {

+			var obj = {

+				STRING: "A string"

+			};

+			t.assertEquals(formatObjectExpansion(obj, 1), 

+				"{" + newLine +

+				"  STRING: A string" + newLine +

+				"}"

+			);

+		});

+

+		s.test("formatObjectExpansion simple circular object test", function(t) {

+			var obj = {};

+			obj.a = obj;

+			

+			t.assertEquals(formatObjectExpansion(obj, 2), 

+				"{" + newLine +

+				"  a: [object Object] [already expanded]" + newLine +

+				"}"

+			);

+		});

+	})();    /* ---------------------------------------------------------- */

+

+    var getSampleDate = function() {

+        var date = new Date();

+        date.setFullYear(2006);

+        date.setMonth(7);

+        date.setDate(30);

+        date.setHours(15);

+        date.setMinutes(38);

+        date.setSeconds(45);

+        return date;

+    };

+

+    /* ---------------------------------------------------------- */

+

+    s.test("String.replace test", function(t) {

+        t.assertEquals("Hello world".replace(/o/g, "Z"), "HellZ wZrld");

+    });

+

+	s.test("PatternLayout format test", function(t) {

+		var layout = new log4javascript.PatternLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("PatternLayout dates test", function(t) {

+        var layout = new log4javascript.PatternLayout("%d %d{DATE} %d{HH:ss}");

+        t.appender.setLayout(layout);

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2},\d{3} \d{2}:\d{2}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("PatternLayout modifiers test", function(t) {

+        var layout = new log4javascript.PatternLayout("%m|%3m|%-3m|%6m|%-6m|%.2m|%1.2m|%6.8m|%-1.2m|%-6.8m|");

+        t.appender.setLayout(layout);

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages[0], "TEST|TEST|TEST|  TEST|TEST  |ST|ST|  TEST|ST|TEST  |");

+    });

+

+    s.test("PatternLayout conversion characters test", function(t) {

+        var layout = new log4javascript.PatternLayout("%c %n %p %r literal %%");

+        t.appender.setLayout(layout);

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^test \s+ DEBUG \d+ literal %$/, t.appender.logMessages[0]);

+    });

+

+    s.test("PatternLayout message test", function(t) {

+        var layout = new log4javascript.PatternLayout("%m{1} %m{2}");

+        t.appender.setLayout(layout);

+        var testObj = {

+            strikers: {

+                quick: "Marlon"

+            }

+        };

+        t.logger.debug(testObj);

+        t.assertEquals("{\r\n  strikers: [object Object]\r\n} {\r\n\  strikers: {\r\n    quick: Marlon\r\n  }\r\n}", t.appender.logMessages[0]);

+    });

+/*

+	s.test("AjaxAppender JsonLayout single message test", function(t) {

+		t.async(10000);

+		// Create and add an Ajax appender

+		var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");

+		ajaxAppender.setLayout(new log4javascript.JsonLayout());

+		ajaxAppender.setRequestSuccessCallback(

+			function(xmlHttp) {

+				// Response comes back as JSON array of messages logged

+				var jsonResponse = xmlHttp.responseText;

+				var arr = eval(jsonResponse);

+				t.assertEquals(arr.length, 1);

+				t.assertEquals(arr[0], "TEST");

+				t.succeed();

+			}

+		);

+		ajaxAppender.setFailCallback(

+			function(msg) {

+				t.fail(msg);

+				ajaxErrorMessage = msg;

+			}

+		);

+		t.logger.addAppender(ajaxAppender);

+		t.logger.debug("TEST");

+	});

+

+	s.test("AjaxAppender JsonLayout batched messages test", function(t) {

+		t.async(10000);

+		var message1 = "TEST 1";

+		var message2 = "String with \"lots of 'quotes'\" + plusses in";

+		var message3 = "A non-threatening string";

+		// Create and add an Ajax appender

+		var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");

+		ajaxAppender.setLayout(new log4javascript.JsonLayout());

+		ajaxAppender.setBatchSize(3);

+		ajaxAppender.setRequestSuccessCallback(

+			function(xmlHttp) {

+				// Response comes back as JSON array of messages logged

+				var jsonResponse = xmlHttp.responseText;

+				var arr = eval(jsonResponse);

+				t.assertEquals(arr.length, 3);

+				t.assertEquals(arr[0], message1);

+				t.assertEquals(arr[1], message2);

+				t.assertEquals(arr[2], message3);

+				t.succeed();

+			}

+		);

+		ajaxAppender.setFailCallback(

+			function(msg) {

+				t.fail(msg);

+				ajaxErrorMessage = msg;

+			}

+		);

+		t.logger.addAppender(ajaxAppender);

+		t.logger.debug(message1);

+		t.logger.info(message2);

+		t.logger.warn(message3);

+	});

+

+	s.test("AjaxAppender HttpPostDataLayout single message test", function(t) {

+		t.async(10000);

+		// Create and add an Ajax appender

+		var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");

+		var testMessage = "TEST +\"1\"";

+		ajaxAppender.setLayout(new log4javascript.HttpPostDataLayout());

+		ajaxAppender.setRequestSuccessCallback(

+			function(xmlHttp) {

+				// Response comes back as JSON array of messages logged

+				var jsonResponse = xmlHttp.responseText;

+				var arr = eval(jsonResponse);

+				t.assertEquals(arr.length, 1);

+				t.assertEquals(arr[0], testMessage);

+				t.succeed();

+			}

+		);

+		ajaxAppender.setFailCallback(

+			function(msg) {

+				t.fail(msg);

+				ajaxErrorMessage = msg;

+			}

+		);

+		t.logger.addAppender(ajaxAppender);

+		t.logger.debug(testMessage);

+	});

+*/

+});
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_uncompressed.js
new file mode 100644
index 0000000..55bd2ca
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/js/tests/log4javascript_uncompressed.js
@@ -0,0 +1,862 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+function array_contains(arr, val) {

+	for (var i = 0; i < arr.length; i++) {

+		if (arr[i] == val) {

+			return true;

+		}

+	}

+	return false;

+}

+

+// Recursively checks that obj2's interface contains all of obj1's

+// interface (functions and objects only)

+function compareObjectInterface(obj1, obj1_name, obj2, obj2_name, namePrefix) {

+	if (!namePrefix) {

+		namePrefix = "";

+	}

+	var obj1PropertyNames = new Array();

+	for (var i in obj1) {

+		if (i != "prototype" && i != "arguments") {

+			obj1PropertyNames.push(i);

+		}

+	}

+	if (obj1 && obj1.prototype && !array_contains(obj1PropertyNames, "prototype")) {

+		//obj1PropertyNames.push("prototype");

+	}

+	for (var j = 0; j < obj1PropertyNames.length; j++) {

+		var propertyName = obj1PropertyNames[j];

+		if ((typeof obj1[propertyName] == "function" || typeof obj1[propertyName] == "object") && !(obj1[propertyName] instanceof Array)) {

+			var propertyFullyQualifiedName = (namePrefix == "") ? propertyName : namePrefix + "." + propertyName;

+			try {

+				if (typeof obj2[propertyName] == "undefined") {

+					throw new Error(obj2_name + " does not contain " + propertyFullyQualifiedName + " in " + obj1_name);

+				} else if (typeof obj2[propertyName] != typeof obj1[propertyName]){

+					throw new Error(obj2_name + "'s " + propertyFullyQualifiedName + " is of the wrong type: " + typeof obj2[propertyName] + " when it is type " + typeof obj1[propertyName] + " in " + obj1_name);

+				} else if (obj1[propertyName] != Function.prototype.apply) {

+					if (!compareObjectInterface(obj1[propertyName], obj1_name, obj2[propertyName], obj2_name, propertyFullyQualifiedName)) {

+						throw new Error("Interfaces don't match");

+					}

+				}

+			} catch(ex) {

+				throw new Error("Exception while checking property name " + propertyFullyQualifiedName + " in " + obj2_name + ": " + ex.message);

+			}

+		}

+	}

+	return true;

+};

+

+// Simply tests a layout for exceptions when formatting

+var testLayoutWithVariables = function(layout, t) {

+	var emptyObject = {};

+	var emptyArray = [];

+	var emptyString = "";

+	var localUndefined = emptyArray[0];

+	var oneLevelObject = {

+		"name": "One-level object"

+	};

+	var twoLevelObject = {

+		"name": "Two-level object",

+		"data": oneLevelObject

+	};

+	var threeLevelObject = {

+		"name": "Three-level object",

+		"data": twoLevelObject

+	};

+	var anArray = [

+		3,

+		"stuff",

+		true,

+		false,

+		0,

+		null,

+		localUndefined,

+		3.14,

+		function(p) { return "I'm a function"; },

+		[1, "things"]

+	];

+	var arrayOfTestItems = [emptyObject, emptyString, emptyString, localUndefined, oneLevelObject,

+			twoLevelObject, threeLevelObject, anArray];

+

+	t.log("Testing layout " + layout)

+	for (var i = 0; i < arrayOfTestItems.length; i++) {

+		var ex = new Error("Test error");

+		var loggingEvent = new log4javascript.LoggingEvent(t.logger, new Date(), log4javascript.Level.INFO,

+				[arrayOfTestItems[i]], null);

+		t.log("Formatting", arrayOfTestItems[i], result);

+		var result = layout.format(loggingEvent);

+		// Now try with an exception

+		loggingEvent.exception = ex;

+		t.log("Formatting with exception", arrayOfTestItems[i], result);

+		result = layout.format(loggingEvent);

+	}

+};

+

+xn.test.enableTestDebug = true;

+xn.test.enable_log4javascript = false;

+

+xn.test.suite("log4javascript tests", function(s) {

+	log4javascript.logLog.setQuietMode(true);

+	var ArrayAppender = function(layout) {

+		if (layout) {

+			this.setLayout(layout);

+		}

+		this.logMessages = [];

+	};

+

+	ArrayAppender.prototype = new log4javascript.Appender();

+

+	ArrayAppender.prototype.layout = new log4javascript.NullLayout();

+

+	ArrayAppender.prototype.append = function(loggingEvent) {

+		var formattedMessage = this.getLayout().format(loggingEvent);

+		if (this.getLayout().ignoresThrowable()) {

+			formattedMessage += loggingEvent.getThrowableStrRep();

+		}

+		this.logMessages.push(formattedMessage);

+	};

+

+	ArrayAppender.prototype.toString = function() {

+		return "[ArrayAppender]";

+	};

+

+    s.setUp = function(t) {

+        t.logger = log4javascript.getLogger("test");

+		t.logger.removeAllAppenders();

+		t.appender = new ArrayAppender();

+        t.logger.addAppender(t.appender);

+    };

+

+    s.tearDown = function(t) {

+        t.logger.removeAppender(t.appender);

+		log4javascript.resetConfiguration();

+	};

+

+    s.test("Stub script interface test", function(t) {

+        try {

+            compareObjectInterface(log4javascript, "log4javascript", log4javascript_stub, "log4javascript_stub");

+        } catch (ex) {

+            t.fail(ex);

+        }

+    });

+

+	s.test("Disable log4javascript test", function(t) {

+		log4javascript.setEnabled(false);

+		t.logger.debug("TEST");

+		t.assertEquals(t.appender.logMessages.length, 0);

+		log4javascript.setEnabled(true);

+	});

+

+    s.test("Array.splice test 1", function(t) {

+        var a = ["Marlon", "Ashley", "Darius", "Lloyd"];

+        var deletedItems = a.splice(1, 2);

+        t.assertEquals(a.join(","), "Marlon,Lloyd");

+        t.assertEquals(deletedItems.join(","), "Ashley,Darius");

+    });

+

+    s.test("Array.splice test 2", function(t) {

+        var a = ["Marlon", "Ashley", "Darius", "Lloyd"];

+        var deletedItems = a.splice(1, 1, "Malky", "Jay");

+        t.assertEquals(a.join(","), "Marlon,Malky,Jay,Darius,Lloyd");

+        t.assertEquals(deletedItems.join(","), "Ashley");

+    });

+

+    s.test("array_remove test", function(t) {

+        var array_remove = log4javascript.evalInScope("array_remove");

+        var a = ["Marlon", "Ashley", "Darius"];

+        array_remove(a, "Darius");

+        t.assertEquals(a.join(","), "Marlon,Ashley");

+    });

+

+	s.test("array_remove with empty array test", function(t) {

+		var array_remove = log4javascript.evalInScope("array_remove");

+		var a = [];

+		array_remove(a, "Darius");

+		t.assertEquals(a.join(","), "");

+	});

+

+    s.test("Logger logging test", function(t) {

+        // Should log since the default level for loggers is DEBUG and

+        // the default threshold for appenders is ALL

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages.length, 1);

+    });

+

+    s.test("Logger levels test", function(t) {

+        var originalLevel = t.logger.getEffectiveLevel();

+        t.logger.setLevel(log4javascript.Level.INFO);

+        t.logger.debug("TEST");

+		t.logger.setLevel(originalLevel);

+        t.assertEquals(t.appender.logMessages.length, 0);

+    });

+

+	s.test("Logger getEffectiveLevel inheritance test 1", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		parentLogger.setLevel(log4javascript.Level.ERROR);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.ERROR);

+	});

+

+	s.test("Logger getEffectiveLevel inheritance test 2", function(t) {

+		var grandParentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2.test3");

+		grandParentLogger.setLevel(log4javascript.Level.ERROR);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.ERROR);

+	});

+

+	s.test("Logger getEffectiveLevel inheritance test 3", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		parentLogger.setLevel(log4javascript.Level.ERROR);

+		childLogger.setLevel(log4javascript.Level.INFO);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.INFO);

+	});

+

+	s.test("Logger getEffectiveLevel root inheritance test", function(t) {

+		var rootLogger = log4javascript.getRootLogger();

+		var childLogger = log4javascript.getLogger("test1.test2.test3");

+		rootLogger.setLevel(log4javascript.Level.WARN);

+		t.assertEquals(childLogger.getEffectiveLevel(), log4javascript.Level.WARN);

+	});

+

+	s.test("Logger null level test", function(t) {

+		t.logger.setLevel(null);

+		// Should default to root logger level, which is DEBUG

+		t.assertEquals(t.logger.getEffectiveLevel(), log4javascript.Level.DEBUG);

+	});

+

+	s.test("Logger appender additivity test 1", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		var parentLoggerAppender = new ArrayAppender();

+		var childLoggerAppender = new ArrayAppender();

+

+		parentLogger.addAppender(parentLoggerAppender);

+		childLogger.addAppender(childLoggerAppender);

+

+		parentLogger.info("Parent logger test message");

+		childLogger.info("Child logger test message");

+

+		t.assertEquals(parentLoggerAppender.logMessages.length, 2);

+		t.assertEquals(childLoggerAppender.logMessages.length, 1);

+	});

+

+	s.test("Logger appender additivity test 2", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		var parentLoggerAppender = new ArrayAppender();

+		var childLoggerAppender = new ArrayAppender();

+

+		parentLogger.addAppender(parentLoggerAppender);

+		childLogger.addAppender(childLoggerAppender);

+

+		childLogger.setAdditivity(false);

+

+		parentLogger.info("Parent logger test message");

+		childLogger.info("Child logger test message");

+

+		t.assertEquals(parentLoggerAppender.logMessages.length, 1);

+		t.assertEquals(childLoggerAppender.logMessages.length, 1);

+	});

+

+	s.test("Logger appender additivity test 3", function(t) {

+		var parentLogger = log4javascript.getLogger("test1");

+		var childLogger = log4javascript.getLogger("test1.test2");

+		var parentLoggerAppender = new ArrayAppender();

+		var childLoggerAppender = new ArrayAppender();

+

+		parentLogger.addAppender(parentLoggerAppender);

+		childLogger.addAppender(childLoggerAppender);

+

+		childLogger.setAdditivity(false);

+

+		parentLogger.info("Parent logger test message");

+		childLogger.info("Child logger test message");

+

+		childLogger.setAdditivity(true);

+

+		childLogger.info("Child logger test message 2");

+

+		t.assertEquals(parentLoggerAppender.logMessages.length, 2);

+		t.assertEquals(childLoggerAppender.logMessages.length, 2);

+	});

+

+	s.test("Appender threshold test", function(t) {

+        t.appender.setThreshold(log4javascript.Level.INFO);

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages.length, 0);

+    });

+

+    s.test("Basic appender / layout test", function(t) {

+        t.logger.debug("TEST");

+		t.assertEquals(t.appender.logMessages[0], "TEST");

+    });

+

+	s.test("Appender uniqueness within logger test", function(t) {

+		// Add the same appender to the logger for a second time

+		t.logger.addAppender(t.appender);

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages.length, 1);

+    });

+

+	s.test("Logger remove appender test", function(t) {

+		t.logger.debug("TEST");

+		t.logger.removeAppender(t.appender);

+		t.logger.debug("TEST AGAIN");

+		t.assertEquals(t.appender.logMessages.length, 1);

+	});

+

+	s.test("", function(t) {

+		t.logger.debug("TEST");

+		t.logger.removeAppender(t.appender);

+		t.logger.debug("TEST AGAIN");

+		t.assertEquals(t.appender.logMessages.length, 1);

+	});

+	s.test("SimpleLayout format test", function(t) {

+		var layout = new log4javascript.SimpleLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("SimpleLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.SimpleLayout());

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages[0], "DEBUG - TEST");

+    });

+	s.test("NullLayout format test", function(t) {

+		var layout = new log4javascript.NullLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("NullLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.NullLayout());

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages[0], "TEST");

+    });

+	s.test("XmlLayout format test", function(t) {

+		var layout = new log4javascript.XmlLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("XmlLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.XmlLayout());

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<\/log4javascript:event>\s*$/, t.appender.logMessages[0]);

+    });

+

+    s.test("XmlLayout with exception test", function(t) {

+        t.appender.setLayout(new log4javascript.XmlLayout());

+        t.logger.debug("TEST", new Error("Test error"));

+        t.assertRegexMatches(/^<log4javascript:event logger="test" timestamp="\d+" level="DEBUG">\s*<log4javascript:message><!\[CDATA\[TEST\]\]><\/log4javascript:message>\s*<log4javascript:exception>\s*<!\[CDATA\[.*\]\]><\/log4javascript:exception>\s*<\/log4javascript:event>\s*$/, t.appender.logMessages[0]);

+    });

+

+	var setUpXmlLayoutMillisecondsTest = function(t) {

+		t.date = new Date();

+		t.timeInMilliseconds = t.date.getTime();

+		t.timeInSeconds = Math.floor(t.timeInMilliseconds / 1000);

+		t.milliseconds = t.date.getMilliseconds();

+		

+		t.loggingEvent = new log4javascript.LoggingEvent(t.logger, t.date, log4javascript.Level.DEBUG, ["TEST"], null);

+		t.layout = new log4javascript.XmlLayout();

+	}

+

+	s.test("XmlLayout seconds/milliseconds test 1", function(t) {

+		setUpXmlLayoutMillisecondsTest(t);

+

+		// Test default (i.e. timestamps in milliseconds) first

+        var regex = new RegExp('^<log4javascript:event logger="test" timestamp="' + t.timeInMilliseconds + '" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');

+        t.assertRegexMatches(regex, t.layout.format(t.loggingEvent));

+	});

+	

+	s.test("XmlLayout seconds/milliseconds test 2", function(t) {

+		setUpXmlLayoutMillisecondsTest(t);

+

+        // Change the global setting

+        log4javascript.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        log4javascript.setTimeStampsInMilliseconds(true);

+        var regex = new RegExp('^<log4javascript:event logger="test" timestamp="' + t.timeInSeconds + '" milliseconds="' + t.milliseconds + '" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');

+        t.assertRegexMatches(regex, formatted);

+	});

+

+	s.test("XmlLayout seconds/milliseconds test 3", function(t) {

+		setUpXmlLayoutMillisecondsTest(t);

+

+        // Change the layout setting

+        t.layout.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        var regex = new RegExp('^<log4javascript:event logger="test" timestamp="' + t.timeInSeconds + '" milliseconds="' + t.milliseconds + '" level="DEBUG">\\s*<log4javascript:message><!\\[CDATA\\[TEST\\]\\]></log4javascript:message>\\s*</log4javascript:event>\\s*$');

+        t.assertRegexMatches(regex, formatted);

+	});

+	s.test("escapeNewLines test", function(t) {

+		var escapeNewLines = log4javascript.evalInScope("escapeNewLines");

+		var str = "1\r2\n3\n4\r\n5\r6\r\n7";

+		t.assertEquals(escapeNewLines(str), "1\\r\\n2\\r\\n3\\r\\n4\\r\\n5\\r\\n6\\r\\n7");

+	});

+

+	s.test("JsonLayout format test", function(t) {

+		var layout = new log4javascript.JsonLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("JsonLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST"}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout JSON validity test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TEST");

+        eval("var o = " + t.appender.logMessages[0]);

+        t.assertEquals(o.message, "TEST");

+    });

+

+    s.test("JsonLayout with number type message test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug(15);

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":15}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with object type message test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug({});

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"\[object Object\]"}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with boolean type message test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug(false);

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":false}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with quote test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TE\"S\"T");

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TE\\"S\\"T"}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("JsonLayout with exception test", function(t) {

+        t.appender.setLayout(new log4javascript.JsonLayout());

+        t.logger.debug("TEST", new Error("Test error"));

+        t.assertRegexMatches(/^{"logger":"test","timestamp":\d+,"level":"DEBUG","url":".*","message":"TEST","exception":.*}$/, t.appender.logMessages[0]);

+    });

+

+	var setUpJsonLayoutMillisecondsTest = function(t) {

+		t.date = new Date();

+		t.timeInMilliseconds = t.date.getTime();

+		t.timeInSeconds = Math.floor(t.timeInMilliseconds / 1000);

+		t.milliseconds = t.date.getMilliseconds();

+		

+		t.loggingEvent = new log4javascript.LoggingEvent(t.logger, t.date, log4javascript.Level.DEBUG, ["TEST"], null);

+		t.layout = new log4javascript.JsonLayout();

+	};

+

+	s.test("JsonLayout seconds/milliseconds test 1", function(t) {

+		setUpJsonLayoutMillisecondsTest(t);

+

+		// Test default (i.e. timestamps in milliseconds) first

+        var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInMilliseconds + ',"level":"DEBUG","url":".*","message":"TEST"}$');

+        t.assertRegexMatches(regex, t.layout.format(t.loggingEvent));

+	});

+	

+	s.test("JsonLayout seconds/milliseconds test 2", function(t) {

+		setUpJsonLayoutMillisecondsTest(t);

+

+        // Change the global setting

+        log4javascript.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        log4javascript.setTimeStampsInMilliseconds(true);

+        var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInSeconds + ',"level":"DEBUG","url":".*","message":"TEST","milliseconds":' + t.milliseconds + '}$');

+        t.assertRegexMatches(regex, formatted);

+	});

+

+	s.test("JsonLayout seconds/milliseconds test 3", function(t) {

+		setUpJsonLayoutMillisecondsTest(t);

+

+        // Change the layout setting

+        t.layout.setTimeStampsInMilliseconds(false);

+        var formatted = t.layout.format(t.loggingEvent);

+        var regex = new RegExp('^{"logger":"test","timestamp":' + t.timeInSeconds + ',"level":"DEBUG","url":".*","message":"TEST","milliseconds":' + t.milliseconds + '}$');

+        t.assertRegexMatches(regex, formatted);

+	});

+	s.test("HttpPostDataLayout format test", function(t) {

+		var layout = new log4javascript.HttpPostDataLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("HttpPostDataLayout test", function(t) {

+        t.appender.setLayout(new log4javascript.HttpPostDataLayout());

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST$/, t.appender.logMessages[0]);

+    });

+

+    s.test("HttpPostDataLayout URL encoding test", function(t) {

+        t.appender.setLayout(new log4javascript.HttpPostDataLayout());

+        t.logger.debug("TEST +\"1\"");

+        t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST%20%2B%221%22$/, t.appender.logMessages[0]);

+    });

+

+    s.test("HttpPostDataLayout with exception test", function(t) {

+        t.appender.setLayout(new log4javascript.HttpPostDataLayout());

+        t.logger.debug("TEST", new Error("Test error"));

+        t.assertRegexMatches(/^logger=test&timestamp=\d+&level=DEBUG&url=.*&message=TEST&exception=.*$/, t.appender.logMessages[0]);

+    });

+

+	(function() {

+		var formatObjectExpansion = log4javascript.evalInScope("formatObjectExpansion");

+		var newLine = log4javascript.evalInScope("newLine");

+		var arr = [

+			null,

+			undefined,

+			1.2,

+			"A string",

+			[1, "test"],

+			{

+				a: {

+					b: 1

+				}

+			}

+		];

+

+		s.test("Basic formatObjectExpansion array test (depth: 1)", function(t) {

+			t.assertEquals(formatObjectExpansion(arr, 1),

+				"[" + newLine +

+				"  null," + newLine +

+				"  undefined," + newLine +

+				"  1.2," + newLine +

+				"  A string," + newLine +

+				"  1,test," + newLine +

+				"  [object Object]" + newLine +

+				"]"

+			);

+		});

+

+		s.test("Basic formatObjectExpansion array test (depth: 2)", function(t) {

+			t.assertEquals(formatObjectExpansion(arr, 2),

+				"[" + newLine +

+				"  null," + newLine +

+				"  undefined," + newLine +

+				"  1.2," + newLine +

+				"  A string," + newLine +

+				"  [" + newLine +

+				"    1," + newLine +

+				"    test" + newLine +

+				"  ]," + newLine +

+				"  {" + newLine +

+				"    a: [object Object]" + newLine +

+				"  }" + newLine +

+				"]"

+			);

+		});

+

+		s.test("formatObjectExpansion simple object test", function(t) {

+			var obj = {

+				STRING: "A string"

+			};

+			t.assertEquals(formatObjectExpansion(obj, 1), 

+				"{" + newLine +

+				"  STRING: A string" + newLine +

+				"}"

+			);

+		});

+

+		s.test("formatObjectExpansion simple circular object test", function(t) {

+			var obj = {};

+			obj.a = obj;

+			

+			t.assertEquals(formatObjectExpansion(obj, 2), 

+				"{" + newLine +

+				"  a: [object Object] [already expanded]" + newLine +

+				"}"

+			);

+		});

+	})();    /* ---------------------------------------------------------- */

+

+    var getSampleDate = function() {

+        var date = new Date();

+        date.setFullYear(2006);

+        date.setMonth(7);

+        date.setDate(30);

+        date.setHours(15);

+        date.setMinutes(38);

+        date.setSeconds(45);

+        return date;

+    };

+

+    /* ---------------------------------------------------------- */

+

+    s.test("String.replace test", function(t) {

+        t.assertEquals("Hello world".replace(/o/g, "Z"), "HellZ wZrld");

+    });

+

+	s.test("PatternLayout format test", function(t) {

+		var layout = new log4javascript.PatternLayout();

+		testLayoutWithVariables(layout, t);

+	});

+

+    s.test("PatternLayout dates test", function(t) {

+        var layout = new log4javascript.PatternLayout("%d %d{DATE} %d{HH:ss}");

+        t.appender.setLayout(layout);

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3} \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2},\d{3} \d{2}:\d{2}$/, t.appender.logMessages[0]);

+    });

+

+    s.test("PatternLayout modifiers test", function(t) {

+        var layout = new log4javascript.PatternLayout("%m|%3m|%-3m|%6m|%-6m|%.2m|%1.2m|%6.8m|%-1.2m|%-6.8m|");

+        t.appender.setLayout(layout);

+        t.logger.debug("TEST");

+        t.assertEquals(t.appender.logMessages[0], "TEST|TEST|TEST|  TEST|TEST  |ST|ST|  TEST|ST|TEST  |");

+    });

+

+    s.test("PatternLayout conversion characters test", function(t) {

+        var layout = new log4javascript.PatternLayout("%c %n %p %r literal %%");

+        t.appender.setLayout(layout);

+        t.logger.debug("TEST");

+        t.assertRegexMatches(/^test \s+ DEBUG \d+ literal %$/, t.appender.logMessages[0]);

+    });

+

+    s.test("PatternLayout message test", function(t) {

+        var layout = new log4javascript.PatternLayout("%m{1} %m{2}");

+        t.appender.setLayout(layout);

+        var testObj = {

+            strikers: {

+                quick: "Marlon"

+            }

+        };

+        t.logger.debug(testObj);

+        t.assertEquals("{\r\n  strikers: [object Object]\r\n} {\r\n\  strikers: {\r\n    quick: Marlon\r\n  }\r\n}", t.appender.logMessages[0]);

+    });

+	// Tests for exceptions when logging

+	s.test("Logging/grouping test", function(t) {

+		var browserConsoleAppender = new log4javascript.BrowserConsoleAppender();

+		t.logger.addAppender(browserConsoleAppender);

+

+		// Test each level

+		t.logger.trace("TEST TRACE");

+		t.logger.debug("TEST DEBUG");

+		t.logger.info("TEST INFO");

+		t.logger.warn("TEST WARN");

+		t.logger.error("TEST ERROR");

+		t.logger.fatal("TEST FATAL");

+		

+		// Test with exception

+		t.logger.fatal("TEST FATAL", new Error("Fake error"));

+		

+		// Test multiple messages

+		t.logger.info("TEST INFO", "Second message", ["a", "b", "c"]);

+		

+		// Test groups

+		t.logger.group("TEST GROUP");

+		t.logger.info("TEST INFO");

+		t.logger.groupEnd("TEST GROUP");

+		t.logger.info("TEST INFO");

+		

+		t.logger.removeAppender(browserConsoleAppender);

+	});

+

+/*

+	s.test("AjaxAppender JsonLayout single message test", function(t) {

+		t.async(10000);

+		// Create and add an Ajax appender

+		var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");

+		ajaxAppender.setLayout(new log4javascript.JsonLayout());

+		ajaxAppender.setRequestSuccessCallback(

+			function(xmlHttp) {

+				// Response comes back as JSON array of messages logged

+				var jsonResponse = xmlHttp.responseText;

+				var arr = eval(jsonResponse);

+				t.assertEquals(arr.length, 1);

+				t.assertEquals(arr[0], "TEST");

+				t.succeed();

+			}

+		);

+		ajaxAppender.setFailCallback(

+			function(msg) {

+				t.fail(msg);

+				ajaxErrorMessage = msg;

+			}

+		);

+		t.logger.addAppender(ajaxAppender);

+		t.logger.debug("TEST");

+	});

+

+	s.test("AjaxAppender JsonLayout batched messages test", function(t) {

+		t.async(10000);

+		var message1 = "TEST 1";

+		var message2 = "String with \"lots of 'quotes'\" + plusses in";

+		var message3 = "A non-threatening string";

+		// Create and add an Ajax appender

+		var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");

+		ajaxAppender.setLayout(new log4javascript.JsonLayout());

+		ajaxAppender.setBatchSize(3);

+		ajaxAppender.setRequestSuccessCallback(

+			function(xmlHttp) {

+				// Response comes back as JSON array of messages logged

+				var jsonResponse = xmlHttp.responseText;

+				var arr = eval(jsonResponse);

+				t.assertEquals(arr.length, 3);

+				t.assertEquals(arr[0], message1);

+				t.assertEquals(arr[1], message2);

+				t.assertEquals(arr[2], message3);

+				t.succeed();

+			}

+		);

+		ajaxAppender.setFailCallback(

+			function(msg) {

+				t.fail(msg);

+				ajaxErrorMessage = msg;

+			}

+		);

+		t.logger.addAppender(ajaxAppender);

+		t.logger.debug(message1);

+		t.logger.info(message2);

+		t.logger.warn(message3);

+	});

+

+	s.test("AjaxAppender HttpPostDataLayout single message test", function(t) {

+		t.async(10000);

+		// Create and add an Ajax appender

+		var ajaxAppender = new log4javascript.AjaxAppender("../log4javascript.do");

+		var testMessage = "TEST +\"1\"";

+		ajaxAppender.setLayout(new log4javascript.HttpPostDataLayout());

+		ajaxAppender.setRequestSuccessCallback(

+			function(xmlHttp) {

+				// Response comes back as JSON array of messages logged

+				var jsonResponse = xmlHttp.responseText;

+				var arr = eval(jsonResponse);

+				t.assertEquals(arr.length, 1);

+				t.assertEquals(arr[0], testMessage);

+				t.succeed();

+			}

+		);

+		ajaxAppender.setFailCallback(

+			function(msg) {

+				t.fail(msg);

+				ajaxErrorMessage = msg;

+			}

+		);

+		t.logger.addAppender(ajaxAppender);

+		t.logger.debug(testMessage);

+	});

+*/

+	var testConsoleAppender = function(t, appender) {

+		var timeoutCallback = function() {

+			//alert("Failed. Debug messages follow.");

+			//log4javascript.logLog.displayDebug();

+			return (windowLoaded ? "Timed out while waiting for messages to appear" :

+				   "Timed out while waiting for window to load") + ". Debug messages: " +

+				   log4javascript.logLog.debugMessages.join("\r\n");

+		}

+

+		t.async(60000, timeoutCallback);

+

+		var windowLoaded = false;

+		var domChecked = false;

+

+		// Set a timeout to allow the pop-up to appear

+		var onLoadHandler = function() {

+			log4javascript.logLog.debug("onLoadHandler");

+			windowLoaded = true;

+			var win = appender.getConsoleWindow();

+

+			if (win && win.loaded) {

+				// Check that the log container element contains the log message. Since

+				// the console window waits 100 milliseconds before actually rendering the

+				// message as a DOM element, we need to use a timer

+				var checkDom = function() {

+					log4javascript.logLog.debug("checkDom");

+					domChecked = true;

+					var logContainer = win.logMainContainer;

+					if (logContainer.hasChildNodes()) {

+						if (logContainer.innerHTML.indexOf("TEST MESSAGE") == -1) {

+							appender.close();

+							t.fail("Log message not correctly logged (log container innerHTML: " + logContainer.innerHTML + ")");

+						} else {

+							t.assert(appender.isVisible());

+							appender.close();

+							t.assert(!appender.isVisible());

+							t.succeed();

+						}

+					} else {

+						appender.close();

+						t.fail("Console has no log messages");

+					}

+				}

+				window.setTimeout(checkDom, 300);

+			} else {

+				appender.close();

+				t.fail("Console mistakenly raised load event");

+			}

+		}

+

+		appender.addEventListener("load", onLoadHandler);

+		t.logger.addAppender(appender);

+		t.logger.debug("TEST MESSAGE");

+	};

+

+	s.test("InlineAppender test", function(t) {

+		var inlineAppender = new log4javascript.InlineAppender();

+		inlineAppender.setInitiallyMinimized(false);

+		inlineAppender.setNewestMessageAtTop(false);

+		inlineAppender.setScrollToLatestMessage(true);

+		inlineAppender.setWidth(600);

+		inlineAppender.setHeight(200);

+

+		testConsoleAppender(t, inlineAppender);

+	});

+

+	s.test("InPageAppender with separate console HTML file test", function(t) {

+		var inPageAppender = new log4javascript.InPageAppender();

+		inPageAppender.setInitiallyMinimized(false);

+		inPageAppender.setNewestMessageAtTop(false);

+		inPageAppender.setScrollToLatestMessage(true);

+		inPageAppender.setUseDocumentWrite(false);

+		inPageAppender.setWidth(600);

+		inPageAppender.setHeight(200);

+

+		testConsoleAppender(t, inPageAppender);

+	});

+

+	s.test("PopUpAppender test", function(t) {

+		var popUpAppender = new log4javascript.PopUpAppender();

+		popUpAppender.setFocusPopUp(true);

+		popUpAppender.setUseOldPopUp(false);

+		popUpAppender.setNewestMessageAtTop(false);

+		popUpAppender.setScrollToLatestMessage(true);

+		popUpAppender.setComplainAboutPopUpBlocking(false);

+		popUpAppender.setWidth(600);

+		popUpAppender.setHeight(200);

+

+		testConsoleAppender(t, popUpAppender);

+		

+		

+	});

+

+	s.test("PopUpAppender with separate console HTML file test", function(t) {

+		var popUpAppender = new log4javascript.PopUpAppender();

+		popUpAppender.setFocusPopUp(true);

+		popUpAppender.setUseOldPopUp(false);

+		popUpAppender.setNewestMessageAtTop(false);

+		popUpAppender.setScrollToLatestMessage(true);

+		popUpAppender.setComplainAboutPopUpBlocking(false);

+		popUpAppender.setUseDocumentWrite(false);

+		popUpAppender.setWidth(600);

+		popUpAppender.setHeight(200);

+

+		testConsoleAppender(t, popUpAppender);

+	});

+});
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/license.txt b/planetstack/core/static/log4javascript-1.4.6/license.txt
new file mode 100644
index 0000000..29f81d8
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/license.txt
@@ -0,0 +1,201 @@
+                                 Apache License

+                           Version 2.0, January 2004

+                        http://www.apache.org/licenses/

+

+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

+

+   1. Definitions.

+

+      "License" shall mean the terms and conditions for use, reproduction,

+      and distribution as defined by Sections 1 through 9 of this document.

+

+      "Licensor" shall mean the copyright owner or entity authorized by

+      the copyright owner that is granting the License.

+

+      "Legal Entity" shall mean the union of the acting entity and all

+      other entities that control, are controlled by, or are under common

+      control with that entity. For the purposes of this definition,

+      "control" means (i) the power, direct or indirect, to cause the

+      direction or management of such entity, whether by contract or

+      otherwise, or (ii) ownership of fifty percent (50%) or more of the

+      outstanding shares, or (iii) beneficial ownership of such entity.

+

+      "You" (or "Your") shall mean an individual or Legal Entity

+      exercising permissions granted by this License.

+

+      "Source" form shall mean the preferred form for making modifications,

+      including but not limited to software source code, documentation

+      source, and configuration files.

+

+      "Object" form shall mean any form resulting from mechanical

+      transformation or translation of a Source form, including but

+      not limited to compiled object code, generated documentation,

+      and conversions to other media types.

+

+      "Work" shall mean the work of authorship, whether in Source or

+      Object form, made available under the License, as indicated by a

+      copyright notice that is included in or attached to the work

+      (an example is provided in the Appendix below).

+

+      "Derivative Works" shall mean any work, whether in Source or Object

+      form, that is based on (or derived from) the Work and for which the

+      editorial revisions, annotations, elaborations, or other modifications

+      represent, as a whole, an original work of authorship. For the purposes

+      of this License, Derivative Works shall not include works that remain

+      separable from, or merely link (or bind by name) to the interfaces of,

+      the Work and Derivative Works thereof.

+

+      "Contribution" shall mean any work of authorship, including

+      the original version of the Work and any modifications or additions

+      to that Work or Derivative Works thereof, that is intentionally

+      submitted to Licensor for inclusion in the Work by the copyright owner

+      or by an individual or Legal Entity authorized to submit on behalf of

+      the copyright owner. For the purposes of this definition, "submitted"

+      means any form of electronic, verbal, or written communication sent

+      to the Licensor or its representatives, including but not limited to

+      communication on electronic mailing lists, source code control systems,

+      and issue tracking systems that are managed by, or on behalf of, the

+      Licensor for the purpose of discussing and improving the Work, but

+      excluding communication that is conspicuously marked or otherwise

+      designated in writing by the copyright owner as "Not a Contribution."

+

+      "Contributor" shall mean Licensor and any individual or Legal Entity

+      on behalf of whom a Contribution has been received by Licensor and

+      subsequently incorporated within the Work.

+

+   2. Grant of Copyright License. Subject to the terms and conditions of

+      this License, each Contributor hereby grants to You a perpetual,

+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable

+      copyright license to reproduce, prepare Derivative Works of,

+      publicly display, publicly perform, sublicense, and distribute the

+      Work and such Derivative Works in Source or Object form.

+

+   3. Grant of Patent License. Subject to the terms and conditions of

+      this License, each Contributor hereby grants to You a perpetual,

+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable

+      (except as stated in this section) patent license to make, have made,

+      use, offer to sell, sell, import, and otherwise transfer the Work,

+      where such license applies only to those patent claims licensable

+      by such Contributor that are necessarily infringed by their

+      Contribution(s) alone or by combination of their Contribution(s)

+      with the Work to which such Contribution(s) was submitted. If You

+      institute patent litigation against any entity (including a

+      cross-claim or counterclaim in a lawsuit) alleging that the Work

+      or a Contribution incorporated within the Work constitutes direct

+      or contributory patent infringement, then any patent licenses

+      granted to You under this License for that Work shall terminate

+      as of the date such litigation is filed.

+

+   4. Redistribution. You may reproduce and distribute copies of the

+      Work or Derivative Works thereof in any medium, with or without

+      modifications, and in Source or Object form, provided that You

+      meet the following conditions:

+

+      (a) You must give any other recipients of the Work or

+          Derivative Works a copy of this License; and

+

+      (b) You must cause any modified files to carry prominent notices

+          stating that You changed the files; and

+

+      (c) You must retain, in the Source form of any Derivative Works

+          that You distribute, all copyright, patent, trademark, and

+          attribution notices from the Source form of the Work,

+          excluding those notices that do not pertain to any part of

+          the Derivative Works; and

+

+      (d) If the Work includes a "NOTICE" text file as part of its

+          distribution, then any Derivative Works that You distribute must

+          include a readable copy of the attribution notices contained

+          within such NOTICE file, excluding those notices that do not

+          pertain to any part of the Derivative Works, in at least one

+          of the following places: within a NOTICE text file distributed

+          as part of the Derivative Works; within the Source form or

+          documentation, if provided along with the Derivative Works; or,

+          within a display generated by the Derivative Works, if and

+          wherever such third-party notices normally appear. The contents

+          of the NOTICE file are for informational purposes only and

+          do not modify the License. You may add Your own attribution

+          notices within Derivative Works that You distribute, alongside

+          or as an addendum to the NOTICE text from the Work, provided

+          that such additional attribution notices cannot be construed

+          as modifying the License.

+

+      You may add Your own copyright statement to Your modifications and

+      may provide additional or different license terms and conditions

+      for use, reproduction, or distribution of Your modifications, or

+      for any such Derivative Works as a whole, provided Your use,

+      reproduction, and distribution of the Work otherwise complies with

+      the conditions stated in this License.

+

+   5. Submission of Contributions. Unless You explicitly state otherwise,

+      any Contribution intentionally submitted for inclusion in the Work

+      by You to the Licensor shall be under the terms and conditions of

+      this License, without any additional terms or conditions.

+      Notwithstanding the above, nothing herein shall supersede or modify

+      the terms of any separate license agreement you may have executed

+      with Licensor regarding such Contributions.

+

+   6. Trademarks. This License does not grant permission to use the trade

+      names, trademarks, service marks, or product names of the Licensor,

+      except as required for reasonable and customary use in describing the

+      origin of the Work and reproducing the content of the NOTICE file.

+

+   7. Disclaimer of Warranty. Unless required by applicable law or

+      agreed to in writing, Licensor provides the Work (and each

+      Contributor provides its Contributions) on an "AS IS" BASIS,

+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or

+      implied, including, without limitation, any warranties or conditions

+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A

+      PARTICULAR PURPOSE. You are solely responsible for determining the

+      appropriateness of using or redistributing the Work and assume any

+      risks associated with Your exercise of permissions under this License.

+

+   8. Limitation of Liability. In no event and under no legal theory,

+      whether in tort (including negligence), contract, or otherwise,

+      unless required by applicable law (such as deliberate and grossly

+      negligent acts) or agreed to in writing, shall any Contributor be

+      liable to You for damages, including any direct, indirect, special,

+      incidental, or consequential damages of any character arising as a

+      result of this License or out of the use or inability to use the

+      Work (including but not limited to damages for loss of goodwill,

+      work stoppage, computer failure or malfunction, or any and all

+      other commercial damages or losses), even if such Contributor

+      has been advised of the possibility of such damages.

+

+   9. Accepting Warranty or Additional Liability. While redistributing

+      the Work or Derivative Works thereof, You may choose to offer,

+      and charge a fee for, acceptance of support, warranty, indemnity,

+      or other liability obligations and/or rights consistent with this

+      License. However, in accepting such obligations, You may act only

+      on Your own behalf and on Your sole responsibility, not on behalf

+      of any other Contributor, and only if You agree to indemnify,

+      defend, and hold each Contributor harmless for any liability

+      incurred by, or claims asserted against, such Contributor by reason

+      of your accepting any such warranty or additional liability.

+

+   END OF TERMS AND CONDITIONS

+

+   APPENDIX: How to apply the Apache License to your work.

+

+      To apply the Apache License to your work, attach the following

+      boilerplate notice, with the fields enclosed by brackets "[]"

+      replaced with your own identifying information. (Don't include

+      the brackets!)  The text should be enclosed in the appropriate

+      comment syntax for the file format. We also recommend that a

+      file or class name and description of purpose be included on the

+      same "printed page" as the copyright notice for easier

+      identification within third-party archives.

+

+   Copyright [yyyy] [name of copyright owner]

+

+   Licensed under the Apache License, Version 2.0 (the "License");

+   you may not use this file except in compliance with the License.

+   You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

diff --git a/planetstack/core/static/log4javascript-1.4.6/log4javascript.js b/planetstack/core/static/log4javascript-1.4.6/log4javascript.js
new file mode 100644
index 0000000..042daa9
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/log4javascript.js
@@ -0,0 +1,274 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+

+if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}

+return this.length;};}

+if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}

+this.length=this.length-1;return firstItem;}};}

+if(!Array.prototype.splice){Array.prototype.splice=function(startIndex,deleteCount){var itemsAfterDeleted=this.slice(startIndex+deleteCount);var itemsDeleted=this.slice(startIndex,startIndex+deleteCount);this.length=startIndex;var argumentsArray=[];for(var i=0,len=arguments.length;i<len;i++){argumentsArray[i]=arguments[i];}

+var itemsToAppend=(argumentsArray.length>2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i<len;i++){this.push(itemsToAppend[i]);}

+return itemsDeleted;};}

+var log4javascript=(function(){function isUndefined(obj){return typeof obj=="undefined";}

+function EventSupport(){}

+EventSupport.prototype={eventTypes:[],eventListeners:{},setEventTypes:function(eventTypesParam){if(eventTypesParam instanceof Array){this.eventTypes=eventTypesParam;this.eventListeners={};for(var i=0,len=this.eventTypes.length;i<len;i++){this.eventListeners[this.eventTypes[i]]=[];}}else{handleError("log4javascript.EventSupport ["+this+"]: setEventTypes: eventTypes parameter must be an Array");}},addEventListener:function(eventType,listener){if(typeof listener=="function"){if(!array_contains(this.eventTypes,eventType)){handleError("log4javascript.EventSupport ["+this+"]: addEventListener: no event called '"+eventType+"'");}

+this.eventListeners[eventType].push(listener);}else{handleError("log4javascript.EventSupport ["+this+"]: addEventListener: listener must be a function");}},removeEventListener:function(eventType,listener){if(typeof listener=="function"){if(!array_contains(this.eventTypes,eventType)){handleError("log4javascript.EventSupport ["+this+"]: removeEventListener: no event called '"+eventType+"'");}

+array_remove(this.eventListeners[eventType],listener);}else{handleError("log4javascript.EventSupport ["+this+"]: removeEventListener: listener must be a function");}},dispatchEvent:function(eventType,eventArgs){if(array_contains(this.eventTypes,eventType)){var listeners=this.eventListeners[eventType];for(var i=0,len=listeners.length;i<len;i++){listeners[i](this,eventType,eventArgs);}}else{handleError("log4javascript.EventSupport ["+this+"]: dispatchEvent: no event called '"+eventType+"'");}}};var applicationStartDate=new Date();var uniqueId="log4javascript_"+applicationStartDate.getTime()+"_"+

+Math.floor(Math.random()*100000000);var emptyFunction=function(){};var newLine="\r\n";var pageLoaded=false;function Log4JavaScript(){}

+Log4JavaScript.prototype=new EventSupport();log4javascript=new Log4JavaScript();log4javascript.version="1.4.6";log4javascript.edition="log4javascript";function toStr(obj){if(obj&&obj.toString){return obj.toString();}else{return String(obj);}}

+function getExceptionMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}else{return toStr(ex);}}

+function getUrlFileName(url){var lastSlashIndex=Math.max(url.lastIndexOf("/"),url.lastIndexOf("\\"));return url.substr(lastSlashIndex+1);}

+function getExceptionStringRep(ex){if(ex){var exStr="Exception: "+getExceptionMessage(ex);try{if(ex.lineNumber){exStr+=" on line number "+ex.lineNumber;}

+if(ex.fileName){exStr+=" in file "+getUrlFileName(ex.fileName);}}catch(localEx){logLog.warn("Unable to obtain file and line information for error");}

+if(showStackTraces&&ex.stack){exStr+=newLine+"Stack trace:"+newLine+ex.stack;}

+return exStr;}

+return null;}

+function bool(obj){return Boolean(obj);}

+function trim(str){return str.replace(/^\s+/,"").replace(/\s+$/,"");}

+function splitIntoLines(text){var text2=text.replace(/\r\n/g,"\n").replace(/\r/g,"\n");return text2.split("\n");}

+var urlEncode=(typeof window.encodeURIComponent!="undefined")?function(str){return encodeURIComponent(str);}:function(str){return escape(str).replace(/\+/g,"%2B").replace(/"/g,"%22").replace(/'/g,"%27").replace(/\//g,"%2F").replace(/=/g,"%3D");};var urlDecode=(typeof window.decodeURIComponent!="undefined")?function(str){return decodeURIComponent(str);}:function(str){return unescape(str).replace(/%2B/g,"+").replace(/%22/g,"\"").replace(/%27/g,"'").replace(/%2F/g,"/").replace(/%3D/g,"=");};function array_remove(arr,val){var index=-1;for(var i=0,len=arr.length;i<len;i++){if(arr[i]===val){index=i;break;}}

+if(index>=0){arr.splice(index,1);return true;}else{return false;}}

+function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}

+return false;}

+function extractBooleanFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return bool(param);}}

+function extractStringFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{return String(param);}}

+function extractIntFromParam(param,defaultValue){if(isUndefined(param)){return defaultValue;}else{try{var value=parseInt(param,10);return isNaN(value)?defaultValue:value;}catch(ex){logLog.warn("Invalid int param "+param,ex);return defaultValue;}}}

+function extractFunctionFromParam(param,defaultValue){if(typeof param=="function"){return param;}else{return defaultValue;}}

+function isError(err){return(err instanceof Error);}

+if(!Function.prototype.apply){Function.prototype.apply=function(obj,args){var methodName="__apply__";if(typeof obj[methodName]!="undefined"){methodName+=String(Math.random()).substr(2);}

+obj[methodName]=this;var argsStrings=[];for(var i=0,len=args.length;i<len;i++){argsStrings[i]="args["+i+"]";}

+var script="obj."+methodName+"("+argsStrings.join(",")+")";var returnValue=eval(script);delete obj[methodName];return returnValue;};}

+if(!Function.prototype.call){Function.prototype.call=function(obj){var args=[];for(var i=1,len=arguments.length;i<len;i++){args[i-1]=arguments[i];}

+return this.apply(obj,args);};}

+function getListenersPropertyName(eventName){return"__log4javascript_listeners__"+eventName;}

+function addEvent(node,eventName,listener,useCapture,win){win=win?win:window;if(node.addEventListener){node.addEventListener(eventName,listener,useCapture);}else if(node.attachEvent){node.attachEvent("on"+eventName,listener);}else{var propertyName=getListenersPropertyName(eventName);if(!node[propertyName]){node[propertyName]=[];node["on"+eventName]=function(evt){evt=getEvent(evt,win);var listenersPropertyName=getListenersPropertyName(eventName);var listeners=this[listenersPropertyName].concat([]);var currentListener;while((currentListener=listeners.shift())){currentListener.call(this,evt);}};}

+node[propertyName].push(listener);}}

+function removeEvent(node,eventName,listener,useCapture){if(node.removeEventListener){node.removeEventListener(eventName,listener,useCapture);}else if(node.detachEvent){node.detachEvent("on"+eventName,listener);}else{var propertyName=getListenersPropertyName(eventName);if(node[propertyName]){array_remove(node[propertyName],listener);}}}

+function getEvent(evt,win){win=win?win:window;return evt?evt:win.event;}

+function stopEventPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}

+evt.returnValue=false;}

+var logLog={quietMode:false,debugMessages:[],setQuietMode:function(quietMode){this.quietMode=bool(quietMode);},numberOfErrors:0,alertAllErrors:false,setAlertAllErrors:function(alertAllErrors){this.alertAllErrors=alertAllErrors;},debug:function(message){this.debugMessages.push(message);},displayDebug:function(){alert(this.debugMessages.join(newLine));},warn:function(message,exception){},error:function(message,exception){if(++this.numberOfErrors==1||this.alertAllErrors){if(!this.quietMode){var alertMessage="log4javascript error: "+message;if(exception){alertMessage+=newLine+newLine+"Original error: "+getExceptionStringRep(exception);}

+alert(alertMessage);}}}};log4javascript.logLog=logLog;log4javascript.setEventTypes(["load","error"]);function handleError(message,exception){logLog.error(message,exception);log4javascript.dispatchEvent("error",{"message":message,"exception":exception});}

+log4javascript.handleError=handleError;var enabled=!((typeof log4javascript_disabled!="undefined")&&log4javascript_disabled);log4javascript.setEnabled=function(enable){enabled=bool(enable);};log4javascript.isEnabled=function(){return enabled;};var useTimeStampsInMilliseconds=true;log4javascript.setTimeStampsInMilliseconds=function(timeStampsInMilliseconds){useTimeStampsInMilliseconds=bool(timeStampsInMilliseconds);};log4javascript.isTimeStampsInMilliseconds=function(){return useTimeStampsInMilliseconds;};log4javascript.evalInScope=function(expr){return eval(expr);};var showStackTraces=false;log4javascript.setShowStackTraces=function(show){showStackTraces=bool(show);};var Level=function(level,name){this.level=level;this.name=name;};Level.prototype={toString:function(){return this.name;},equals:function(level){return this.level==level.level;},isGreaterOrEqual:function(level){return this.level>=level.level;}};Level.ALL=new Level(Number.MIN_VALUE,"ALL");Level.TRACE=new Level(10000,"TRACE");Level.DEBUG=new Level(20000,"DEBUG");Level.INFO=new Level(30000,"INFO");Level.WARN=new Level(40000,"WARN");Level.ERROR=new Level(50000,"ERROR");Level.FATAL=new Level(60000,"FATAL");Level.OFF=new Level(Number.MAX_VALUE,"OFF");log4javascript.Level=Level;function Timer(name,level){this.name=name;this.level=isUndefined(level)?Level.INFO:level;this.start=new Date();}

+Timer.prototype.getElapsedTime=function(){return new Date().getTime()-this.start.getTime();};var anonymousLoggerName="[anonymous]";var defaultLoggerName="[default]";var nullLoggerName="[null]";var rootLoggerName="root";function Logger(name){this.name=name;this.parent=null;this.children=[];var appenders=[];var loggerLevel=null;var isRoot=(this.name===rootLoggerName);var isNull=(this.name===nullLoggerName);var appenderCache=null;var appenderCacheInvalidated=false;this.addChild=function(childLogger){this.children.push(childLogger);childLogger.parent=this;childLogger.invalidateAppenderCache();};var additive=true;this.getAdditivity=function(){return additive;};this.setAdditivity=function(additivity){var valueChanged=(additive!=additivity);additive=additivity;if(valueChanged){this.invalidateAppenderCache();}};this.addAppender=function(appender){if(isNull){handleError("Logger.addAppender: you may not add an appender to the null logger");}else{if(appender instanceof log4javascript.Appender){if(!array_contains(appenders,appender)){appenders.push(appender);appender.setAddedToLogger(this);this.invalidateAppenderCache();}}else{handleError("Logger.addAppender: appender supplied ('"+

+toStr(appender)+"') is not a subclass of Appender");}}};this.removeAppender=function(appender){array_remove(appenders,appender);appender.setRemovedFromLogger(this);this.invalidateAppenderCache();};this.removeAllAppenders=function(){var appenderCount=appenders.length;if(appenderCount>0){for(var i=0;i<appenderCount;i++){appenders[i].setRemovedFromLogger(this);}

+appenders.length=0;this.invalidateAppenderCache();}};this.getEffectiveAppenders=function(){if(appenderCache===null||appenderCacheInvalidated){var parentEffectiveAppenders=(isRoot||!this.getAdditivity())?[]:this.parent.getEffectiveAppenders();appenderCache=parentEffectiveAppenders.concat(appenders);appenderCacheInvalidated=false;}

+return appenderCache;};this.invalidateAppenderCache=function(){appenderCacheInvalidated=true;for(var i=0,len=this.children.length;i<len;i++){this.children[i].invalidateAppenderCache();}};this.log=function(level,params){if(enabled&&level.isGreaterOrEqual(this.getEffectiveLevel())){var exception;var finalParamIndex=params.length-1;var lastParam=params[finalParamIndex];if(params.length>1&&isError(lastParam)){exception=lastParam;finalParamIndex--;}

+var messages=[];for(var i=0;i<=finalParamIndex;i++){messages[i]=params[i];}

+var loggingEvent=new LoggingEvent(this,new Date(),level,messages,exception);this.callAppenders(loggingEvent);}};this.callAppenders=function(loggingEvent){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].doAppend(loggingEvent);}};this.setLevel=function(level){if(isRoot&&level===null){handleError("Logger.setLevel: you cannot set the level of the root logger to null");}else if(level instanceof Level){loggerLevel=level;}else{handleError("Logger.setLevel: level supplied to logger "+

+this.name+" is not an instance of log4javascript.Level");}};this.getLevel=function(){return loggerLevel;};this.getEffectiveLevel=function(){for(var logger=this;logger!==null;logger=logger.parent){var level=logger.getLevel();if(level!==null){return level;}}};this.group=function(name,initiallyExpanded){if(enabled){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].group(name,initiallyExpanded);}}};this.groupEnd=function(){if(enabled){var effectiveAppenders=this.getEffectiveAppenders();for(var i=0,len=effectiveAppenders.length;i<len;i++){effectiveAppenders[i].groupEnd();}}};var timers={};this.time=function(name,level){if(enabled){if(isUndefined(name)){handleError("Logger.time: a name for the timer must be supplied");}else if(level&&!(level instanceof Level)){handleError("Logger.time: level supplied to timer "+

+name+" is not an instance of log4javascript.Level");}else{timers[name]=new Timer(name,level);}}};this.timeEnd=function(name){if(enabled){if(isUndefined(name)){handleError("Logger.timeEnd: a name for the timer must be supplied");}else if(timers[name]){var timer=timers[name];var milliseconds=timer.getElapsedTime();this.log(timer.level,["Timer "+toStr(name)+" completed in "+milliseconds+"ms"]);delete timers[name];}else{logLog.warn("Logger.timeEnd: no timer found with name "+name);}}};this.assert=function(expr){if(enabled&&!expr){var args=[];for(var i=1,len=arguments.length;i<len;i++){args.push(arguments[i]);}

+args=(args.length>0)?args:["Assertion Failure"];args.push(newLine);args.push(expr);this.log(Level.ERROR,args);}};this.toString=function(){return"Logger["+this.name+"]";};}

+Logger.prototype={trace:function(){this.log(Level.TRACE,arguments);},debug:function(){this.log(Level.DEBUG,arguments);},info:function(){this.log(Level.INFO,arguments);},warn:function(){this.log(Level.WARN,arguments);},error:function(){this.log(Level.ERROR,arguments);},fatal:function(){this.log(Level.FATAL,arguments);},isEnabledFor:function(level){return level.isGreaterOrEqual(this.getEffectiveLevel());},isTraceEnabled:function(){return this.isEnabledFor(Level.TRACE);},isDebugEnabled:function(){return this.isEnabledFor(Level.DEBUG);},isInfoEnabled:function(){return this.isEnabledFor(Level.INFO);},isWarnEnabled:function(){return this.isEnabledFor(Level.WARN);},isErrorEnabled:function(){return this.isEnabledFor(Level.ERROR);},isFatalEnabled:function(){return this.isEnabledFor(Level.FATAL);}};Logger.prototype.trace.isEntryPoint=true;Logger.prototype.debug.isEntryPoint=true;Logger.prototype.info.isEntryPoint=true;Logger.prototype.warn.isEntryPoint=true;Logger.prototype.error.isEntryPoint=true;Logger.prototype.fatal.isEntryPoint=true;var loggers={};var loggerNames=[];var ROOT_LOGGER_DEFAULT_LEVEL=Level.DEBUG;var rootLogger=new Logger(rootLoggerName);rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);log4javascript.getRootLogger=function(){return rootLogger;};log4javascript.getLogger=function(loggerName){if(!(typeof loggerName=="string")){loggerName=anonymousLoggerName;logLog.warn("log4javascript.getLogger: non-string logger name "+

+toStr(loggerName)+" supplied, returning anonymous logger");}

+if(loggerName==rootLoggerName){handleError("log4javascript.getLogger: root logger may not be obtained by name");}

+if(!loggers[loggerName]){var logger=new Logger(loggerName);loggers[loggerName]=logger;loggerNames.push(loggerName);var lastDotIndex=loggerName.lastIndexOf(".");var parentLogger;if(lastDotIndex>-1){var parentLoggerName=loggerName.substring(0,lastDotIndex);parentLogger=log4javascript.getLogger(parentLoggerName);}else{parentLogger=rootLogger;}

+parentLogger.addChild(logger);}

+return loggers[loggerName];};var defaultLogger=null;log4javascript.getDefaultLogger=function(){if(!defaultLogger){defaultLogger=log4javascript.getLogger(defaultLoggerName);var a=new log4javascript.PopUpAppender();defaultLogger.addAppender(a);}

+return defaultLogger;};var nullLogger=null;log4javascript.getNullLogger=function(){if(!nullLogger){nullLogger=new Logger(nullLoggerName);nullLogger.setLevel(Level.OFF);}

+return nullLogger;};log4javascript.resetConfiguration=function(){rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);loggers={};};var LoggingEvent=function(logger,timeStamp,level,messages,exception){this.logger=logger;this.timeStamp=timeStamp;this.timeStampInMilliseconds=timeStamp.getTime();this.timeStampInSeconds=Math.floor(this.timeStampInMilliseconds/1000);this.milliseconds=this.timeStamp.getMilliseconds();this.level=level;this.messages=messages;this.exception=exception;};LoggingEvent.prototype={getThrowableStrRep:function(){return this.exception?getExceptionStringRep(this.exception):"";},getCombinedMessages:function(){return(this.messages.length==1)?this.messages[0]:this.messages.join(newLine);},toString:function(){return"LoggingEvent["+this.level+"]";}};log4javascript.LoggingEvent=LoggingEvent;var Layout=function(){};Layout.prototype={defaults:{loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url"},loggerKey:"logger",timeStampKey:"timestamp",millisecondsKey:"milliseconds",levelKey:"level",messageKey:"message",exceptionKey:"exception",urlKey:"url",batchHeader:"",batchFooter:"",batchSeparator:"",returnsPostData:false,overrideTimeStampsSetting:false,useTimeStampsInMilliseconds:null,format:function(){handleError("Layout.format: layout supplied has no format() method");},ignoresThrowable:function(){handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");},getContentType:function(){return"text/plain";},allowBatching:function(){return true;},setTimeStampsInMilliseconds:function(timeStampsInMilliseconds){this.overrideTimeStampsSetting=true;this.useTimeStampsInMilliseconds=bool(timeStampsInMilliseconds);},isTimeStampsInMilliseconds:function(){return this.overrideTimeStampsSetting?this.useTimeStampsInMilliseconds:useTimeStampsInMilliseconds;},getTimeStampValue:function(loggingEvent){return this.isTimeStampsInMilliseconds()?loggingEvent.timeStampInMilliseconds:loggingEvent.timeStampInSeconds;},getDataValues:function(loggingEvent,combineMessages){var dataValues=[[this.loggerKey,loggingEvent.logger.name],[this.timeStampKey,this.getTimeStampValue(loggingEvent)],[this.levelKey,loggingEvent.level.name],[this.urlKey,window.location.href],[this.messageKey,combineMessages?loggingEvent.getCombinedMessages():loggingEvent.messages]];if(!this.isTimeStampsInMilliseconds()){dataValues.push([this.millisecondsKey,loggingEvent.milliseconds]);}

+if(loggingEvent.exception){dataValues.push([this.exceptionKey,getExceptionStringRep(loggingEvent.exception)]);}

+if(this.hasCustomFields()){for(var i=0,len=this.customFields.length;i<len;i++){var val=this.customFields[i].value;if(typeof val==="function"){val=val(this,loggingEvent);}

+dataValues.push([this.customFields[i].name,val]);}}

+return dataValues;},setKeys:function(loggerKey,timeStampKey,levelKey,messageKey,exceptionKey,urlKey,millisecondsKey){this.loggerKey=extractStringFromParam(loggerKey,this.defaults.loggerKey);this.timeStampKey=extractStringFromParam(timeStampKey,this.defaults.timeStampKey);this.levelKey=extractStringFromParam(levelKey,this.defaults.levelKey);this.messageKey=extractStringFromParam(messageKey,this.defaults.messageKey);this.exceptionKey=extractStringFromParam(exceptionKey,this.defaults.exceptionKey);this.urlKey=extractStringFromParam(urlKey,this.defaults.urlKey);this.millisecondsKey=extractStringFromParam(millisecondsKey,this.defaults.millisecondsKey);},setCustomField:function(name,value){var fieldUpdated=false;for(var i=0,len=this.customFields.length;i<len;i++){if(this.customFields[i].name===name){this.customFields[i].value=value;fieldUpdated=true;}}

+if(!fieldUpdated){this.customFields.push({"name":name,"value":value});}},hasCustomFields:function(){return(this.customFields.length>0);},toString:function(){handleError("Layout.toString: all layouts must override this method");}};log4javascript.Layout=Layout;var Appender=function(){};Appender.prototype=new EventSupport();Appender.prototype.layout=new PatternLayout();Appender.prototype.threshold=Level.ALL;Appender.prototype.loggers=[];Appender.prototype.doAppend=function(loggingEvent){if(enabled&&loggingEvent.level.level>=this.threshold.level){this.append(loggingEvent);}};Appender.prototype.append=function(loggingEvent){};Appender.prototype.setLayout=function(layout){if(layout instanceof Layout){this.layout=layout;}else{handleError("Appender.setLayout: layout supplied to "+

+this.toString()+" is not a subclass of Layout");}};Appender.prototype.getLayout=function(){return this.layout;};Appender.prototype.setThreshold=function(threshold){if(threshold instanceof Level){this.threshold=threshold;}else{handleError("Appender.setThreshold: threshold supplied to "+

+this.toString()+" is not a subclass of Level");}};Appender.prototype.getThreshold=function(){return this.threshold;};Appender.prototype.setAddedToLogger=function(logger){this.loggers.push(logger);};Appender.prototype.setRemovedFromLogger=function(logger){array_remove(this.loggers,logger);};Appender.prototype.group=emptyFunction;Appender.prototype.groupEnd=emptyFunction;Appender.prototype.toString=function(){handleError("Appender.toString: all appenders must override this method");};log4javascript.Appender=Appender;function SimpleLayout(){this.customFields=[];}

+SimpleLayout.prototype=new Layout();SimpleLayout.prototype.format=function(loggingEvent){return loggingEvent.level.name+" - "+loggingEvent.getCombinedMessages();};SimpleLayout.prototype.ignoresThrowable=function(){return true;};SimpleLayout.prototype.toString=function(){return"SimpleLayout";};log4javascript.SimpleLayout=SimpleLayout;function NullLayout(){this.customFields=[];}

+NullLayout.prototype=new Layout();NullLayout.prototype.format=function(loggingEvent){return loggingEvent.messages;};NullLayout.prototype.ignoresThrowable=function(){return true;};NullLayout.prototype.toString=function(){return"NullLayout";};log4javascript.NullLayout=NullLayout;function XmlLayout(combineMessages){this.combineMessages=extractBooleanFromParam(combineMessages,true);this.customFields=[];}

+XmlLayout.prototype=new Layout();XmlLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};XmlLayout.prototype.getContentType=function(){return"text/xml";};XmlLayout.prototype.escapeCdata=function(str){return str.replace(/\]\]>/,"]]>]]&gt;<![CDATA[");};XmlLayout.prototype.format=function(loggingEvent){var layout=this;var i,len;function formatMessage(message){message=(typeof message==="string")?message:toStr(message);return"<log4javascript:message><![CDATA["+

+layout.escapeCdata(message)+"]]></log4javascript:message>";}

+var str="<log4javascript:event logger=\""+loggingEvent.logger.name+"\" timestamp=\""+this.getTimeStampValue(loggingEvent)+"\"";if(!this.isTimeStampsInMilliseconds()){str+=" milliseconds=\""+loggingEvent.milliseconds+"\"";}

+str+=" level=\""+loggingEvent.level.name+"\">"+newLine;if(this.combineMessages){str+=formatMessage(loggingEvent.getCombinedMessages());}else{str+="<log4javascript:messages>"+newLine;for(i=0,len=loggingEvent.messages.length;i<len;i++){str+=formatMessage(loggingEvent.messages[i])+newLine;}

+str+="</log4javascript:messages>"+newLine;}

+if(this.hasCustomFields()){for(i=0,len=this.customFields.length;i<len;i++){str+="<log4javascript:customfield name=\""+

+this.customFields[i].name+"\"><![CDATA["+

+this.customFields[i].value.toString()+"]]></log4javascript:customfield>"+newLine;}}

+if(loggingEvent.exception){str+="<log4javascript:exception><![CDATA["+

+getExceptionStringRep(loggingEvent.exception)+"]]></log4javascript:exception>"+newLine;}

+str+="</log4javascript:event>"+newLine+newLine;return str;};XmlLayout.prototype.ignoresThrowable=function(){return false;};XmlLayout.prototype.toString=function(){return"XmlLayout";};log4javascript.XmlLayout=XmlLayout;function escapeNewLines(str){return str.replace(/\r\n|\r|\n/g,"\\r\\n");}

+function JsonLayout(readable,combineMessages){this.readable=extractBooleanFromParam(readable,false);this.combineMessages=extractBooleanFromParam(combineMessages,true);this.batchHeader=this.readable?"["+newLine:"[";this.batchFooter=this.readable?"]"+newLine:"]";this.batchSeparator=this.readable?","+newLine:",";this.setKeys();this.colon=this.readable?": ":":";this.tab=this.readable?"\t":"";this.lineBreak=this.readable?newLine:"";this.customFields=[];}

+JsonLayout.prototype=new Layout();JsonLayout.prototype.isReadable=function(){return this.readable;};JsonLayout.prototype.isCombinedMessages=function(){return this.combineMessages;};JsonLayout.prototype.format=function(loggingEvent){var layout=this;var dataValues=this.getDataValues(loggingEvent,this.combineMessages);var str="{"+this.lineBreak;var i,len;function formatValue(val,prefix,expand){var formattedValue;var valType=typeof val;if(val instanceof Date){formattedValue=String(val.getTime());}else if(expand&&(val instanceof Array)){formattedValue="["+layout.lineBreak;for(var i=0,len=val.length;i<len;i++){var childPrefix=prefix+layout.tab;formattedValue+=childPrefix+formatValue(val[i],childPrefix,false);if(i<val.length-1){formattedValue+=",";}

+formattedValue+=layout.lineBreak;}

+formattedValue+=prefix+"]";}else if(valType!=="number"&&valType!=="boolean"){formattedValue="\""+escapeNewLines(toStr(val).replace(/\"/g,"\\\""))+"\"";}else{formattedValue=val;}

+return formattedValue;}

+for(i=0,len=dataValues.length-1;i<=len;i++){str+=this.tab+"\""+dataValues[i][0]+"\""+this.colon+formatValue(dataValues[i][1],this.tab,true);if(i<len){str+=",";}

+str+=this.lineBreak;}

+str+="}"+this.lineBreak;return str;};JsonLayout.prototype.ignoresThrowable=function(){return false;};JsonLayout.prototype.toString=function(){return"JsonLayout";};JsonLayout.prototype.getContentType=function(){return"application/json";};log4javascript.JsonLayout=JsonLayout;function HttpPostDataLayout(){this.setKeys();this.customFields=[];this.returnsPostData=true;}

+HttpPostDataLayout.prototype=new Layout();HttpPostDataLayout.prototype.allowBatching=function(){return false;};HttpPostDataLayout.prototype.format=function(loggingEvent){var dataValues=this.getDataValues(loggingEvent);var queryBits=[];for(var i=0,len=dataValues.length;i<len;i++){var val=(dataValues[i][1]instanceof Date)?String(dataValues[i][1].getTime()):dataValues[i][1];queryBits.push(urlEncode(dataValues[i][0])+"="+urlEncode(val));}

+return queryBits.join("&");};HttpPostDataLayout.prototype.ignoresThrowable=function(loggingEvent){return false;};HttpPostDataLayout.prototype.toString=function(){return"HttpPostDataLayout";};log4javascript.HttpPostDataLayout=HttpPostDataLayout;function formatObjectExpansion(obj,depth,indentation){var objectsExpanded=[];function doFormat(obj,depth,indentation){var i,j,len,childDepth,childIndentation,childLines,expansion,childExpansion;if(!indentation){indentation="";}

+function formatString(text){var lines=splitIntoLines(text);for(var j=1,jLen=lines.length;j<jLen;j++){lines[j]=indentation+lines[j];}

+return lines.join(newLine);}

+if(obj===null){return"null";}else if(typeof obj=="undefined"){return"undefined";}else if(typeof obj=="string"){return formatString(obj);}else if(typeof obj=="object"&&array_contains(objectsExpanded,obj)){try{expansion=toStr(obj);}catch(ex){expansion="Error formatting property. Details: "+getExceptionStringRep(ex);}

+return expansion+" [already expanded]";}else if((obj instanceof Array)&&depth>0){objectsExpanded.push(obj);expansion="["+newLine;childDepth=depth-1;childIndentation=indentation+"  ";childLines=[];for(i=0,len=obj.length;i<len;i++){try{childExpansion=doFormat(obj[i],childDepth,childIndentation);childLines.push(childIndentation+childExpansion);}catch(ex){childLines.push(childIndentation+"Error formatting array member. Details: "+

+getExceptionStringRep(ex)+"");}}

+expansion+=childLines.join(","+newLine)+newLine+indentation+"]";return expansion;}else if(Object.prototype.toString.call(obj)=="[object Date]"){return obj.toString();}else if(typeof obj=="object"&&depth>0){objectsExpanded.push(obj);expansion="{"+newLine;childDepth=depth-1;childIndentation=indentation+"  ";childLines=[];for(i in obj){try{childExpansion=doFormat(obj[i],childDepth,childIndentation);childLines.push(childIndentation+i+": "+childExpansion);}catch(ex){childLines.push(childIndentation+i+": Error formatting property. Details: "+

+getExceptionStringRep(ex));}}

+expansion+=childLines.join(","+newLine)+newLine+indentation+"}";return expansion;}else{return formatString(toStr(obj));}}

+return doFormat(obj,depth,indentation);}

+var SimpleDateFormat;(function(){var regex=/('[^']*')|(G+|y+|M+|w+|W+|D+|d+|F+|E+|a+|H+|k+|K+|h+|m+|s+|S+|Z+)|([a-zA-Z]+)|([^a-zA-Z']+)/;var monthNames=["January","February","March","April","May","June","July","August","September","October","November","December"];var dayNames=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var TEXT2=0,TEXT3=1,NUMBER=2,YEAR=3,MONTH=4,TIMEZONE=5;var types={G:TEXT2,y:YEAR,M:MONTH,w:NUMBER,W:NUMBER,D:NUMBER,d:NUMBER,F:NUMBER,E:TEXT3,a:TEXT2,H:NUMBER,k:NUMBER,K:NUMBER,h:NUMBER,m:NUMBER,s:NUMBER,S:NUMBER,Z:TIMEZONE};var ONE_DAY=24*60*60*1000;var ONE_WEEK=7*ONE_DAY;var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK=1;var newDateAtMidnight=function(year,month,day){var d=new Date(year,month,day,0,0,0);d.setMilliseconds(0);return d;};Date.prototype.getDifference=function(date){return this.getTime()-date.getTime();};Date.prototype.isBefore=function(d){return this.getTime()<d.getTime();};Date.prototype.getUTCTime=function(){return Date.UTC(this.getFullYear(),this.getMonth(),this.getDate(),this.getHours(),this.getMinutes(),this.getSeconds(),this.getMilliseconds());};Date.prototype.getTimeSince=function(d){return this.getUTCTime()-d.getUTCTime();};Date.prototype.getPreviousSunday=function(){var midday=new Date(this.getFullYear(),this.getMonth(),this.getDate(),12,0,0);var previousSunday=new Date(midday.getTime()-this.getDay()*ONE_DAY);return newDateAtMidnight(previousSunday.getFullYear(),previousSunday.getMonth(),previousSunday.getDate());};Date.prototype.getWeekInYear=function(minimalDaysInFirstWeek){if(isUndefined(this.minimalDaysInFirstWeek)){minimalDaysInFirstWeek=DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;}

+var previousSunday=this.getPreviousSunday();var startOfYear=newDateAtMidnight(this.getFullYear(),0,1);var numberOfSundays=previousSunday.isBefore(startOfYear)?0:1+Math.floor(previousSunday.getTimeSince(startOfYear)/ONE_WEEK);var numberOfDaysInFirstWeek=7-startOfYear.getDay();var weekInYear=numberOfSundays;if(numberOfDaysInFirstWeek<minimalDaysInFirstWeek){weekInYear--;}

+return weekInYear;};Date.prototype.getWeekInMonth=function(minimalDaysInFirstWeek){if(isUndefined(this.minimalDaysInFirstWeek)){minimalDaysInFirstWeek=DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;}

+var previousSunday=this.getPreviousSunday();var startOfMonth=newDateAtMidnight(this.getFullYear(),this.getMonth(),1);var numberOfSundays=previousSunday.isBefore(startOfMonth)?0:1+Math.floor(previousSunday.getTimeSince(startOfMonth)/ONE_WEEK);var numberOfDaysInFirstWeek=7-startOfMonth.getDay();var weekInMonth=numberOfSundays;if(numberOfDaysInFirstWeek>=minimalDaysInFirstWeek){weekInMonth++;}

+return weekInMonth;};Date.prototype.getDayInYear=function(){var startOfYear=newDateAtMidnight(this.getFullYear(),0,1);return 1+Math.floor(this.getTimeSince(startOfYear)/ONE_DAY);};SimpleDateFormat=function(formatString){this.formatString=formatString;};SimpleDateFormat.prototype.setMinimalDaysInFirstWeek=function(days){this.minimalDaysInFirstWeek=days;};SimpleDateFormat.prototype.getMinimalDaysInFirstWeek=function(){return isUndefined(this.minimalDaysInFirstWeek)?DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK:this.minimalDaysInFirstWeek;};var padWithZeroes=function(str,len){while(str.length<len){str="0"+str;}

+return str;};var formatText=function(data,numberOfLetters,minLength){return(numberOfLetters>=4)?data:data.substr(0,Math.max(minLength,numberOfLetters));};var formatNumber=function(data,numberOfLetters){var dataString=""+data;return padWithZeroes(dataString,numberOfLetters);};SimpleDateFormat.prototype.format=function(date){var formattedString="";var result;var searchString=this.formatString;while((result=regex.exec(searchString))){var quotedString=result[1];var patternLetters=result[2];var otherLetters=result[3];var otherCharacters=result[4];if(quotedString){if(quotedString=="''"){formattedString+="'";}else{formattedString+=quotedString.substring(1,quotedString.length-1);}}else if(otherLetters){}else if(otherCharacters){formattedString+=otherCharacters;}else if(patternLetters){var patternLetter=patternLetters.charAt(0);var numberOfLetters=patternLetters.length;var rawData="";switch(patternLetter){case"G":rawData="AD";break;case"y":rawData=date.getFullYear();break;case"M":rawData=date.getMonth();break;case"w":rawData=date.getWeekInYear(this.getMinimalDaysInFirstWeek());break;case"W":rawData=date.getWeekInMonth(this.getMinimalDaysInFirstWeek());break;case"D":rawData=date.getDayInYear();break;case"d":rawData=date.getDate();break;case"F":rawData=1+Math.floor((date.getDate()-1)/7);break;case"E":rawData=dayNames[date.getDay()];break;case"a":rawData=(date.getHours()>=12)?"PM":"AM";break;case"H":rawData=date.getHours();break;case"k":rawData=date.getHours()||24;break;case"K":rawData=date.getHours()%12;break;case"h":rawData=(date.getHours()%12)||12;break;case"m":rawData=date.getMinutes();break;case"s":rawData=date.getSeconds();break;case"S":rawData=date.getMilliseconds();break;case"Z":rawData=date.getTimezoneOffset();break;}

+switch(types[patternLetter]){case TEXT2:formattedString+=formatText(rawData,numberOfLetters,2);break;case TEXT3:formattedString+=formatText(rawData,numberOfLetters,3);break;case NUMBER:formattedString+=formatNumber(rawData,numberOfLetters);break;case YEAR:if(numberOfLetters<=3){var dataString=""+rawData;formattedString+=dataString.substr(2,2);}else{formattedString+=formatNumber(rawData,numberOfLetters);}

+break;case MONTH:if(numberOfLetters>=3){formattedString+=formatText(monthNames[rawData],numberOfLetters,numberOfLetters);}else{formattedString+=formatNumber(rawData+1,numberOfLetters);}

+break;case TIMEZONE:var isPositive=(rawData>0);var prefix=isPositive?"-":"+";var absData=Math.abs(rawData);var hours=""+Math.floor(absData/60);hours=padWithZeroes(hours,2);var minutes=""+(absData%60);minutes=padWithZeroes(minutes,2);formattedString+=prefix+hours+minutes;break;}}

+searchString=searchString.substr(result.index+result[0].length);}

+return formattedString;};})();log4javascript.SimpleDateFormat=SimpleDateFormat;function PatternLayout(pattern){if(pattern){this.pattern=pattern;}else{this.pattern=PatternLayout.DEFAULT_CONVERSION_PATTERN;}

+this.customFields=[];}

+PatternLayout.TTCC_CONVERSION_PATTERN="%r %p %c - %m%n";PatternLayout.DEFAULT_CONVERSION_PATTERN="%m%n";PatternLayout.ISO8601_DATEFORMAT="yyyy-MM-dd HH:mm:ss,SSS";PatternLayout.DATETIME_DATEFORMAT="dd MMM yyyy HH:mm:ss,SSS";PatternLayout.ABSOLUTETIME_DATEFORMAT="HH:mm:ss,SSS";PatternLayout.prototype=new Layout();PatternLayout.prototype.format=function(loggingEvent){var regex=/%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;var formattedString="";var result;var searchString=this.pattern;while((result=regex.exec(searchString))){var matchedString=result[0];var padding=result[1];var truncation=result[2];var conversionCharacter=result[3];var specifier=result[5];var text=result[6];if(text){formattedString+=""+text;}else{var replacement="";switch(conversionCharacter){case"a":case"m":var depth=0;if(specifier){depth=parseInt(specifier,10);if(isNaN(depth)){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character '"+conversionCharacter+"' - should be a number");depth=0;}}

+var messages=(conversionCharacter==="a")?loggingEvent.messages[0]:loggingEvent.messages;for(var i=0,len=messages.length;i<len;i++){if(i>0&&(replacement.charAt(replacement.length-1)!==" ")){replacement+=" ";}

+if(depth===0){replacement+=messages[i];}else{replacement+=formatObjectExpansion(messages[i],depth);}}

+break;case"c":var loggerName=loggingEvent.logger.name;if(specifier){var precision=parseInt(specifier,10);var loggerNameBits=loggingEvent.logger.name.split(".");if(precision>=loggerNameBits.length){replacement=loggerName;}else{replacement=loggerNameBits.slice(loggerNameBits.length-precision).join(".");}}else{replacement=loggerName;}

+break;case"d":var dateFormat=PatternLayout.ISO8601_DATEFORMAT;if(specifier){dateFormat=specifier;if(dateFormat=="ISO8601"){dateFormat=PatternLayout.ISO8601_DATEFORMAT;}else if(dateFormat=="ABSOLUTE"){dateFormat=PatternLayout.ABSOLUTETIME_DATEFORMAT;}else if(dateFormat=="DATE"){dateFormat=PatternLayout.DATETIME_DATEFORMAT;}}

+replacement=(new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);break;case"f":if(this.hasCustomFields()){var fieldIndex=0;if(specifier){fieldIndex=parseInt(specifier,10);if(isNaN(fieldIndex)){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - should be a number");}else if(fieldIndex===0){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - must be greater than zero");}else if(fieldIndex>this.customFields.length){handleError("PatternLayout.format: invalid specifier '"+

+specifier+"' for conversion character 'f' - there aren't that many custom fields");}else{fieldIndex=fieldIndex-1;}}

+var val=this.customFields[fieldIndex].value;if(typeof val=="function"){val=val(this,loggingEvent);}

+replacement=val;}

+break;case"n":replacement=newLine;break;case"p":replacement=loggingEvent.level.name;break;case"r":replacement=""+loggingEvent.timeStamp.getDifference(applicationStartDate);break;case"%":replacement="%";break;default:replacement=matchedString;break;}

+var l;if(truncation){l=parseInt(truncation.substr(1),10);var strLen=replacement.length;if(l<strLen){replacement=replacement.substring(strLen-l,strLen);}}

+if(padding){if(padding.charAt(0)=="-"){l=parseInt(padding.substr(1),10);while(replacement.length<l){replacement+=" ";}}else{l=parseInt(padding,10);while(replacement.length<l){replacement=" "+replacement;}}}

+formattedString+=replacement;}

+searchString=searchString.substr(result.index+result[0].length);}

+return formattedString;};PatternLayout.prototype.ignoresThrowable=function(){return true;};PatternLayout.prototype.toString=function(){return"PatternLayout";};log4javascript.PatternLayout=PatternLayout;function AlertAppender(){}

+AlertAppender.prototype=new Appender();AlertAppender.prototype.layout=new SimpleLayout();AlertAppender.prototype.append=function(loggingEvent){var formattedMessage=this.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();}

+alert(formattedMessage);};AlertAppender.prototype.toString=function(){return"AlertAppender";};log4javascript.AlertAppender=AlertAppender;function BrowserConsoleAppender(){}

+BrowserConsoleAppender.prototype=new log4javascript.Appender();BrowserConsoleAppender.prototype.layout=new NullLayout();BrowserConsoleAppender.prototype.threshold=Level.DEBUG;BrowserConsoleAppender.prototype.append=function(loggingEvent){var appender=this;var getFormattedMessage=function(){var layout=appender.getLayout();var formattedMessage=layout.format(loggingEvent);if(layout.ignoresThrowable()&&loggingEvent.exception){formattedMessage+=loggingEvent.getThrowableStrRep();}

+return formattedMessage;};if((typeof opera!="undefined")&&opera.postError){opera.postError(getFormattedMessage());}else if(window.console&&window.console.log){var formattedMesage=getFormattedMessage();if(window.console.debug&&Level.DEBUG.isGreaterOrEqual(loggingEvent.level)){window.console.debug(formattedMesage);}else if(window.console.info&&Level.INFO.equals(loggingEvent.level)){window.console.info(formattedMesage);}else if(window.console.warn&&Level.WARN.equals(loggingEvent.level)){window.console.warn(formattedMesage);}else if(window.console.error&&loggingEvent.level.isGreaterOrEqual(Level.ERROR)){window.console.error(formattedMesage);}else{window.console.log(formattedMesage);}}};BrowserConsoleAppender.prototype.group=function(name){if(window.console&&window.console.group){window.console.group(name);}};BrowserConsoleAppender.prototype.groupEnd=function(){if(window.console&&window.console.groupEnd){window.console.groupEnd();}};BrowserConsoleAppender.prototype.toString=function(){return"BrowserConsoleAppender";};log4javascript.BrowserConsoleAppender=BrowserConsoleAppender;var xmlHttpFactories=[function(){return new XMLHttpRequest();},function(){return new ActiveXObject("Msxml2.XMLHTTP");},function(){return new ActiveXObject("Microsoft.XMLHTTP");}];var getXmlHttp=function(errorHandler){var xmlHttp=null,factory;for(var i=0,len=xmlHttpFactories.length;i<len;i++){factory=xmlHttpFactories[i];try{xmlHttp=factory();getXmlHttp=factory;return xmlHttp;}catch(e){}}

+if(errorHandler){errorHandler();}else{handleError("getXmlHttp: unable to obtain XMLHttpRequest object");}};function isHttpRequestSuccessful(xmlHttp){return isUndefined(xmlHttp.status)||xmlHttp.status===0||(xmlHttp.status>=200&&xmlHttp.status<300)||xmlHttp.status==1223;}

+function AjaxAppender(url){var appender=this;var isSupported=true;if(!url){handleError("AjaxAppender: URL must be specified in constructor");isSupported=false;}

+var timed=this.defaults.timed;var waitForResponse=this.defaults.waitForResponse;var batchSize=this.defaults.batchSize;var timerInterval=this.defaults.timerInterval;var requestSuccessCallback=this.defaults.requestSuccessCallback;var failCallback=this.defaults.failCallback;var postVarName=this.defaults.postVarName;var sendAllOnUnload=this.defaults.sendAllOnUnload;var contentType=this.defaults.contentType;var sessionId=null;var queuedLoggingEvents=[];var queuedRequests=[];var headers=[];var sending=false;var initialized=false;function checkCanConfigure(configOptionName){if(initialized){handleError("AjaxAppender: configuration option '"+

+configOptionName+"' may not be set after the appender has been initialized");return false;}

+return true;}

+this.getSessionId=function(){return sessionId;};this.setSessionId=function(sessionIdParam){sessionId=extractStringFromParam(sessionIdParam,null);this.layout.setCustomField("sessionid",sessionId);};this.setLayout=function(layoutParam){if(checkCanConfigure("layout")){this.layout=layoutParam;if(sessionId!==null){this.setSessionId(sessionId);}}};this.isTimed=function(){return timed;};this.setTimed=function(timedParam){if(checkCanConfigure("timed")){timed=bool(timedParam);}};this.getTimerInterval=function(){return timerInterval;};this.setTimerInterval=function(timerIntervalParam){if(checkCanConfigure("timerInterval")){timerInterval=extractIntFromParam(timerIntervalParam,timerInterval);}};this.isWaitForResponse=function(){return waitForResponse;};this.setWaitForResponse=function(waitForResponseParam){if(checkCanConfigure("waitForResponse")){waitForResponse=bool(waitForResponseParam);}};this.getBatchSize=function(){return batchSize;};this.setBatchSize=function(batchSizeParam){if(checkCanConfigure("batchSize")){batchSize=extractIntFromParam(batchSizeParam,batchSize);}};this.isSendAllOnUnload=function(){return sendAllOnUnload;};this.setSendAllOnUnload=function(sendAllOnUnloadParam){if(checkCanConfigure("sendAllOnUnload")){sendAllOnUnload=extractBooleanFromParam(sendAllOnUnloadParam,sendAllOnUnload);}};this.setRequestSuccessCallback=function(requestSuccessCallbackParam){requestSuccessCallback=extractFunctionFromParam(requestSuccessCallbackParam,requestSuccessCallback);};this.setFailCallback=function(failCallbackParam){failCallback=extractFunctionFromParam(failCallbackParam,failCallback);};this.getPostVarName=function(){return postVarName;};this.setPostVarName=function(postVarNameParam){if(checkCanConfigure("postVarName")){postVarName=extractStringFromParam(postVarNameParam,postVarName);}};this.getHeaders=function(){return headers;};this.addHeader=function(name,value){if(name.toLowerCase()=="content-type"){contentType=value;}else{headers.push({name:name,value:value});}};function sendAll(){if(isSupported&&enabled){sending=true;var currentRequestBatch;if(waitForResponse){if(queuedRequests.length>0){currentRequestBatch=queuedRequests.shift();sendRequest(preparePostData(currentRequestBatch),sendAll);}else{sending=false;if(timed){scheduleSending();}}}else{while((currentRequestBatch=queuedRequests.shift())){sendRequest(preparePostData(currentRequestBatch));}

+sending=false;if(timed){scheduleSending();}}}}

+this.sendAll=sendAll;function sendAllRemaining(){var sendingAnything=false;if(isSupported&&enabled){var actualBatchSize=appender.getLayout().allowBatching()?batchSize:1;var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);if(queuedLoggingEvents.length>=actualBatchSize){queuedRequests.push(batchedLoggingEvents);batchedLoggingEvents=[];}}

+if(batchedLoggingEvents.length>0){queuedRequests.push(batchedLoggingEvents);}

+sendingAnything=(queuedRequests.length>0);waitForResponse=false;timed=false;sendAll();}

+return sendingAnything;}

+this.sendAllRemaining=sendAllRemaining;function preparePostData(batchedLoggingEvents){var formattedMessages=[];var currentLoggingEvent;var postData="";while((currentLoggingEvent=batchedLoggingEvents.shift())){var currentFormattedMessage=appender.getLayout().format(currentLoggingEvent);if(appender.getLayout().ignoresThrowable()){currentFormattedMessage+=currentLoggingEvent.getThrowableStrRep();}

+formattedMessages.push(currentFormattedMessage);}

+if(batchedLoggingEvents.length==1){postData=formattedMessages.join("");}else{postData=appender.getLayout().batchHeader+

+formattedMessages.join(appender.getLayout().batchSeparator)+

+appender.getLayout().batchFooter;}

+if(contentType==appender.defaults.contentType){postData=appender.getLayout().returnsPostData?postData:urlEncode(postVarName)+"="+urlEncode(postData);if(postData.length>0){postData+="&";}

+postData+="layout="+urlEncode(appender.getLayout().toString());}

+return postData;}

+function scheduleSending(){window.setTimeout(sendAll,timerInterval);}

+function xmlHttpErrorHandler(){var msg="AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}}

+function sendRequest(postData,successCallback){try{var xmlHttp=getXmlHttp(xmlHttpErrorHandler);if(isSupported){if(xmlHttp.overrideMimeType){xmlHttp.overrideMimeType(appender.getLayout().getContentType());}

+xmlHttp.onreadystatechange=function(){if(xmlHttp.readyState==4){if(isHttpRequestSuccessful(xmlHttp)){if(requestSuccessCallback){requestSuccessCallback(xmlHttp);}

+if(successCallback){successCallback(xmlHttp);}}else{var msg="AjaxAppender.append: XMLHttpRequest request to URL "+

+url+" returned status code "+xmlHttp.status;handleError(msg);if(failCallback){failCallback(msg);}}

+xmlHttp.onreadystatechange=emptyFunction;xmlHttp=null;}};xmlHttp.open("POST",url,true);try{for(var i=0,header;header=headers[i++];){xmlHttp.setRequestHeader(header.name,header.value);}

+xmlHttp.setRequestHeader("Content-Type",contentType);}catch(headerEx){var msg="AjaxAppender.append: your browser's XMLHttpRequest implementation"+" does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";handleError(msg);isSupported=false;if(failCallback){failCallback(msg);}

+return;}

+xmlHttp.send(postData);}}catch(ex){var errMsg="AjaxAppender.append: error sending log message to "+url;handleError(errMsg,ex);isSupported=false;if(failCallback){failCallback(errMsg+". Details: "+getExceptionStringRep(ex));}}}

+this.append=function(loggingEvent){if(isSupported){if(!initialized){init();}

+queuedLoggingEvents.push(loggingEvent);var actualBatchSize=this.getLayout().allowBatching()?batchSize:1;if(queuedLoggingEvents.length>=actualBatchSize){var currentLoggingEvent;var batchedLoggingEvents=[];while((currentLoggingEvent=queuedLoggingEvents.shift())){batchedLoggingEvents.push(currentLoggingEvent);}

+queuedRequests.push(batchedLoggingEvents);if(!timed&&(!waitForResponse||(waitForResponse&&!sending))){sendAll();}}}};function init(){initialized=true;if(sendAllOnUnload){var oldBeforeUnload=window.onbeforeunload;window.onbeforeunload=function(){if(oldBeforeUnload){oldBeforeUnload();}

+if(sendAllRemaining()){return"Sending log messages";}};}

+if(timed){scheduleSending();}}}

+AjaxAppender.prototype=new Appender();AjaxAppender.prototype.defaults={waitForResponse:false,timed:false,timerInterval:1000,batchSize:1,sendAllOnUnload:false,requestSuccessCallback:null,failCallback:null,postVarName:"data",contentType:"application/x-www-form-urlencoded"};AjaxAppender.prototype.layout=new HttpPostDataLayout();AjaxAppender.prototype.toString=function(){return"AjaxAppender";};log4javascript.AjaxAppender=AjaxAppender;function setCookie(name,value,days,path){var expires;path=path?"; path="+path:"";if(days){var date=new Date();date.setTime(date.getTime()+(days*24*60*60*1000));expires="; expires="+date.toGMTString();}else{expires="";}

+document.cookie=escape(name)+"="+escape(value)+expires+path;}

+function getCookie(name){var nameEquals=escape(name)+"=";var ca=document.cookie.split(";");for(var i=0,len=ca.length;i<len;i++){var c=ca[i];while(c.charAt(0)===" "){c=c.substring(1,c.length);}

+if(c.indexOf(nameEquals)===0){return unescape(c.substring(nameEquals.length,c.length));}}

+return null;}

+function getBaseUrl(){var scripts=document.getElementsByTagName("script");for(var i=0,len=scripts.length;i<len;++i){if(scripts[i].src.indexOf("log4javascript")!=-1){var lastSlash=scripts[i].src.lastIndexOf("/");return(lastSlash==-1)?"":scripts[i].src.substr(0,lastSlash+1);}}

+return null;}

+function isLoaded(win){try{return bool(win.loaded);}catch(ex){return false;}}

+var ConsoleAppender;(function(){var getConsoleHtmlLines=function(){return['<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">','<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">','<head>','<title>log4javascript</title>','<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />','<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->','<meta http-equiv="X-UA-Compatible" content="IE=7" />','<script type="text/javascript">var isIe = false, isIePre7 = false;</script>','<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->','<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->','<script type="text/javascript">','//<![CDATA[','var loggingEnabled=true;var logQueuedEventsTimer=null;var logEntries=[];var logEntriesAndSeparators=[];var logItems=[];var renderDelay=100;var unrenderedLogItemsExist=false;var rootGroup,currentGroup=null;var loaded=false;var currentLogItem=null;var logMainContainer;function copyProperties(obj,props){for(var i in props){obj[i]=props[i];}}','function LogItem(){}','LogItem.prototype={mainContainer:null,wrappedContainer:null,unwrappedContainer:null,group:null,appendToLog:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].appendToLog();}','this.group.update();},doRemove:function(doUpdate,removeFromGroup){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].remove();}','this.unwrappedElementContainer=null;this.wrappedElementContainer=null;this.mainElementContainer=null;}','if(this.group&&removeFromGroup){this.group.removeChild(this,doUpdate);}','if(this===currentLogItem){currentLogItem=null;}},remove:function(doUpdate,removeFromGroup){this.doRemove(doUpdate,removeFromGroup);},render:function(){},accept:function(visitor){visitor.visit(this);},getUnwrappedDomContainer:function(){return this.group.unwrappedElementContainer.contentDiv;},getWrappedDomContainer:function(){return this.group.wrappedElementContainer.contentDiv;},getMainDomContainer:function(){return this.group.mainElementContainer.contentDiv;}};LogItem.serializedItemKeys={LOG_ENTRY:0,GROUP_START:1,GROUP_END:2};function LogItemContainerElement(){}','LogItemContainerElement.prototype={appendToLog:function(){var insertBeforeFirst=(newestAtTop&&this.containerDomNode.hasChildNodes());if(insertBeforeFirst){this.containerDomNode.insertBefore(this.mainDiv,this.containerDomNode.firstChild);}else{this.containerDomNode.appendChild(this.mainDiv);}}};function SeparatorElementContainer(containerDomNode){this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="separator";this.mainDiv.innerHTML="&nbsp;";}','SeparatorElementContainer.prototype=new LogItemContainerElement();SeparatorElementContainer.prototype.remove=function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;};function Separator(){this.rendered=false;}','Separator.prototype=new LogItem();copyProperties(Separator.prototype,{render:function(){var containerDomNode=this.group.contentDiv;if(isIe){this.unwrappedElementContainer=new SeparatorElementContainer(this.getUnwrappedDomContainer());this.wrappedElementContainer=new SeparatorElementContainer(this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new SeparatorElementContainer(this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}','this.content=this.formattedMessage;this.rendered=true;}});function GroupElementContainer(group,containerDomNode,isRoot,isWrapped){this.group=group;this.containerDomNode=containerDomNode;this.isRoot=isRoot;this.isWrapped=isWrapped;this.expandable=false;if(this.isRoot){if(isIe){this.contentDiv=logMainContainer.appendChild(document.createElement("div"));this.contentDiv.id=this.isWrapped?"log_wrapped":"log_unwrapped";}else{this.contentDiv=logMainContainer;}}else{var groupElementContainer=this;this.mainDiv=document.createElement("div");this.mainDiv.className="group";this.headingDiv=this.mainDiv.appendChild(document.createElement("div"));this.headingDiv.className="groupheading";this.expander=this.headingDiv.appendChild(document.createElement("span"));this.expander.className="expander unselectable greyedout";this.expander.unselectable=true;var expanderText=this.group.expanded?"-":"+";this.expanderTextNode=this.expander.appendChild(document.createTextNode(expanderText));this.headingDiv.appendChild(document.createTextNode(" "+this.group.name));this.contentDiv=this.mainDiv.appendChild(document.createElement("div"));var contentCssClass=this.group.expanded?"expanded":"collapsed";this.contentDiv.className="groupcontent "+contentCssClass;this.expander.onclick=function(){if(groupElementContainer.group.expandable){groupElementContainer.group.toggleExpanded();}};}}','GroupElementContainer.prototype=new LogItemContainerElement();copyProperties(GroupElementContainer.prototype,{toggleExpanded:function(){if(!this.isRoot){var oldCssClass,newCssClass,expanderText;if(this.group.expanded){newCssClass="expanded";oldCssClass="collapsed";expanderText="-";}else{newCssClass="collapsed";oldCssClass="expanded";expanderText="+";}','replaceClass(this.contentDiv,newCssClass,oldCssClass);this.expanderTextNode.nodeValue=expanderText;}},remove:function(){if(!this.isRoot){this.headingDiv=null;this.expander.onclick=null;this.expander=null;this.expanderTextNode=null;this.contentDiv=null;this.containerDomNode=null;this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;}},reverseChildren:function(){var node=null;var childDomNodes=[];while((node=this.contentDiv.firstChild)){this.contentDiv.removeChild(node);childDomNodes.push(node);}','while((node=childDomNodes.pop())){this.contentDiv.appendChild(node);}},update:function(){if(!this.isRoot){if(this.group.expandable){removeClass(this.expander,"greyedout");}else{addClass(this.expander,"greyedout");}}},clear:function(){if(this.isRoot){this.contentDiv.innerHTML="";}}});function Group(name,isRoot,initiallyExpanded){this.name=name;this.group=null;this.isRoot=isRoot;this.initiallyExpanded=initiallyExpanded;this.elementContainers=[];this.children=[];this.expanded=initiallyExpanded;this.rendered=false;this.expandable=false;}','Group.prototype=new LogItem();copyProperties(Group.prototype,{addChild:function(logItem){this.children.push(logItem);logItem.group=this;},render:function(){if(isIe){var unwrappedDomContainer,wrappedDomContainer;if(this.isRoot){unwrappedDomContainer=logMainContainer;wrappedDomContainer=logMainContainer;}else{unwrappedDomContainer=this.getUnwrappedDomContainer();wrappedDomContainer=this.getWrappedDomContainer();}','this.unwrappedElementContainer=new GroupElementContainer(this,unwrappedDomContainer,this.isRoot,false);this.wrappedElementContainer=new GroupElementContainer(this,wrappedDomContainer,this.isRoot,true);this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{var mainDomContainer=this.isRoot?logMainContainer:this.getMainDomContainer();this.mainElementContainer=new GroupElementContainer(this,mainDomContainer,this.isRoot,false);this.elementContainers=[this.mainElementContainer];}','this.rendered=true;},toggleExpanded:function(){this.expanded=!this.expanded;for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].toggleExpanded();}},expand:function(){if(!this.expanded){this.toggleExpanded();}},accept:function(visitor){visitor.visitGroup(this);},reverseChildren:function(){if(this.rendered){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].reverseChildren();}}},update:function(){var previouslyExpandable=this.expandable;this.expandable=(this.children.length!==0);if(this.expandable!==previouslyExpandable){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].update();}}},flatten:function(){var visitor=new GroupFlattener();this.accept(visitor);return visitor.logEntriesAndSeparators;},removeChild:function(child,doUpdate){array_remove(this.children,child);child.group=null;if(doUpdate){this.update();}},remove:function(doUpdate,removeFromGroup){for(var i=0,len=this.children.length;i<len;i++){this.children[i].remove(false,false);}','this.children=[];this.update();if(this===currentGroup){currentGroup=this.group;}','this.doRemove(doUpdate,removeFromGroup);},serialize:function(items){items.push([LogItem.serializedItemKeys.GROUP_START,this.name]);for(var i=0,len=this.children.length;i<len;i++){this.children[i].serialize(items);}','if(this!==currentGroup){items.push([LogItem.serializedItemKeys.GROUP_END]);}},clear:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clear();}}});function LogEntryElementContainer(){}','LogEntryElementContainer.prototype=new LogItemContainerElement();copyProperties(LogEntryElementContainer.prototype,{remove:function(){this.doRemove();},doRemove:function(){this.mainDiv.parentNode.removeChild(this.mainDiv);this.mainDiv=null;this.contentElement=null;this.containerDomNode=null;},setContent:function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=content;}},setSearchMatch:function(isMatch){var oldCssClass=isMatch?"searchnonmatch":"searchmatch";var newCssClass=isMatch?"searchmatch":"searchnonmatch";replaceClass(this.mainDiv,newCssClass,oldCssClass);},clearSearch:function(){removeClass(this.mainDiv,"searchmatch");removeClass(this.mainDiv,"searchnonmatch");}});function LogEntryWrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.mainDiv.className="logentry wrapped "+this.logEntry.level;this.contentElement=this.mainDiv;}','LogEntryWrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryWrappedElementContainer.prototype.setContent=function(content,wrappedContent){if(content===this.formattedMessage){this.contentElement.innerHTML="";this.contentElement.appendChild(document.createTextNode(this.formattedMessage));}else{this.contentElement.innerHTML=wrappedContent;}};function LogEntryUnwrappedElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry unwrapped "+this.logEntry.level;this.pre=this.mainDiv.appendChild(document.createElement("pre"));this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));this.pre.className="unwrapped";this.contentElement=this.pre;}','LogEntryUnwrappedElementContainer.prototype=new LogEntryElementContainer();LogEntryUnwrappedElementContainer.prototype.remove=function(){this.doRemove();this.pre=null;};function LogEntryMainElementContainer(logEntry,containerDomNode){this.logEntry=logEntry;this.containerDomNode=containerDomNode;this.mainDiv=document.createElement("div");this.mainDiv.className="logentry nonielogentry "+this.logEntry.level;this.contentElement=this.mainDiv.appendChild(document.createElement("span"));this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));}','LogEntryMainElementContainer.prototype=new LogEntryElementContainer();function LogEntry(level,formattedMessage){this.level=level;this.formattedMessage=formattedMessage;this.rendered=false;}','LogEntry.prototype=new LogItem();copyProperties(LogEntry.prototype,{render:function(){var logEntry=this;var containerDomNode=this.group.contentDiv;if(isIe){this.formattedMessage=this.formattedMessage.replace(/\\r\\n/g,"\\r");this.unwrappedElementContainer=new LogEntryUnwrappedElementContainer(this,this.getUnwrappedDomContainer());this.wrappedElementContainer=new LogEntryWrappedElementContainer(this,this.getWrappedDomContainer());this.elementContainers=[this.unwrappedElementContainer,this.wrappedElementContainer];}else{this.mainElementContainer=new LogEntryMainElementContainer(this,this.getMainDomContainer());this.elementContainers=[this.mainElementContainer];}','this.content=this.formattedMessage;this.rendered=true;},setContent:function(content,wrappedContent){if(content!=this.content){if(isIe&&(content!==this.formattedMessage)){content=content.replace(/\\r\\n/g,"\\r");}','for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setContent(content,wrappedContent);}','this.content=content;}},getSearchMatches:function(){var matches=[];var i,len;if(isIe){var unwrappedEls=getElementsByClass(this.unwrappedElementContainer.mainDiv,"searchterm","span");var wrappedEls=getElementsByClass(this.wrappedElementContainer.mainDiv,"searchterm","span");for(i=0,len=unwrappedEls.length;i<len;i++){matches[i]=new Match(this.level,null,unwrappedEls[i],wrappedEls[i]);}}else{var els=getElementsByClass(this.mainElementContainer.mainDiv,"searchterm","span");for(i=0,len=els.length;i<len;i++){matches[i]=new Match(this.level,els[i]);}}','return matches;},setSearchMatch:function(isMatch){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].setSearchMatch(isMatch);}},clearSearch:function(){for(var i=0,len=this.elementContainers.length;i<len;i++){this.elementContainers[i].clearSearch();}},accept:function(visitor){visitor.visitLogEntry(this);},serialize:function(items){items.push([LogItem.serializedItemKeys.LOG_ENTRY,this.level,this.formattedMessage]);}});function LogItemVisitor(){}','LogItemVisitor.prototype={visit:function(logItem){},visitParent:function(logItem){if(logItem.group){logItem.group.accept(this);}},visitChildren:function(logItem){for(var i=0,len=logItem.children.length;i<len;i++){logItem.children[i].accept(this);}},visitLogEntry:function(logEntry){this.visit(logEntry);},visitSeparator:function(separator){this.visit(separator);},visitGroup:function(group){this.visit(group);}};function GroupFlattener(){this.logEntriesAndSeparators=[];}','GroupFlattener.prototype=new LogItemVisitor();GroupFlattener.prototype.visitGroup=function(group){this.visitChildren(group);};GroupFlattener.prototype.visitLogEntry=function(logEntry){this.logEntriesAndSeparators.push(logEntry);};GroupFlattener.prototype.visitSeparator=function(separator){this.logEntriesAndSeparators.push(separator);};window.onload=function(){if(location.search){var queryBits=unescape(location.search).substr(1).split("&"),nameValueBits;for(var i=0,len=queryBits.length;i<len;i++){nameValueBits=queryBits[i].split("=");if(nameValueBits[0]=="log4javascript_domain"){document.domain=nameValueBits[1];break;}}}','logMainContainer=$("log");if(isIePre7){addClass(logMainContainer,"oldIe");}','rootGroup=new Group("root",true);rootGroup.render();currentGroup=rootGroup;setCommandInputWidth();setLogContainerHeight();toggleLoggingEnabled();toggleSearchEnabled();toggleSearchFilter();toggleSearchHighlight();applyFilters();checkAllLevels();toggleWrap();toggleNewestAtTop();toggleScrollToLatest();renderQueuedLogItems();loaded=true;$("command").value="";$("command").autocomplete="off";$("command").onkeydown=function(evt){evt=getEvent(evt);if(evt.keyCode==10||evt.keyCode==13){evalCommandLine();stopPropagation(evt);}else if(evt.keyCode==27){this.value="";this.focus();}else if(evt.keyCode==38&&commandHistory.length>0){currentCommandIndex=Math.max(0,currentCommandIndex-1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}else if(evt.keyCode==40&&commandHistory.length>0){currentCommandIndex=Math.min(commandHistory.length-1,currentCommandIndex+1);this.value=commandHistory[currentCommandIndex];moveCaretToEnd(this);}};$("command").onkeypress=function(evt){evt=getEvent(evt);if(evt.keyCode==38&&commandHistory.length>0&&evt.preventDefault){evt.preventDefault();}};$("command").onkeyup=function(evt){evt=getEvent(evt);if(evt.keyCode==27&&evt.preventDefault){evt.preventDefault();this.focus();}};document.onkeydown=function keyEventHandler(evt){evt=getEvent(evt);switch(evt.keyCode){case 69:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){evalLastCommand();cancelKeyEvent(evt);return false;}','break;case 75:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusSearch();cancelKeyEvent(evt);return false;}','break;case 40:case 76:if(evt.shiftKey&&(evt.ctrlKey||evt.metaKey)){focusCommandLine();cancelKeyEvent(evt);return false;}','break;}};setTimeout(setLogContainerHeight,20);setShowCommandLine(showCommandLine);doSearch();};window.onunload=function(){if(mainWindowExists()){appender.unload();}','appender=null;};function toggleLoggingEnabled(){setLoggingEnabled($("enableLogging").checked);}','function setLoggingEnabled(enable){loggingEnabled=enable;}','var appender=null;function setAppender(appenderParam){appender=appenderParam;}','function setShowCloseButton(showCloseButton){$("closeButton").style.display=showCloseButton?"inline":"none";}','function setShowHideButton(showHideButton){$("hideButton").style.display=showHideButton?"inline":"none";}','var newestAtTop=false;function LogItemContentReverser(){}','LogItemContentReverser.prototype=new LogItemVisitor();LogItemContentReverser.prototype.visitGroup=function(group){group.reverseChildren();this.visitChildren(group);};function setNewestAtTop(isNewestAtTop){var oldNewestAtTop=newestAtTop;var i,iLen,j,jLen;newestAtTop=Boolean(isNewestAtTop);if(oldNewestAtTop!=newestAtTop){var visitor=new LogItemContentReverser();rootGroup.accept(visitor);if(currentSearch){var currentMatch=currentSearch.matches[currentMatchIndex];var matchIndex=0;var matches=[];var actOnLogEntry=function(logEntry){var logEntryMatches=logEntry.getSearchMatches();for(j=0,jLen=logEntryMatches.length;j<jLen;j++){matches[matchIndex]=logEntryMatches[j];if(currentMatch&&logEntryMatches[j].equals(currentMatch)){currentMatchIndex=matchIndex;}','matchIndex++;}};if(newestAtTop){for(i=logEntries.length-1;i>=0;i--){actOnLogEntry(logEntries[i]);}}else{for(i=0,iLen=logEntries.length;i<iLen;i++){actOnLogEntry(logEntries[i]);}}','currentSearch.matches=matches;if(currentMatch){currentMatch.setCurrent();}}else if(scrollToLatest){doScrollToLatest();}}','$("newestAtTop").checked=isNewestAtTop;}','function toggleNewestAtTop(){var isNewestAtTop=$("newestAtTop").checked;setNewestAtTop(isNewestAtTop);}','var scrollToLatest=true;function setScrollToLatest(isScrollToLatest){scrollToLatest=isScrollToLatest;if(scrollToLatest){doScrollToLatest();}','$("scrollToLatest").checked=isScrollToLatest;}','function toggleScrollToLatest(){var isScrollToLatest=$("scrollToLatest").checked;setScrollToLatest(isScrollToLatest);}','function doScrollToLatest(){var l=logMainContainer;if(typeof l.scrollTop!="undefined"){if(newestAtTop){l.scrollTop=0;}else{var latestLogEntry=l.lastChild;if(latestLogEntry){l.scrollTop=l.scrollHeight;}}}}','var closeIfOpenerCloses=true;function setCloseIfOpenerCloses(isCloseIfOpenerCloses){closeIfOpenerCloses=isCloseIfOpenerCloses;}','var maxMessages=null;function setMaxMessages(max){maxMessages=max;pruneLogEntries();}','var showCommandLine=false;function setShowCommandLine(isShowCommandLine){showCommandLine=isShowCommandLine;if(loaded){$("commandLine").style.display=showCommandLine?"block":"none";setCommandInputWidth();setLogContainerHeight();}}','function focusCommandLine(){if(loaded){$("command").focus();}}','function focusSearch(){if(loaded){$("searchBox").focus();}}','function getLogItems(){var items=[];for(var i=0,len=logItems.length;i<len;i++){logItems[i].serialize(items);}','return items;}','function setLogItems(items){var loggingReallyEnabled=loggingEnabled;loggingEnabled=true;for(var i=0,len=items.length;i<len;i++){switch(items[i][0]){case LogItem.serializedItemKeys.LOG_ENTRY:log(items[i][1],items[i][2]);break;case LogItem.serializedItemKeys.GROUP_START:group(items[i][1]);break;case LogItem.serializedItemKeys.GROUP_END:groupEnd();break;}}','loggingEnabled=loggingReallyEnabled;}','function log(logLevel,formattedMessage){if(loggingEnabled){var logEntry=new LogEntry(logLevel,formattedMessage);logEntries.push(logEntry);logEntriesAndSeparators.push(logEntry);logItems.push(logEntry);currentGroup.addChild(logEntry);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}','logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}','function renderQueuedLogItems(){logQueuedEventsTimer=null;var pruned=pruneLogEntries();var initiallyHasMatches=currentSearch?currentSearch.hasMatches():false;for(var i=0,len=logItems.length;i<len;i++){if(!logItems[i].rendered){logItems[i].render();logItems[i].appendToLog();if(currentSearch&&(logItems[i]instanceof LogEntry)){currentSearch.applyTo(logItems[i]);}}}','if(currentSearch){if(pruned){if(currentSearch.hasVisibleMatches()){if(currentMatchIndex===null){setCurrentMatchIndex(0);}','displayMatches();}else{displayNoMatches();}}else if(!initiallyHasMatches&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}}','if(scrollToLatest){doScrollToLatest();}','unrenderedLogItemsExist=false;}','function pruneLogEntries(){if((maxMessages!==null)&&(logEntriesAndSeparators.length>maxMessages)){var numberToDelete=logEntriesAndSeparators.length-maxMessages;var prunedLogEntries=logEntriesAndSeparators.slice(0,numberToDelete);if(currentSearch){currentSearch.removeMatches(prunedLogEntries);}','var group;for(var i=0;i<numberToDelete;i++){group=logEntriesAndSeparators[i].group;array_remove(logItems,logEntriesAndSeparators[i]);array_remove(logEntries,logEntriesAndSeparators[i]);logEntriesAndSeparators[i].remove(true,true);if(group.children.length===0&&group!==currentGroup&&group!==rootGroup){array_remove(logItems,group);group.remove(true,true);}}','logEntriesAndSeparators=array_removeFromStart(logEntriesAndSeparators,numberToDelete);return true;}','return false;}','function group(name,startExpanded){if(loggingEnabled){initiallyExpanded=(typeof startExpanded==="undefined")?true:Boolean(startExpanded);var newGroup=new Group(name,false,initiallyExpanded);currentGroup.addChild(newGroup);currentGroup=newGroup;logItems.push(newGroup);if(loaded){if(logQueuedEventsTimer!==null){clearTimeout(logQueuedEventsTimer);}','logQueuedEventsTimer=setTimeout(renderQueuedLogItems,renderDelay);unrenderedLogItemsExist=true;}}}','function groupEnd(){currentGroup=(currentGroup===rootGroup)?rootGroup:currentGroup.group;}','function mainPageReloaded(){currentGroup=rootGroup;var separator=new Separator();logEntriesAndSeparators.push(separator);logItems.push(separator);currentGroup.addChild(separator);}','function closeWindow(){if(appender&&mainWindowExists()){appender.close(true);}else{window.close();}}','function hide(){if(appender&&mainWindowExists()){appender.hide();}}','var mainWindow=window;var windowId="log4javascriptConsoleWindow_"+new Date().getTime()+"_"+(""+Math.random()).substr(2);function setMainWindow(win){mainWindow=win;mainWindow[windowId]=window;if(opener&&closeIfOpenerCloses){pollOpener();}}','function pollOpener(){if(closeIfOpenerCloses){if(mainWindowExists()){setTimeout(pollOpener,500);}else{closeWindow();}}}','function mainWindowExists(){try{return(mainWindow&&!mainWindow.closed&&mainWindow[windowId]==window);}catch(ex){}','return false;}','var logLevels=["TRACE","DEBUG","INFO","WARN","ERROR","FATAL"];function getCheckBox(logLevel){return $("switch_"+logLevel);}','function getIeWrappedLogContainer(){return $("log_wrapped");}','function getIeUnwrappedLogContainer(){return $("log_unwrapped");}','function applyFilters(){for(var i=0;i<logLevels.length;i++){if(getCheckBox(logLevels[i]).checked){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}','updateSearchFromFilters();}','function toggleAllLevels(){var turnOn=$("switch_ALL").checked;for(var i=0;i<logLevels.length;i++){getCheckBox(logLevels[i]).checked=turnOn;if(turnOn){addClass(logMainContainer,logLevels[i]);}else{removeClass(logMainContainer,logLevels[i]);}}}','function checkAllLevels(){for(var i=0;i<logLevels.length;i++){if(!getCheckBox(logLevels[i]).checked){getCheckBox("ALL").checked=false;return;}}','getCheckBox("ALL").checked=true;}','function clearLog(){rootGroup.clear();currentGroup=rootGroup;logEntries=[];logItems=[];logEntriesAndSeparators=[];doSearch();}','function toggleWrap(){var enable=$("wrap").checked;if(enable){addClass(logMainContainer,"wrap");}else{removeClass(logMainContainer,"wrap");}','refreshCurrentMatch();}','var searchTimer=null;function scheduleSearch(){try{clearTimeout(searchTimer);}catch(ex){}','searchTimer=setTimeout(doSearch,500);}','function Search(searchTerm,isRegex,searchRegex,isCaseSensitive){this.searchTerm=searchTerm;this.isRegex=isRegex;this.searchRegex=searchRegex;this.isCaseSensitive=isCaseSensitive;this.matches=[];}','Search.prototype={hasMatches:function(){return this.matches.length>0;},hasVisibleMatches:function(){if(this.hasMatches()){for(var i=0;i<this.matches.length;i++){if(this.matches[i].isVisible()){return true;}}}','return false;},match:function(logEntry){var entryText=String(logEntry.formattedMessage);var matchesSearch=false;if(this.isRegex){matchesSearch=this.searchRegex.test(entryText);}else if(this.isCaseSensitive){matchesSearch=(entryText.indexOf(this.searchTerm)>-1);}else{matchesSearch=(entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase())>-1);}','return matchesSearch;},getNextVisibleMatchIndex:function(){for(var i=currentMatchIndex+1;i<this.matches.length;i++){if(this.matches[i].isVisible()){return i;}}','for(i=0;i<=currentMatchIndex;i++){if(this.matches[i].isVisible()){return i;}}','return-1;},getPreviousVisibleMatchIndex:function(){for(var i=currentMatchIndex-1;i>=0;i--){if(this.matches[i].isVisible()){return i;}}','for(var i=this.matches.length-1;i>=currentMatchIndex;i--){if(this.matches[i].isVisible()){return i;}}','return-1;},applyTo:function(logEntry){var doesMatch=this.match(logEntry);if(doesMatch){logEntry.group.expand();logEntry.setSearchMatch(true);var logEntryContent;var wrappedLogEntryContent;var searchTermReplacementStartTag="<span class=\\\"searchterm\\\">";var searchTermReplacementEndTag="<"+"/span>";var preTagName=isIe?"pre":"span";var preStartTag="<"+preTagName+" class=\\\"pre\\\">";var preEndTag="<"+"/"+preTagName+">";var startIndex=0;var searchIndex,matchedText,textBeforeMatch;if(this.isRegex){var flags=this.isCaseSensitive?"g":"gi";var capturingRegex=new RegExp("("+this.searchRegex.source+")",flags);var rnd=(""+Math.random()).substr(2);var startToken="%%s"+rnd+"%%";var endToken="%%e"+rnd+"%%";logEntryContent=logEntry.formattedMessage.replace(capturingRegex,startToken+"$1"+endToken);logEntryContent=escapeHtml(logEntryContent);var result;var searchString=logEntryContent;logEntryContent="";wrappedLogEntryContent="";while((searchIndex=searchString.indexOf(startToken,startIndex))>-1){var endTokenIndex=searchString.indexOf(endToken,searchIndex);matchedText=searchString.substring(searchIndex+startToken.length,endTokenIndex);textBeforeMatch=searchString.substring(startIndex,searchIndex);logEntryContent+=preStartTag+textBeforeMatch+preEndTag;logEntryContent+=searchTermReplacementStartTag+preStartTag+matchedText+','preEndTag+searchTermReplacementEndTag;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+','matchedText+searchTermReplacementEndTag;}','startIndex=endTokenIndex+endToken.length;}','logEntryContent+=preStartTag+searchString.substr(startIndex)+preEndTag;if(isIe){wrappedLogEntryContent+=searchString.substr(startIndex);}}else{logEntryContent="";wrappedLogEntryContent="";var searchTermReplacementLength=searchTermReplacementStartTag.length+','this.searchTerm.length+searchTermReplacementEndTag.length;var searchTermLength=this.searchTerm.length;var searchTermLowerCase=this.searchTerm.toLowerCase();var logTextLowerCase=logEntry.formattedMessage.toLowerCase();while((searchIndex=logTextLowerCase.indexOf(searchTermLowerCase,startIndex))>-1){matchedText=escapeHtml(logEntry.formattedMessage.substr(searchIndex,this.searchTerm.length));textBeforeMatch=escapeHtml(logEntry.formattedMessage.substring(startIndex,searchIndex));var searchTermReplacement=searchTermReplacementStartTag+','preStartTag+matchedText+preEndTag+searchTermReplacementEndTag;logEntryContent+=preStartTag+textBeforeMatch+preEndTag+searchTermReplacement;if(isIe){wrappedLogEntryContent+=textBeforeMatch+searchTermReplacementStartTag+','matchedText+searchTermReplacementEndTag;}','startIndex=searchIndex+searchTermLength;}','var textAfterLastMatch=escapeHtml(logEntry.formattedMessage.substr(startIndex));logEntryContent+=preStartTag+textAfterLastMatch+preEndTag;if(isIe){wrappedLogEntryContent+=textAfterLastMatch;}}','logEntry.setContent(logEntryContent,wrappedLogEntryContent);var logEntryMatches=logEntry.getSearchMatches();this.matches=this.matches.concat(logEntryMatches);}else{logEntry.setSearchMatch(false);logEntry.setContent(logEntry.formattedMessage,logEntry.formattedMessage);}','return doesMatch;},removeMatches:function(logEntries){var matchesToRemoveCount=0;var currentMatchRemoved=false;var matchesToRemove=[];var i,iLen,j,jLen;for(i=0,iLen=this.matches.length;i<iLen;i++){for(j=0,jLen=logEntries.length;j<jLen;j++){if(this.matches[i].belongsTo(logEntries[j])){matchesToRemove.push(this.matches[i]);if(i===currentMatchIndex){currentMatchRemoved=true;}}}}','var newMatch=currentMatchRemoved?null:this.matches[currentMatchIndex];if(currentMatchRemoved){for(i=currentMatchIndex,iLen=this.matches.length;i<iLen;i++){if(this.matches[i].isVisible()&&!array_contains(matchesToRemove,this.matches[i])){newMatch=this.matches[i];break;}}}','for(i=0,iLen=matchesToRemove.length;i<iLen;i++){array_remove(this.matches,matchesToRemove[i]);matchesToRemove[i].remove();}','if(this.hasVisibleMatches()){if(newMatch===null){setCurrentMatchIndex(0);}else{var newMatchIndex=0;for(i=0,iLen=this.matches.length;i<iLen;i++){if(newMatch===this.matches[i]){newMatchIndex=i;break;}}','setCurrentMatchIndex(newMatchIndex);}}else{currentMatchIndex=null;displayNoMatches();}}};function getPageOffsetTop(el,container){var currentEl=el;var y=0;while(currentEl&&currentEl!=container){y+=currentEl.offsetTop;currentEl=currentEl.offsetParent;}','return y;}','function scrollIntoView(el){var logContainer=logMainContainer;if(!$("wrap").checked){var logContainerLeft=logContainer.scrollLeft;var logContainerRight=logContainerLeft+logContainer.offsetWidth;var elLeft=el.offsetLeft;var elRight=elLeft+el.offsetWidth;if(elLeft<logContainerLeft||elRight>logContainerRight){logContainer.scrollLeft=elLeft-(logContainer.offsetWidth-el.offsetWidth)/2;}}','var logContainerTop=logContainer.scrollTop;var logContainerBottom=logContainerTop+logContainer.offsetHeight;var elTop=getPageOffsetTop(el)-getToolBarsHeight();var elBottom=elTop+el.offsetHeight;if(elTop<logContainerTop||elBottom>logContainerBottom){logContainer.scrollTop=elTop-(logContainer.offsetHeight-el.offsetHeight)/2;}}','function Match(logEntryLevel,spanInMainDiv,spanInUnwrappedPre,spanInWrappedDiv){this.logEntryLevel=logEntryLevel;this.spanInMainDiv=spanInMainDiv;if(isIe){this.spanInUnwrappedPre=spanInUnwrappedPre;this.spanInWrappedDiv=spanInWrappedDiv;}','this.mainSpan=isIe?spanInUnwrappedPre:spanInMainDiv;}','Match.prototype={equals:function(match){return this.mainSpan===match.mainSpan;},setCurrent:function(){if(isIe){addClass(this.spanInUnwrappedPre,"currentmatch");addClass(this.spanInWrappedDiv,"currentmatch");var elementToScroll=$("wrap").checked?this.spanInWrappedDiv:this.spanInUnwrappedPre;scrollIntoView(elementToScroll);}else{addClass(this.spanInMainDiv,"currentmatch");scrollIntoView(this.spanInMainDiv);}},belongsTo:function(logEntry){if(isIe){return isDescendant(this.spanInUnwrappedPre,logEntry.unwrappedPre);}else{return isDescendant(this.spanInMainDiv,logEntry.mainDiv);}},setNotCurrent:function(){if(isIe){removeClass(this.spanInUnwrappedPre,"currentmatch");removeClass(this.spanInWrappedDiv,"currentmatch");}else{removeClass(this.spanInMainDiv,"currentmatch");}},isOrphan:function(){return isOrphan(this.mainSpan);},isVisible:function(){return getCheckBox(this.logEntryLevel).checked;},remove:function(){if(isIe){this.spanInUnwrappedPre=null;this.spanInWrappedDiv=null;}else{this.spanInMainDiv=null;}}};var currentSearch=null;var currentMatchIndex=null;function doSearch(){var searchBox=$("searchBox");var searchTerm=searchBox.value;var isRegex=$("searchRegex").checked;var isCaseSensitive=$("searchCaseSensitive").checked;var i;if(searchTerm===""){$("searchReset").disabled=true;$("searchNav").style.display="none";removeClass(document.body,"searching");removeClass(searchBox,"hasmatches");removeClass(searchBox,"nomatches");for(i=0;i<logEntries.length;i++){logEntries[i].clearSearch();logEntries[i].setContent(logEntries[i].formattedMessage,logEntries[i].formattedMessage);}','currentSearch=null;setLogContainerHeight();}else{$("searchReset").disabled=false;$("searchNav").style.display="block";var searchRegex;var regexValid;if(isRegex){try{searchRegex=isCaseSensitive?new RegExp(searchTerm,"g"):new RegExp(searchTerm,"gi");regexValid=true;replaceClass(searchBox,"validregex","invalidregex");searchBox.title="Valid regex";}catch(ex){regexValid=false;replaceClass(searchBox,"invalidregex","validregex");searchBox.title="Invalid regex: "+(ex.message?ex.message:(ex.description?ex.description:"unknown error"));return;}}else{searchBox.title="";removeClass(searchBox,"validregex");removeClass(searchBox,"invalidregex");}','addClass(document.body,"searching");currentSearch=new Search(searchTerm,isRegex,searchRegex,isCaseSensitive);for(i=0;i<logEntries.length;i++){currentSearch.applyTo(logEntries[i]);}','setLogContainerHeight();if(currentSearch.hasVisibleMatches()){setCurrentMatchIndex(0);displayMatches();}else{displayNoMatches();}}}','function updateSearchFromFilters(){if(currentSearch){if(currentSearch.hasMatches()){if(currentMatchIndex===null){currentMatchIndex=0;}','var currentMatch=currentSearch.matches[currentMatchIndex];if(currentMatch.isVisible()){displayMatches();setCurrentMatchIndex(currentMatchIndex);}else{currentMatch.setNotCurrent();var nextVisibleMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextVisibleMatchIndex>-1){setCurrentMatchIndex(nextVisibleMatchIndex);displayMatches();}else{displayNoMatches();}}}else{displayNoMatches();}}}','function refreshCurrentMatch(){if(currentSearch&&currentSearch.hasVisibleMatches()){setCurrentMatchIndex(currentMatchIndex);}}','function displayMatches(){replaceClass($("searchBox"),"hasmatches","nomatches");$("searchBox").title=""+currentSearch.matches.length+" matches found";$("searchNav").style.display="block";setLogContainerHeight();}','function displayNoMatches(){replaceClass($("searchBox"),"nomatches","hasmatches");$("searchBox").title="No matches found";$("searchNav").style.display="none";setLogContainerHeight();}','function toggleSearchEnabled(enable){enable=(typeof enable=="undefined")?!$("searchDisable").checked:enable;$("searchBox").disabled=!enable;$("searchReset").disabled=!enable;$("searchRegex").disabled=!enable;$("searchNext").disabled=!enable;$("searchPrevious").disabled=!enable;$("searchCaseSensitive").disabled=!enable;$("searchNav").style.display=(enable&&($("searchBox").value!=="")&&currentSearch&&currentSearch.hasVisibleMatches())?"block":"none";if(enable){removeClass($("search"),"greyedout");addClass(document.body,"searching");if($("searchHighlight").checked){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}','if($("searchFilter").checked){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}','$("searchDisable").checked=!enable;}else{addClass($("search"),"greyedout");removeClass(document.body,"searching");removeClass(logMainContainer,"searchhighlight");removeClass(logMainContainer,"searchfilter");}','setLogContainerHeight();}','function toggleSearchFilter(){var enable=$("searchFilter").checked;if(enable){addClass(logMainContainer,"searchfilter");}else{removeClass(logMainContainer,"searchfilter");}','refreshCurrentMatch();}','function toggleSearchHighlight(){var enable=$("searchHighlight").checked;if(enable){addClass(logMainContainer,"searchhighlight");}else{removeClass(logMainContainer,"searchhighlight");}}','function clearSearch(){$("searchBox").value="";doSearch();}','function searchNext(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var nextMatchIndex=currentSearch.getNextVisibleMatchIndex();if(nextMatchIndex>currentMatchIndex||confirm("Reached the end of the page. Start from the top?")){setCurrentMatchIndex(nextMatchIndex);}}}','function searchPrevious(){if(currentSearch!==null&&currentMatchIndex!==null){currentSearch.matches[currentMatchIndex].setNotCurrent();var previousMatchIndex=currentSearch.getPreviousVisibleMatchIndex();if(previousMatchIndex<currentMatchIndex||confirm("Reached the start of the page. Continue from the bottom?")){setCurrentMatchIndex(previousMatchIndex);}}}','function setCurrentMatchIndex(index){currentMatchIndex=index;currentSearch.matches[currentMatchIndex].setCurrent();}','function addClass(el,cssClass){if(!hasClass(el,cssClass)){if(el.className){el.className+=" "+cssClass;}else{el.className=cssClass;}}}','function hasClass(el,cssClass){if(el.className){var classNames=el.className.split(" ");return array_contains(classNames,cssClass);}','return false;}','function removeClass(el,cssClass){if(hasClass(el,cssClass)){var existingClasses=el.className.split(" ");var newClasses=[];for(var i=0,len=existingClasses.length;i<len;i++){if(existingClasses[i]!=cssClass){newClasses[newClasses.length]=existingClasses[i];}}','el.className=newClasses.join(" ");}}','function replaceClass(el,newCssClass,oldCssClass){removeClass(el,oldCssClass);addClass(el,newCssClass);}','function getElementsByClass(el,cssClass,tagName){var elements=el.getElementsByTagName(tagName);var matches=[];for(var i=0,len=elements.length;i<len;i++){if(hasClass(elements[i],cssClass)){matches.push(elements[i]);}}','return matches;}','function $(id){return document.getElementById(id);}','function isDescendant(node,ancestorNode){while(node!=null){if(node===ancestorNode){return true;}','node=node.parentNode;}','return false;}','function isOrphan(node){var currentNode=node;while(currentNode){if(currentNode==document.body){return false;}','currentNode=currentNode.parentNode;}','return true;}','function escapeHtml(str){return str.replace(/&/g,"&amp;").replace(/[<]/g,"&lt;").replace(/>/g,"&gt;");}','function getWindowWidth(){if(window.innerWidth){return window.innerWidth;}else if(document.documentElement&&document.documentElement.clientWidth){return document.documentElement.clientWidth;}else if(document.body){return document.body.clientWidth;}','return 0;}','function getWindowHeight(){if(window.innerHeight){return window.innerHeight;}else if(document.documentElement&&document.documentElement.clientHeight){return document.documentElement.clientHeight;}else if(document.body){return document.body.clientHeight;}','return 0;}','function getToolBarsHeight(){return $("switches").offsetHeight;}','function getChromeHeight(){var height=getToolBarsHeight();if(showCommandLine){height+=$("commandLine").offsetHeight;}','return height;}','function setLogContainerHeight(){if(logMainContainer){var windowHeight=getWindowHeight();$("body").style.height=getWindowHeight()+"px";logMainContainer.style.height=""+','Math.max(0,windowHeight-getChromeHeight())+"px";}}','function setCommandInputWidth(){if(showCommandLine){$("command").style.width=""+Math.max(0,$("commandLineContainer").offsetWidth-','($("evaluateButton").offsetWidth+13))+"px";}}','window.onresize=function(){setCommandInputWidth();setLogContainerHeight();};if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0,len=arguments.length;i<len;i++){this[this.length]=arguments[i];}','return this.length;};}','if(!Array.prototype.pop){Array.prototype.pop=function(){if(this.length>0){var val=this[this.length-1];this.length=this.length-1;return val;}};}','if(!Array.prototype.shift){Array.prototype.shift=function(){if(this.length>0){var firstItem=this[0];for(var i=0,len=this.length-1;i<len;i++){this[i]=this[i+1];}','this.length=this.length-1;return firstItem;}};}','if(!Array.prototype.splice){Array.prototype.splice=function(startIndex,deleteCount){var itemsAfterDeleted=this.slice(startIndex+deleteCount);var itemsDeleted=this.slice(startIndex,startIndex+deleteCount);this.length=startIndex;var argumentsArray=[];for(var i=0,len=arguments.length;i<len;i++){argumentsArray[i]=arguments[i];}','var itemsToAppend=(argumentsArray.length>2)?itemsAfterDeleted=argumentsArray.slice(2).concat(itemsAfterDeleted):itemsAfterDeleted;for(i=0,len=itemsToAppend.length;i<len;i++){this.push(itemsToAppend[i]);}','return itemsDeleted;};}','function array_remove(arr,val){var index=-1;for(var i=0,len=arr.length;i<len;i++){if(arr[i]===val){index=i;break;}}','if(index>=0){arr.splice(index,1);return index;}else{return false;}}','function array_removeFromStart(array,numberToRemove){if(Array.prototype.splice){array.splice(0,numberToRemove);}else{for(var i=numberToRemove,len=array.length;i<len;i++){array[i-numberToRemove]=array[i];}','array.length=array.length-numberToRemove;}','return array;}','function array_contains(arr,val){for(var i=0,len=arr.length;i<len;i++){if(arr[i]==val){return true;}}','return false;}','function getErrorMessage(ex){if(ex.message){return ex.message;}else if(ex.description){return ex.description;}','return""+ex;}','function moveCaretToEnd(input){if(input.setSelectionRange){input.focus();var length=input.value.length;input.setSelectionRange(length,length);}else if(input.createTextRange){var range=input.createTextRange();range.collapse(false);range.select();}','input.focus();}','function stopPropagation(evt){if(evt.stopPropagation){evt.stopPropagation();}else if(typeof evt.cancelBubble!="undefined"){evt.cancelBubble=true;}}','function getEvent(evt){return evt?evt:event;}','function getTarget(evt){return evt.target?evt.target:evt.srcElement;}','function getRelatedTarget(evt){if(evt.relatedTarget){return evt.relatedTarget;}else if(evt.srcElement){switch(evt.type){case"mouseover":return evt.fromElement;case"mouseout":return evt.toElement;default:return evt.srcElement;}}}','function cancelKeyEvent(evt){evt.returnValue=false;stopPropagation(evt);}','function evalCommandLine(){var expr=$("command").value;evalCommand(expr);$("command").value="";}','function evalLastCommand(){if(lastCommand!=null){evalCommand(lastCommand);}}','var lastCommand=null;var commandHistory=[];var currentCommandIndex=0;function evalCommand(expr){if(appender){appender.evalCommandAndAppend(expr);}else{var prefix=">>> "+expr+"\\r\\n";try{log("INFO",prefix+eval(expr));}catch(ex){log("ERROR",prefix+"Error: "+getErrorMessage(ex));}}','if(expr!=commandHistory[commandHistory.length-1]){commandHistory.push(expr);if(appender){appender.storeCommandHistory(commandHistory);}}','currentCommandIndex=(expr==commandHistory[currentCommandIndex])?currentCommandIndex+1:commandHistory.length;lastCommand=expr;}','//]]>','</script>','<style type="text/css">','body{background-color:white;color:black;padding:0;margin:0;font-family:tahoma,verdana,arial,helvetica,sans-serif;overflow:hidden}div#switchesContainer input{margin-bottom:0}div.toolbar{border-top:solid #ffffff 1px;border-bottom:solid #aca899 1px;background-color:#f1efe7;padding:3px 5px;font-size:68.75%}div.toolbar,div#search input{font-family:tahoma,verdana,arial,helvetica,sans-serif}div.toolbar input.button{padding:0 5px;font-size:100%}div.toolbar input.hidden{display:none}div#switches input#clearButton{margin-left:20px}div#levels label{font-weight:bold}div#levels label,div#options label{margin-right:5px}div#levels label#wrapLabel{font-weight:normal}div#search label{margin-right:10px}div#search label.searchboxlabel{margin-right:0}div#search input{font-size:100%}div#search input.validregex{color:green}div#search input.invalidregex{color:red}div#search input.nomatches{color:white;background-color:#ff6666}div#search input.nomatches{color:white;background-color:#ff6666}div#searchNav{display:none}div#commandLine{display:none}div#commandLine input#command{font-size:100%;font-family:Courier New,Courier}div#commandLine input#evaluateButton{}*.greyedout{color:gray !important;border-color:gray !important}*.greyedout *.alwaysenabled{color:black}*.unselectable{-khtml-user-select:none;-moz-user-select:none;user-select:none}div#log{font-family:Courier New,Courier;font-size:75%;width:100%;overflow:auto;clear:both;position:relative}div.group{border-color:#cccccc;border-style:solid;border-width:1px 0 1px 1px;overflow:visible}div.oldIe div.group,div.oldIe div.group *,div.oldIe *.logentry{height:1%}div.group div.groupheading span.expander{border:solid black 1px;font-family:Courier New,Courier;font-size:0.833em;background-color:#eeeeee;position:relative;top:-1px;color:black;padding:0 2px;cursor:pointer;cursor:hand;height:1%}div.group div.groupcontent{margin-left:10px;padding-bottom:2px;overflow:visible}div.group div.expanded{display:block}div.group div.collapsed{display:none}*.logentry{overflow:visible;display:none;white-space:pre}span.pre{white-space:pre}pre.unwrapped{display:inline !important}pre.unwrapped pre.pre,div.wrapped pre.pre{display:inline}div.wrapped pre.pre{white-space:normal}div.wrapped{display:none}body.searching *.logentry span.currentmatch{color:white !important;background-color:green !important}body.searching div.searchhighlight *.logentry span.searchterm{color:black;background-color:yellow}div.wrap *.logentry{white-space:normal !important;border-width:0 0 1px 0;border-color:#dddddd;border-style:dotted}div.wrap #log_wrapped,#log_unwrapped{display:block}div.wrap #log_unwrapped,#log_wrapped{display:none}div.wrap *.logentry span.pre{overflow:visible;white-space:normal}div.wrap *.logentry pre.unwrapped{display:none}div.wrap *.logentry span.wrapped{display:inline}div.searchfilter *.searchnonmatch{display:none !important}div#log *.TRACE,label#label_TRACE{color:#666666}div#log *.DEBUG,label#label_DEBUG{color:green}div#log *.INFO,label#label_INFO{color:#000099}div#log *.WARN,label#label_WARN{color:#999900}div#log *.ERROR,label#label_ERROR{color:red}div#log *.FATAL,label#label_FATAL{color:#660066}div.TRACE#log *.TRACE,div.DEBUG#log *.DEBUG,div.INFO#log *.INFO,div.WARN#log *.WARN,div.ERROR#log *.ERROR,div.FATAL#log *.FATAL{display:block}div#log div.separator{background-color:#cccccc;margin:5px 0;line-height:1px}','</style>','</head>','<body id="body">','<div id="switchesContainer">','<div id="switches">','<div id="levels" class="toolbar">','Filters:','<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>','<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>','<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>','<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>','<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>','<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>','<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>','</div>','<div id="search" class="toolbar">','<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />','<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />','<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>','<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>','<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>','<div id="searchNav">','<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />','<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />','<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>','<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>','</div>','</div>','<div id="options" class="toolbar">','Options:','<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>','<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>','<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>','<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>','<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />','<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />','<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />','</div>','</div>','</div>','<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>','<div id="commandLine" class="toolbar">','<div id="commandLineContainer">','<input type="text" id="command" title="Enter a JavaScript command here and hit return or press \'Evaluate\'" />','<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />','</div>','</div>','</body>','</html>',''];};var defaultCommandLineFunctions=[];ConsoleAppender=function(){};var consoleAppenderIdCounter=1;ConsoleAppender.prototype=new Appender();ConsoleAppender.prototype.create=function(inPage,container,lazyInit,initiallyMinimized,useDocumentWrite,width,height,focusConsoleWindow){var appender=this;var initialized=false;var consoleWindowCreated=false;var consoleWindowLoaded=false;var consoleClosed=false;var queuedLoggingEvents=[];var isSupported=true;var consoleAppenderId=consoleAppenderIdCounter++;initiallyMinimized=extractBooleanFromParam(initiallyMinimized,this.defaults.initiallyMinimized);lazyInit=extractBooleanFromParam(lazyInit,this.defaults.lazyInit);useDocumentWrite=extractBooleanFromParam(useDocumentWrite,this.defaults.useDocumentWrite);var newestMessageAtTop=this.defaults.newestMessageAtTop;var scrollToLatestMessage=this.defaults.scrollToLatestMessage;width=width?width:this.defaults.width;height=height?height:this.defaults.height;var maxMessages=this.defaults.maxMessages;var showCommandLine=this.defaults.showCommandLine;var commandLineObjectExpansionDepth=this.defaults.commandLineObjectExpansionDepth;var showHideButton=this.defaults.showHideButton;var showCloseButton=this.defaults.showCloseButton;var showLogEntryDeleteButtons=this.defaults.showLogEntryDeleteButtons;this.setLayout(this.defaults.layout);var init,createWindow,safeToAppend,getConsoleWindow,open;var appenderName=inPage?"InPageAppender":"PopUpAppender";var checkCanConfigure=function(configOptionName){if(consoleWindowCreated){handleError(appenderName+": configuration option '"+configOptionName+"' may not be set after the appender has been initialized");return false;}

+return true;};var consoleWindowExists=function(){return(consoleWindowLoaded&&isSupported&&!consoleClosed);};this.isNewestMessageAtTop=function(){return newestMessageAtTop;};this.setNewestMessageAtTop=function(newestMessageAtTopParam){newestMessageAtTop=bool(newestMessageAtTopParam);if(consoleWindowExists()){getConsoleWindow().setNewestAtTop(newestMessageAtTop);}};this.isScrollToLatestMessage=function(){return scrollToLatestMessage;};this.setScrollToLatestMessage=function(scrollToLatestMessageParam){scrollToLatestMessage=bool(scrollToLatestMessageParam);if(consoleWindowExists()){getConsoleWindow().setScrollToLatest(scrollToLatestMessage);}};this.getWidth=function(){return width;};this.setWidth=function(widthParam){if(checkCanConfigure("width")){width=extractStringFromParam(widthParam,width);}};this.getHeight=function(){return height;};this.setHeight=function(heightParam){if(checkCanConfigure("height")){height=extractStringFromParam(heightParam,height);}};this.getMaxMessages=function(){return maxMessages;};this.setMaxMessages=function(maxMessagesParam){maxMessages=extractIntFromParam(maxMessagesParam,maxMessages);if(consoleWindowExists()){getConsoleWindow().setMaxMessages(maxMessages);}};this.isShowCommandLine=function(){return showCommandLine;};this.setShowCommandLine=function(showCommandLineParam){showCommandLine=bool(showCommandLineParam);if(consoleWindowExists()){getConsoleWindow().setShowCommandLine(showCommandLine);}};this.isShowHideButton=function(){return showHideButton;};this.setShowHideButton=function(showHideButtonParam){showHideButton=bool(showHideButtonParam);if(consoleWindowExists()){getConsoleWindow().setShowHideButton(showHideButton);}};this.isShowCloseButton=function(){return showCloseButton;};this.setShowCloseButton=function(showCloseButtonParam){showCloseButton=bool(showCloseButtonParam);if(consoleWindowExists()){getConsoleWindow().setShowCloseButton(showCloseButton);}};this.getCommandLineObjectExpansionDepth=function(){return commandLineObjectExpansionDepth;};this.setCommandLineObjectExpansionDepth=function(commandLineObjectExpansionDepthParam){commandLineObjectExpansionDepth=extractIntFromParam(commandLineObjectExpansionDepthParam,commandLineObjectExpansionDepth);};var minimized=initiallyMinimized;this.isInitiallyMinimized=function(){return initiallyMinimized;};this.setInitiallyMinimized=function(initiallyMinimizedParam){if(checkCanConfigure("initiallyMinimized")){initiallyMinimized=bool(initiallyMinimizedParam);minimized=initiallyMinimized;}};this.isUseDocumentWrite=function(){return useDocumentWrite;};this.setUseDocumentWrite=function(useDocumentWriteParam){if(checkCanConfigure("useDocumentWrite")){useDocumentWrite=bool(useDocumentWriteParam);}};function QueuedLoggingEvent(loggingEvent,formattedMessage){this.loggingEvent=loggingEvent;this.levelName=loggingEvent.level.name;this.formattedMessage=formattedMessage;}

+QueuedLoggingEvent.prototype.append=function(){getConsoleWindow().log(this.levelName,this.formattedMessage);};function QueuedGroup(name,initiallyExpanded){this.name=name;this.initiallyExpanded=initiallyExpanded;}

+QueuedGroup.prototype.append=function(){getConsoleWindow().group(this.name,this.initiallyExpanded);};function QueuedGroupEnd(){}

+QueuedGroupEnd.prototype.append=function(){getConsoleWindow().groupEnd();};var checkAndAppend=function(){safeToAppend();if(!initialized){init();}else if(consoleClosed&&reopenWhenClosed){createWindow();}

+if(safeToAppend()){appendQueuedLoggingEvents();}};this.append=function(loggingEvent){if(isSupported){var formattedMessage=appender.getLayout().format(loggingEvent);if(this.getLayout().ignoresThrowable()){formattedMessage+=loggingEvent.getThrowableStrRep();}

+queuedLoggingEvents.push(new QueuedLoggingEvent(loggingEvent,formattedMessage));checkAndAppend();}};this.group=function(name,initiallyExpanded){if(isSupported){queuedLoggingEvents.push(new QueuedGroup(name,initiallyExpanded));checkAndAppend();}};this.groupEnd=function(){if(isSupported){queuedLoggingEvents.push(new QueuedGroupEnd());checkAndAppend();}};var appendQueuedLoggingEvents=function(){var currentLoggingEvent;while(queuedLoggingEvents.length>0){queuedLoggingEvents.shift().append();}

+if(focusConsoleWindow){getConsoleWindow().focus();}};this.setAddedToLogger=function(logger){this.loggers.push(logger);if(enabled&&!lazyInit){init();}};this.clear=function(){if(consoleWindowExists()){getConsoleWindow().clearLog();}

+queuedLoggingEvents.length=0;};this.focus=function(){if(consoleWindowExists()){getConsoleWindow().focus();}};this.focusCommandLine=function(){if(consoleWindowExists()){getConsoleWindow().focusCommandLine();}};this.focusSearch=function(){if(consoleWindowExists()){getConsoleWindow().focusSearch();}};var commandWindow=window;this.getCommandWindow=function(){return commandWindow;};this.setCommandWindow=function(commandWindowParam){commandWindow=commandWindowParam;};this.executeLastCommand=function(){if(consoleWindowExists()){getConsoleWindow().evalLastCommand();}};var commandLayout=new PatternLayout("%m");this.getCommandLayout=function(){return commandLayout;};this.setCommandLayout=function(commandLayoutParam){commandLayout=commandLayoutParam;};this.evalCommandAndAppend=function(expr){var commandReturnValue={appendResult:true,isError:false};var commandOutput="";try{var result,i;if(!commandWindow.eval&&commandWindow.execScript){commandWindow.execScript("null");}

+var commandLineFunctionsHash={};for(i=0,len=commandLineFunctions.length;i<len;i++){commandLineFunctionsHash[commandLineFunctions[i][0]]=commandLineFunctions[i][1];}

+var objectsToRestore=[];var addObjectToRestore=function(name){objectsToRestore.push([name,commandWindow[name]]);};addObjectToRestore("appender");commandWindow.appender=appender;addObjectToRestore("commandReturnValue");commandWindow.commandReturnValue=commandReturnValue;addObjectToRestore("commandLineFunctionsHash");commandWindow.commandLineFunctionsHash=commandLineFunctionsHash;var addFunctionToWindow=function(name){addObjectToRestore(name);commandWindow[name]=function(){return this.commandLineFunctionsHash[name](appender,arguments,commandReturnValue);};};for(i=0,len=commandLineFunctions.length;i<len;i++){addFunctionToWindow(commandLineFunctions[i][0]);}

+if(commandWindow===window&&commandWindow.execScript){addObjectToRestore("evalExpr");addObjectToRestore("result");window.evalExpr=expr;commandWindow.execScript("window.result=eval(window.evalExpr);");result=window.result;}else{result=commandWindow.eval(expr);}

+commandOutput=isUndefined(result)?result:formatObjectExpansion(result,commandLineObjectExpansionDepth);for(i=0,len=objectsToRestore.length;i<len;i++){commandWindow[objectsToRestore[i][0]]=objectsToRestore[i][1];}}catch(ex){commandOutput="Error evaluating command: "+getExceptionStringRep(ex);commandReturnValue.isError=true;}

+if(commandReturnValue.appendResult){var message=">>> "+expr;if(!isUndefined(commandOutput)){message+=newLine+commandOutput;}

+var level=commandReturnValue.isError?Level.ERROR:Level.INFO;var loggingEvent=new LoggingEvent(null,new Date(),level,[message],null);var mainLayout=this.getLayout();this.setLayout(commandLayout);this.append(loggingEvent);this.setLayout(mainLayout);}};var commandLineFunctions=defaultCommandLineFunctions.concat([]);this.addCommandLineFunction=function(functionName,commandLineFunction){commandLineFunctions.push([functionName,commandLineFunction]);};var commandHistoryCookieName="log4javascriptCommandHistory";this.storeCommandHistory=function(commandHistory){setCookie(commandHistoryCookieName,commandHistory.join(","));};var writeHtml=function(doc){var lines=getConsoleHtmlLines();doc.open();for(var i=0,len=lines.length;i<len;i++){doc.writeln(lines[i]);}

+doc.close();};this.setEventTypes(["load","unload"]);var consoleWindowLoadHandler=function(){var win=getConsoleWindow();win.setAppender(appender);win.setNewestAtTop(newestMessageAtTop);win.setScrollToLatest(scrollToLatestMessage);win.setMaxMessages(maxMessages);win.setShowCommandLine(showCommandLine);win.setShowHideButton(showHideButton);win.setShowCloseButton(showCloseButton);win.setMainWindow(window);var storedValue=getCookie(commandHistoryCookieName);if(storedValue){win.commandHistory=storedValue.split(",");win.currentCommandIndex=win.commandHistory.length;}

+appender.dispatchEvent("load",{"win":win});};this.unload=function(){logLog.debug("unload "+this+", caller: "+this.unload.caller);if(!consoleClosed){logLog.debug("really doing unload "+this);consoleClosed=true;consoleWindowLoaded=false;consoleWindowCreated=false;appender.dispatchEvent("unload",{});}};var pollConsoleWindow=function(windowTest,interval,successCallback,errorMessage){function doPoll(){try{if(consoleClosed){clearInterval(poll);}

+if(windowTest(getConsoleWindow())){clearInterval(poll);successCallback();}}catch(ex){clearInterval(poll);isSupported=false;handleError(errorMessage,ex);}}

+var poll=setInterval(doPoll,interval);};var getConsoleUrl=function(){var documentDomainSet=(document.domain!=location.hostname);return useDocumentWrite?"":getBaseUrl()+"console.html"+

+(documentDomainSet?"?log4javascript_domain="+escape(document.domain):"");};if(inPage){var containerElement=null;var cssProperties=[];this.addCssProperty=function(name,value){if(checkCanConfigure("cssProperties")){cssProperties.push([name,value]);}};var windowCreationStarted=false;var iframeContainerDiv;var iframeId=uniqueId+"_InPageAppender_"+consoleAppenderId;this.hide=function(){if(initialized&&consoleWindowCreated){if(consoleWindowExists()){getConsoleWindow().$("command").blur();}

+iframeContainerDiv.style.display="none";minimized=true;}};this.show=function(){if(initialized){if(consoleWindowCreated){iframeContainerDiv.style.display="block";this.setShowCommandLine(showCommandLine);minimized=false;}else if(!windowCreationStarted){createWindow(true);}}};this.isVisible=function(){return!minimized&&!consoleClosed;};this.close=function(fromButton){if(!consoleClosed&&(!fromButton||confirm("This will permanently remove the console from the page. No more messages will be logged. Do you wish to continue?"))){iframeContainerDiv.parentNode.removeChild(iframeContainerDiv);this.unload();}};open=function(){var initErrorMessage="InPageAppender.open: unable to create console iframe";function finalInit(){try{if(!initiallyMinimized){appender.show();}

+consoleWindowLoadHandler();consoleWindowLoaded=true;appendQueuedLoggingEvents();}catch(ex){isSupported=false;handleError(initErrorMessage,ex);}}

+function writeToDocument(){try{var windowTest=function(win){return isLoaded(win);};if(useDocumentWrite){writeHtml(getConsoleWindow().document);}

+if(windowTest(getConsoleWindow())){finalInit();}else{pollConsoleWindow(windowTest,100,finalInit,initErrorMessage);}}catch(ex){isSupported=false;handleError(initErrorMessage,ex);}}

+minimized=false;iframeContainerDiv=containerElement.appendChild(document.createElement("div"));iframeContainerDiv.style.width=width;iframeContainerDiv.style.height=height;iframeContainerDiv.style.border="solid gray 1px";for(var i=0,len=cssProperties.length;i<len;i++){iframeContainerDiv.style[cssProperties[i][0]]=cssProperties[i][1];}

+var iframeSrc=useDocumentWrite?"":" src='"+getConsoleUrl()+"'";iframeContainerDiv.innerHTML="<iframe id='"+iframeId+"' name='"+iframeId+"' width='100%' height='100%' frameborder='0'"+iframeSrc+" scrolling='no'></iframe>";consoleClosed=false;var iframeDocumentExistsTest=function(win){try{return bool(win)&&bool(win.document);}catch(ex){return false;}};if(iframeDocumentExistsTest(getConsoleWindow())){writeToDocument();}else{pollConsoleWindow(iframeDocumentExistsTest,100,writeToDocument,initErrorMessage);}

+consoleWindowCreated=true;};createWindow=function(show){if(show||!initiallyMinimized){var pageLoadHandler=function(){if(!container){containerElement=document.createElement("div");containerElement.style.position="fixed";containerElement.style.left="0";containerElement.style.right="0";containerElement.style.bottom="0";document.body.appendChild(containerElement);appender.addCssProperty("borderWidth","1px 0 0 0");appender.addCssProperty("zIndex",1000000);open();}else{try{var el=document.getElementById(container);if(el.nodeType==1){containerElement=el;}

+open();}catch(ex){handleError("InPageAppender.init: invalid container element '"+container+"' supplied",ex);}}};if(pageLoaded&&container&&container.appendChild){containerElement=container;open();}else if(pageLoaded){pageLoadHandler();}else{log4javascript.addEventListener("load",pageLoadHandler);}

+windowCreationStarted=true;}};init=function(){createWindow();initialized=true;};getConsoleWindow=function(){var iframe=window.frames[iframeId];if(iframe){return iframe;}};safeToAppend=function(){if(isSupported&&!consoleClosed){if(consoleWindowCreated&&!consoleWindowLoaded&&getConsoleWindow()&&isLoaded(getConsoleWindow())){consoleWindowLoaded=true;}

+return consoleWindowLoaded;}

+return false;};}else{var useOldPopUp=appender.defaults.useOldPopUp;var complainAboutPopUpBlocking=appender.defaults.complainAboutPopUpBlocking;var reopenWhenClosed=this.defaults.reopenWhenClosed;this.isUseOldPopUp=function(){return useOldPopUp;};this.setUseOldPopUp=function(useOldPopUpParam){if(checkCanConfigure("useOldPopUp")){useOldPopUp=bool(useOldPopUpParam);}};this.isComplainAboutPopUpBlocking=function(){return complainAboutPopUpBlocking;};this.setComplainAboutPopUpBlocking=function(complainAboutPopUpBlockingParam){if(checkCanConfigure("complainAboutPopUpBlocking")){complainAboutPopUpBlocking=bool(complainAboutPopUpBlockingParam);}};this.isFocusPopUp=function(){return focusConsoleWindow;};this.setFocusPopUp=function(focusPopUpParam){focusConsoleWindow=bool(focusPopUpParam);};this.isReopenWhenClosed=function(){return reopenWhenClosed;};this.setReopenWhenClosed=function(reopenWhenClosedParam){reopenWhenClosed=bool(reopenWhenClosedParam);};this.close=function(){logLog.debug("close "+this);try{popUp.close();this.unload();}catch(ex){}};this.hide=function(){logLog.debug("hide "+this);if(consoleWindowExists()){this.close();}};this.show=function(){logLog.debug("show "+this);if(!consoleWindowCreated){open();}};this.isVisible=function(){return safeToAppend();};var popUp;open=function(){var windowProperties="width="+width+",height="+height+",status,resizable";var frameInfo="";try{var frameEl=window.frameElement;if(frameEl){frameInfo="_"+frameEl.tagName+"_"+(frameEl.name||frameEl.id||"");}}catch(e){frameInfo="_inaccessibleParentFrame";}

+var windowName="PopUp_"+location.host.replace(/[^a-z0-9]/gi,"_")+"_"+consoleAppenderId+frameInfo;if(!useOldPopUp||!useDocumentWrite){windowName=windowName+"_"+uniqueId;}

+var checkPopUpClosed=function(win){if(consoleClosed){return true;}else{try{return bool(win)&&win.closed;}catch(ex){}}

+return false;};var popUpClosedCallback=function(){if(!consoleClosed){appender.unload();}};function finalInit(){getConsoleWindow().setCloseIfOpenerCloses(!useOldPopUp||!useDocumentWrite);consoleWindowLoadHandler();consoleWindowLoaded=true;appendQueuedLoggingEvents();pollConsoleWindow(checkPopUpClosed,500,popUpClosedCallback,"PopUpAppender.checkPopUpClosed: error checking pop-up window");}

+try{popUp=window.open(getConsoleUrl(),windowName,windowProperties);consoleClosed=false;consoleWindowCreated=true;if(popUp&&popUp.document){if(useDocumentWrite&&useOldPopUp&&isLoaded(popUp)){popUp.mainPageReloaded();finalInit();}else{if(useDocumentWrite){writeHtml(popUp.document);}

+var popUpLoadedTest=function(win){return bool(win)&&isLoaded(win);};if(isLoaded(popUp)){finalInit();}else{pollConsoleWindow(popUpLoadedTest,100,finalInit,"PopUpAppender.init: unable to create console window");}}}else{isSupported=false;logLog.warn("PopUpAppender.init: pop-ups blocked, please unblock to use PopUpAppender");if(complainAboutPopUpBlocking){handleError("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");}}}catch(ex){handleError("PopUpAppender.init: error creating pop-up",ex);}};createWindow=function(){if(!initiallyMinimized){open();}};init=function(){createWindow();initialized=true;};getConsoleWindow=function(){return popUp;};safeToAppend=function(){if(isSupported&&!isUndefined(popUp)&&!consoleClosed){if(popUp.closed||(consoleWindowLoaded&&isUndefined(popUp.closed))){appender.unload();logLog.debug("PopUpAppender: pop-up closed");return false;}

+if(!consoleWindowLoaded&&isLoaded(popUp)){consoleWindowLoaded=true;}}

+return isSupported&&consoleWindowLoaded&&!consoleClosed;};}

+this.getConsoleWindow=getConsoleWindow;};ConsoleAppender.addGlobalCommandLineFunction=function(functionName,commandLineFunction){defaultCommandLineFunctions.push([functionName,commandLineFunction]);};function PopUpAppender(lazyInit,initiallyMinimized,useDocumentWrite,width,height){this.create(false,null,lazyInit,initiallyMinimized,useDocumentWrite,width,height,this.defaults.focusPopUp);}

+PopUpAppender.prototype=new ConsoleAppender();PopUpAppender.prototype.defaults={layout:new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),initiallyMinimized:false,focusPopUp:false,lazyInit:true,useOldPopUp:true,complainAboutPopUpBlocking:true,newestMessageAtTop:false,scrollToLatestMessage:true,width:"600",height:"400",reopenWhenClosed:false,maxMessages:null,showCommandLine:true,commandLineObjectExpansionDepth:1,showHideButton:false,showCloseButton:true,showLogEntryDeleteButtons:true,useDocumentWrite:true};PopUpAppender.prototype.toString=function(){return"PopUpAppender";};log4javascript.PopUpAppender=PopUpAppender;function InPageAppender(container,lazyInit,initiallyMinimized,useDocumentWrite,width,height){this.create(true,container,lazyInit,initiallyMinimized,useDocumentWrite,width,height,false);}

+InPageAppender.prototype=new ConsoleAppender();InPageAppender.prototype.defaults={layout:new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),initiallyMinimized:false,lazyInit:true,newestMessageAtTop:false,scrollToLatestMessage:true,width:"100%",height:"220px",maxMessages:null,showCommandLine:true,commandLineObjectExpansionDepth:1,showHideButton:false,showCloseButton:false,showLogEntryDeleteButtons:true,useDocumentWrite:true};InPageAppender.prototype.toString=function(){return"InPageAppender";};log4javascript.InPageAppender=InPageAppender;log4javascript.InlineAppender=InPageAppender;})();function padWithSpaces(str,len){if(str.length<len){var spaces=[];var numberOfSpaces=Math.max(0,len-str.length);for(var i=0;i<numberOfSpaces;i++){spaces[i]=" ";}

+str+=spaces.join("");}

+return str;}

+(function(){function dir(obj){var maxLen=0;for(var p in obj){maxLen=Math.max(toStr(p).length,maxLen);}

+var propList=[];for(p in obj){var propNameStr="  "+padWithSpaces(toStr(p),maxLen+2);var propVal;try{propVal=splitIntoLines(toStr(obj[p])).join(padWithSpaces(newLine,maxLen+6));}catch(ex){propVal="[Error obtaining property. Details: "+getExceptionMessage(ex)+"]";}

+propList.push(propNameStr+propVal);}

+return propList.join(newLine);}

+var nodeTypes={ELEMENT_NODE:1,ATTRIBUTE_NODE:2,TEXT_NODE:3,CDATA_SECTION_NODE:4,ENTITY_REFERENCE_NODE:5,ENTITY_NODE:6,PROCESSING_INSTRUCTION_NODE:7,COMMENT_NODE:8,DOCUMENT_NODE:9,DOCUMENT_TYPE_NODE:10,DOCUMENT_FRAGMENT_NODE:11,NOTATION_NODE:12};var preFormattedElements=["script","pre"];var emptyElements=["br","img","hr","param","link","area","input","col","base","meta"];var indentationUnit="  ";function getXhtml(rootNode,includeRootNode,indentation,startNewLine,preformatted){includeRootNode=(typeof includeRootNode=="undefined")?true:!!includeRootNode;if(typeof indentation!="string"){indentation="";}

+startNewLine=!!startNewLine;preformatted=!!preformatted;var xhtml;function isWhitespace(node){return((node.nodeType==nodeTypes.TEXT_NODE)&&/^[ \t\r\n]*$/.test(node.nodeValue));}

+function fixAttributeValue(attrValue){return attrValue.toString().replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/"/g,"&quot;");}

+function getStyleAttributeValue(el){var stylePairs=el.style.cssText.split(";");var styleValue="";var isFirst=true;for(var j=0,len=stylePairs.length;j<len;j++){var nameValueBits=stylePairs[j].split(":");var props=[];if(!/^\s*$/.test(nameValueBits[0])){props.push(trim(nameValueBits[0]).toLowerCase()+":"+trim(nameValueBits[1]));}

+styleValue=props.join(";");}

+return styleValue;}

+function getNamespace(el){if(el.prefix){return el.prefix;}else if(el.outerHTML){var regex=new RegExp("<([^:]+):"+el.tagName+"[^>]*>","i");if(regex.test(el.outerHTML)){return RegExp.$1.toLowerCase();}}

+return"";}

+var lt="<";var gt=">";if(includeRootNode&&rootNode.nodeType!=nodeTypes.DOCUMENT_FRAGMENT_NODE){switch(rootNode.nodeType){case nodeTypes.ELEMENT_NODE:var tagName=rootNode.tagName.toLowerCase();xhtml=startNewLine?newLine+indentation:"";xhtml+=lt;var prefix=getNamespace(rootNode);var hasPrefix=!!prefix;if(hasPrefix){xhtml+=prefix+":";}

+xhtml+=tagName;for(i=0,len=rootNode.attributes.length;i<len;i++){var currentAttr=rootNode.attributes[i];if(!currentAttr.specified||currentAttr.nodeValue===null||currentAttr.nodeName.toLowerCase()==="style"||typeof currentAttr.nodeValue!=="string"||currentAttr.nodeName.indexOf("_moz")===0){continue;}

+xhtml+=" "+currentAttr.nodeName.toLowerCase()+"=\"";xhtml+=fixAttributeValue(currentAttr.nodeValue);xhtml+="\"";}

+if(rootNode.style.cssText){var styleValue=getStyleAttributeValue(rootNode);if(styleValue!==""){xhtml+=" style=\""+getStyleAttributeValue(rootNode)+"\"";}}

+if(array_contains(emptyElements,tagName)||(hasPrefix&&!rootNode.hasChildNodes())){xhtml+="/"+gt;}else{xhtml+=gt;var childStartNewLine=!(rootNode.childNodes.length===1&&rootNode.childNodes[0].nodeType===nodeTypes.TEXT_NODE);var childPreformatted=array_contains(preFormattedElements,tagName);for(var i=0,len=rootNode.childNodes.length;i<len;i++){xhtml+=getXhtml(rootNode.childNodes[i],true,indentation+indentationUnit,childStartNewLine,childPreformatted);}

+var endTag=lt+"/"+tagName+gt;xhtml+=childStartNewLine?newLine+indentation+endTag:endTag;}

+return xhtml;case nodeTypes.TEXT_NODE:if(isWhitespace(rootNode)){xhtml="";}else{if(preformatted){xhtml=rootNode.nodeValue;}else{var lines=splitIntoLines(trim(rootNode.nodeValue));var trimmedLines=[];for(var i=0,len=lines.length;i<len;i++){trimmedLines[i]=trim(lines[i]);}

+xhtml=trimmedLines.join(newLine+indentation);}

+if(startNewLine){xhtml=newLine+indentation+xhtml;}}

+return xhtml;case nodeTypes.CDATA_SECTION_NODE:return"<![CDA"+"TA["+rootNode.nodeValue+"]"+"]>"+newLine;case nodeTypes.DOCUMENT_NODE:xhtml="";for(var i=0,len=rootNode.childNodes.length;i<len;i++){xhtml+=getXhtml(rootNode.childNodes[i],true,indentation);}

+return xhtml;default:return"";}}else{xhtml="";for(var i=0,len=rootNode.childNodes.length;i<len;i++){xhtml+=getXhtml(rootNode.childNodes[i],true,indentation+indentationUnit);}

+return xhtml;}}

+function createCommandLineFunctions(){ConsoleAppender.addGlobalCommandLineFunction("$",function(appender,args,returnValue){return document.getElementById(args[0]);});ConsoleAppender.addGlobalCommandLineFunction("dir",function(appender,args,returnValue){var lines=[];for(var i=0,len=args.length;i<len;i++){lines[i]=dir(args[i]);}

+return lines.join(newLine+newLine);});ConsoleAppender.addGlobalCommandLineFunction("dirxml",function(appender,args,returnValue){var lines=[];for(var i=0,len=args.length;i<len;i++){var win=appender.getCommandWindow();lines[i]=getXhtml(args[i]);}

+return lines.join(newLine+newLine);});ConsoleAppender.addGlobalCommandLineFunction("cd",function(appender,args,returnValue){var win,message;if(args.length===0||args[0]===""){win=window;message="Command line set to run in main window";}else{if(args[0].window==args[0]){win=args[0];message="Command line set to run in frame '"+args[0].name+"'";}else{win=window.frames[args[0]];if(win){message="Command line set to run in frame '"+args[0]+"'";}else{returnValue.isError=true;message="Frame '"+args[0]+"' does not exist";win=appender.getCommandWindow();}}}

+appender.setCommandWindow(win);return message;});ConsoleAppender.addGlobalCommandLineFunction("clear",function(appender,args,returnValue){returnValue.appendResult=false;appender.clear();});ConsoleAppender.addGlobalCommandLineFunction("keys",function(appender,args,returnValue){var keys=[];for(var k in args[0]){keys.push(k);}

+return keys;});ConsoleAppender.addGlobalCommandLineFunction("values",function(appender,args,returnValue){var values=[];for(var k in args[0]){try{values.push(args[0][k]);}catch(ex){logLog.warn("values(): Unable to obtain value for key "+k+". Details: "+getExceptionMessage(ex));}}

+return values;});ConsoleAppender.addGlobalCommandLineFunction("expansionDepth",function(appender,args,returnValue){var expansionDepth=parseInt(args[0],10);if(isNaN(expansionDepth)||expansionDepth<0){returnValue.isError=true;return""+args[0]+" is not a valid expansion depth";}else{appender.setCommandLineObjectExpansionDepth(expansionDepth);return"Object expansion depth set to "+expansionDepth;}});}

+function init(){createCommandLineFunctions();}

+init();})();log4javascript.setDocumentReady=function(){pageLoaded=true;log4javascript.dispatchEvent("load",{});};if(window.addEventListener){window.addEventListener("load",log4javascript.setDocumentReady,false);}else if(window.attachEvent){window.attachEvent("onload",log4javascript.setDocumentReady);}else{var oldOnload=window.onload;if(typeof window.onload!="function"){window.onload=log4javascript.setDocumentReady;}else{window.onload=function(evt){if(oldOnload){oldOnload(evt);}

+log4javascript.setDocumentReady();};}}

+window.log4javascript=log4javascript;return log4javascript;})();

diff --git a/planetstack/core/static/log4javascript-1.4.6/log4javascript_uncompressed.js b/planetstack/core/static/log4javascript-1.4.6/log4javascript_uncompressed.js
new file mode 100644
index 0000000..a644e3b
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/log4javascript_uncompressed.js
@@ -0,0 +1,5879 @@
+/**

+ * Copyright 2013 Tim Down.

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+/**

+ * log4javascript

+ *

+ * log4javascript is a logging framework for JavaScript based on log4j

+ * for Java. This file contains all core log4javascript code and is the only

+ * file required to use log4javascript, unless you require support for

+ * document.domain, in which case you will also need console.html, which must be

+ * stored in the same directory as the main log4javascript.js file.

+ *

+ * Author: Tim Down <tim@log4javascript.org>

+ * Version: 1.4.6

+ * Edition: log4javascript

+ * Build date: 19 March 2013

+ * Website: http://log4javascript.org

+ */

+

+/* -------------------------------------------------------------------------- */

+// Array-related stuff

+

+// Next three methods are solely for IE5, which is missing them

+if (!Array.prototype.push) {

+	Array.prototype.push = function() {

+		for (var i = 0, len = arguments.length; i < len; i++){

+			this[this.length] = arguments[i];

+		}

+		return this.length;

+	};

+}

+

+if (!Array.prototype.shift) {

+	Array.prototype.shift = function() {

+		if (this.length > 0) {

+			var firstItem = this[0];

+			for (var i = 0, len = this.length - 1; i < len; i++) {

+				this[i] = this[i + 1];

+			}

+			this.length = this.length - 1;

+			return firstItem;

+		}

+	};

+}

+

+if (!Array.prototype.splice) {

+	Array.prototype.splice = function(startIndex, deleteCount) {

+		var itemsAfterDeleted = this.slice(startIndex + deleteCount);

+		var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);

+		this.length = startIndex;

+		// Copy the arguments into a proper Array object

+		var argumentsArray = [];

+		for (var i = 0, len = arguments.length; i < len; i++) {

+			argumentsArray[i] = arguments[i];

+		}

+		var itemsToAppend = (argumentsArray.length > 2) ?

+			itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;

+		for (i = 0, len = itemsToAppend.length; i < len; i++) {

+			this.push(itemsToAppend[i]);

+		}

+		return itemsDeleted;

+	};

+}

+

+/* -------------------------------------------------------------------------- */

+

+var log4javascript = (function() {

+

+	function isUndefined(obj) {

+		return typeof obj == "undefined";

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// Custom event support

+

+	function EventSupport() {}

+

+	EventSupport.prototype = {

+		eventTypes: [],

+		eventListeners: {},

+		setEventTypes: function(eventTypesParam) {

+			if (eventTypesParam instanceof Array) {

+				this.eventTypes = eventTypesParam;

+				this.eventListeners = {};

+				for (var i = 0, len = this.eventTypes.length; i < len; i++) {

+					this.eventListeners[this.eventTypes[i]] = [];

+				}

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: setEventTypes: eventTypes parameter must be an Array");

+			}

+		},

+

+		addEventListener: function(eventType, listener) {

+			if (typeof listener == "function") {

+				if (!array_contains(this.eventTypes, eventType)) {

+					handleError("log4javascript.EventSupport [" + this + "]: addEventListener: no event called '" + eventType + "'");

+				}

+				this.eventListeners[eventType].push(listener);

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: addEventListener: listener must be a function");

+			}

+		},

+

+		removeEventListener: function(eventType, listener) {

+			if (typeof listener == "function") {

+				if (!array_contains(this.eventTypes, eventType)) {

+					handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: no event called '" + eventType + "'");

+				}

+				array_remove(this.eventListeners[eventType], listener);

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: removeEventListener: listener must be a function");

+			}

+		},

+

+		dispatchEvent: function(eventType, eventArgs) {

+			if (array_contains(this.eventTypes, eventType)) {

+				var listeners = this.eventListeners[eventType];

+				for (var i = 0, len = listeners.length; i < len; i++) {

+					listeners[i](this, eventType, eventArgs);

+				}

+			} else {

+				handleError("log4javascript.EventSupport [" + this + "]: dispatchEvent: no event called '" + eventType + "'");

+			}

+		}

+	};

+

+	/* -------------------------------------------------------------------------- */

+

+	var applicationStartDate = new Date();

+	var uniqueId = "log4javascript_" + applicationStartDate.getTime() + "_" +

+		Math.floor(Math.random() * 100000000);

+	var emptyFunction = function() {};

+	var newLine = "\r\n";

+	var pageLoaded = false;

+

+	// Create main log4javascript object; this will be assigned public properties

+	function Log4JavaScript() {}

+	Log4JavaScript.prototype = new EventSupport();

+

+	log4javascript = new Log4JavaScript();

+	log4javascript.version = "1.4.6";

+	log4javascript.edition = "log4javascript";

+

+	/* -------------------------------------------------------------------------- */

+	// Utility functions

+

+	function toStr(obj) {

+		if (obj && obj.toString) {

+			return obj.toString();

+		} else {

+			return String(obj);

+		}

+	}

+

+	function getExceptionMessage(ex) {

+		if (ex.message) {

+			return ex.message;

+		} else if (ex.description) {

+			return ex.description;

+		} else {

+			return toStr(ex);

+		}

+	}

+

+	// Gets the portion of the URL after the last slash

+	function getUrlFileName(url) {

+		var lastSlashIndex = Math.max(url.lastIndexOf("/"), url.lastIndexOf("\\"));

+		return url.substr(lastSlashIndex + 1);

+	}

+

+	// Returns a nicely formatted representation of an error

+	function getExceptionStringRep(ex) {

+		if (ex) {

+			var exStr = "Exception: " + getExceptionMessage(ex);

+			try {

+				if (ex.lineNumber) {

+					exStr += " on line number " + ex.lineNumber;

+				}

+				if (ex.fileName) {

+					exStr += " in file " + getUrlFileName(ex.fileName);

+				}

+			} catch (localEx) {

+				logLog.warn("Unable to obtain file and line information for error");

+			}

+			if (showStackTraces && ex.stack) {

+				exStr += newLine + "Stack trace:" + newLine + ex.stack;

+			}

+			return exStr;

+		}

+		return null;

+	}

+

+	function bool(obj) {

+		return Boolean(obj);

+	}

+

+	function trim(str) {

+		return str.replace(/^\s+/, "").replace(/\s+$/, "");

+	}

+

+	function splitIntoLines(text) {

+		// Ensure all line breaks are \n only

+		var text2 = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");

+		return text2.split("\n");

+	}

+

+	var urlEncode = (typeof window.encodeURIComponent != "undefined") ?

+		function(str) {

+			return encodeURIComponent(str);

+		}: 

+		function(str) {

+			return escape(str).replace(/\+/g, "%2B").replace(/"/g, "%22").replace(/'/g, "%27").replace(/\//g, "%2F").replace(/=/g, "%3D");

+		};

+

+	var urlDecode = (typeof window.decodeURIComponent != "undefined") ?

+		function(str) {

+			return decodeURIComponent(str);

+		}: 

+		function(str) {

+			return unescape(str).replace(/%2B/g, "+").replace(/%22/g, "\"").replace(/%27/g, "'").replace(/%2F/g, "/").replace(/%3D/g, "=");

+		};

+

+	function array_remove(arr, val) {

+		var index = -1;

+		for (var i = 0, len = arr.length; i < len; i++) {

+			if (arr[i] === val) {

+				index = i;

+				break;

+			}

+		}

+		if (index >= 0) {

+			arr.splice(index, 1);

+			return true;

+		} else {

+			return false;

+		}

+	}

+

+	function array_contains(arr, val) {

+		for(var i = 0, len = arr.length; i < len; i++) {

+			if (arr[i] == val) {

+				return true;

+			}

+		}

+		return false;

+	}

+

+	function extractBooleanFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			return bool(param);

+		}

+	}

+

+	function extractStringFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			return String(param);

+		}

+	}

+

+	function extractIntFromParam(param, defaultValue) {

+		if (isUndefined(param)) {

+			return defaultValue;

+		} else {

+			try {

+				var value = parseInt(param, 10);

+				return isNaN(value) ? defaultValue : value;

+			} catch (ex) {

+				logLog.warn("Invalid int param " + param, ex);

+				return defaultValue;

+			}

+		}

+	}

+

+	function extractFunctionFromParam(param, defaultValue) {

+		if (typeof param == "function") {

+			return param;

+		} else {

+			return defaultValue;

+		}

+	}

+

+	function isError(err) {

+		return (err instanceof Error);

+	}

+

+	if (!Function.prototype.apply){

+		Function.prototype.apply = function(obj, args) {

+			var methodName = "__apply__";

+			if (typeof obj[methodName] != "undefined") {

+				methodName += String(Math.random()).substr(2);

+			}

+			obj[methodName] = this;

+

+			var argsStrings = [];

+			for (var i = 0, len = args.length; i < len; i++) {

+				argsStrings[i] = "args[" + i + "]";

+			}

+			var script = "obj." + methodName + "(" + argsStrings.join(",") + ")";

+			var returnValue = eval(script);

+			delete obj[methodName];

+			return returnValue;

+		};

+	}

+

+	if (!Function.prototype.call){

+		Function.prototype.call = function(obj) {

+			var args = [];

+			for (var i = 1, len = arguments.length; i < len; i++) {

+				args[i - 1] = arguments[i];

+			}

+			return this.apply(obj, args);

+		};

+	}

+

+	function getListenersPropertyName(eventName) {

+		return "__log4javascript_listeners__" + eventName;

+	}

+

+	function addEvent(node, eventName, listener, useCapture, win) {

+		win = win ? win : window;

+		if (node.addEventListener) {

+			node.addEventListener(eventName, listener, useCapture);

+		} else if (node.attachEvent) {

+			node.attachEvent("on" + eventName, listener);

+		} else {

+			var propertyName = getListenersPropertyName(eventName);

+			if (!node[propertyName]) {

+				node[propertyName] = [];

+				// Set event handler

+				node["on" + eventName] = function(evt) {

+					evt = getEvent(evt, win);

+					var listenersPropertyName = getListenersPropertyName(eventName);

+

+					// Clone the array of listeners to leave the original untouched

+					var listeners = this[listenersPropertyName].concat([]);

+					var currentListener;

+

+					// Call each listener in turn

+					while ((currentListener = listeners.shift())) {

+						currentListener.call(this, evt);

+					}

+				};

+			}

+			node[propertyName].push(listener);

+		}

+	}

+

+	function removeEvent(node, eventName, listener, useCapture) {

+		if (node.removeEventListener) {

+			node.removeEventListener(eventName, listener, useCapture);

+		} else if (node.detachEvent) {

+			node.detachEvent("on" + eventName, listener);

+		} else {

+			var propertyName = getListenersPropertyName(eventName);

+			if (node[propertyName]) {

+				array_remove(node[propertyName], listener);

+			}

+		}

+	}

+

+	function getEvent(evt, win) {

+		win = win ? win : window;

+		return evt ? evt : win.event;

+	}

+

+	function stopEventPropagation(evt) {

+		if (evt.stopPropagation) {

+			evt.stopPropagation();

+		} else if (typeof evt.cancelBubble != "undefined") {

+			evt.cancelBubble = true;

+		}

+		evt.returnValue = false;

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// Simple logging for log4javascript itself

+

+	var logLog = {

+		quietMode: false,

+

+		debugMessages: [],

+

+		setQuietMode: function(quietMode) {

+			this.quietMode = bool(quietMode);

+		},

+

+		numberOfErrors: 0,

+

+		alertAllErrors: false,

+

+		setAlertAllErrors: function(alertAllErrors) {

+			this.alertAllErrors = alertAllErrors;

+		},

+

+		debug: function(message) {

+			this.debugMessages.push(message);

+		},

+

+		displayDebug: function() {

+			alert(this.debugMessages.join(newLine));

+		},

+

+		warn: function(message, exception) {

+		},

+

+		error: function(message, exception) {

+			if (++this.numberOfErrors == 1 || this.alertAllErrors) {

+				if (!this.quietMode) {

+					var alertMessage = "log4javascript error: " + message;

+					if (exception) {

+						alertMessage += newLine + newLine + "Original error: " + getExceptionStringRep(exception);

+					}

+					alert(alertMessage);

+				}

+			}

+		}

+	};

+	log4javascript.logLog = logLog;

+

+	log4javascript.setEventTypes(["load", "error"]);

+

+	function handleError(message, exception) {

+		logLog.error(message, exception);

+		log4javascript.dispatchEvent("error", { "message": message, "exception": exception });

+	}

+

+	log4javascript.handleError = handleError;

+

+	/* ---------------------------------------------------------------------- */

+

+	var enabled = !((typeof log4javascript_disabled != "undefined") &&

+					log4javascript_disabled);

+

+	log4javascript.setEnabled = function(enable) {

+		enabled = bool(enable);

+	};

+

+	log4javascript.isEnabled = function() {

+		return enabled;

+	};

+

+	var useTimeStampsInMilliseconds = true;

+

+	log4javascript.setTimeStampsInMilliseconds = function(timeStampsInMilliseconds) {

+		useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);

+	};

+

+	log4javascript.isTimeStampsInMilliseconds = function() {

+		return useTimeStampsInMilliseconds;

+	};

+	

+

+	// This evaluates the given expression in the current scope, thus allowing

+	// scripts to access private variables. Particularly useful for testing

+	log4javascript.evalInScope = function(expr) {

+		return eval(expr);

+	};

+

+	var showStackTraces = false;

+

+	log4javascript.setShowStackTraces = function(show) {

+		showStackTraces = bool(show);

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Levels

+

+	var Level = function(level, name) {

+		this.level = level;

+		this.name = name;

+	};

+

+	Level.prototype = {

+		toString: function() {

+			return this.name;

+		},

+		equals: function(level) {

+			return this.level == level.level;

+		},

+		isGreaterOrEqual: function(level) {

+			return this.level >= level.level;

+		}

+	};

+

+	Level.ALL = new Level(Number.MIN_VALUE, "ALL");

+	Level.TRACE = new Level(10000, "TRACE");

+	Level.DEBUG = new Level(20000, "DEBUG");

+	Level.INFO = new Level(30000, "INFO");

+	Level.WARN = new Level(40000, "WARN");

+	Level.ERROR = new Level(50000, "ERROR");

+	Level.FATAL = new Level(60000, "FATAL");

+	Level.OFF = new Level(Number.MAX_VALUE, "OFF");

+

+	log4javascript.Level = Level;

+

+	/* ---------------------------------------------------------------------- */

+	// Timers

+

+	function Timer(name, level) {

+		this.name = name;

+		this.level = isUndefined(level) ? Level.INFO : level;

+		this.start = new Date();

+	}

+

+	Timer.prototype.getElapsedTime = function() {

+		return new Date().getTime() - this.start.getTime();

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Loggers

+

+	var anonymousLoggerName = "[anonymous]";

+	var defaultLoggerName = "[default]";

+	var nullLoggerName = "[null]";

+	var rootLoggerName = "root";

+

+	function Logger(name) {

+		this.name = name;

+		this.parent = null;

+		this.children = [];

+

+		var appenders = [];

+		var loggerLevel = null;

+		var isRoot = (this.name === rootLoggerName);

+		var isNull = (this.name === nullLoggerName);

+

+		var appenderCache = null;

+		var appenderCacheInvalidated = false;

+		

+		this.addChild = function(childLogger) {

+			this.children.push(childLogger);

+			childLogger.parent = this;

+			childLogger.invalidateAppenderCache();

+		};

+

+		// Additivity

+		var additive = true;

+		this.getAdditivity = function() {

+			return additive;

+		};

+

+		this.setAdditivity = function(additivity) {

+			var valueChanged = (additive != additivity);

+			additive = additivity;

+			if (valueChanged) {

+				this.invalidateAppenderCache();

+			}

+		};

+

+		// Create methods that use the appenders variable in this scope

+		this.addAppender = function(appender) {

+			if (isNull) {

+				handleError("Logger.addAppender: you may not add an appender to the null logger");

+			} else {

+				if (appender instanceof log4javascript.Appender) {

+					if (!array_contains(appenders, appender)) {

+						appenders.push(appender);

+						appender.setAddedToLogger(this);

+						this.invalidateAppenderCache();

+					}

+				} else {

+					handleError("Logger.addAppender: appender supplied ('" +

+						toStr(appender) + "') is not a subclass of Appender");

+				}

+			}

+		};

+

+		this.removeAppender = function(appender) {

+			array_remove(appenders, appender);

+			appender.setRemovedFromLogger(this);

+			this.invalidateAppenderCache();

+		};

+

+		this.removeAllAppenders = function() {

+			var appenderCount = appenders.length;

+			if (appenderCount > 0) {

+				for (var i = 0; i < appenderCount; i++) {

+					appenders[i].setRemovedFromLogger(this);

+				}

+				appenders.length = 0;

+				this.invalidateAppenderCache();

+			}

+		};

+

+		this.getEffectiveAppenders = function() {

+			if (appenderCache === null || appenderCacheInvalidated) {

+				// Build appender cache

+				var parentEffectiveAppenders = (isRoot || !this.getAdditivity()) ?

+					[] : this.parent.getEffectiveAppenders();

+				appenderCache = parentEffectiveAppenders.concat(appenders);

+				appenderCacheInvalidated = false;

+			}

+			return appenderCache;

+		};

+		

+		this.invalidateAppenderCache = function() {

+			appenderCacheInvalidated = true;

+			for (var i = 0, len = this.children.length; i < len; i++) {

+				this.children[i].invalidateAppenderCache();

+			}

+		};

+

+		this.log = function(level, params) {

+			if (enabled && level.isGreaterOrEqual(this.getEffectiveLevel())) {

+				// Check whether last param is an exception

+				var exception;

+				var finalParamIndex = params.length - 1;

+				var lastParam = params[finalParamIndex];

+				if (params.length > 1 && isError(lastParam)) {

+					exception = lastParam;

+					finalParamIndex--;

+				}

+

+				// Construct genuine array for the params

+				var messages = [];

+				for (var i = 0; i <= finalParamIndex; i++) {

+					messages[i] = params[i];

+				}

+

+				var loggingEvent = new LoggingEvent(

+					this, new Date(), level, messages, exception);

+

+				this.callAppenders(loggingEvent);

+			}

+		};

+

+		this.callAppenders = function(loggingEvent) {

+			var effectiveAppenders = this.getEffectiveAppenders();

+			for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+				effectiveAppenders[i].doAppend(loggingEvent);

+			}

+		};

+

+		this.setLevel = function(level) {

+			// Having a level of null on the root logger would be very bad.

+			if (isRoot && level === null) {

+				handleError("Logger.setLevel: you cannot set the level of the root logger to null");

+			} else if (level instanceof Level) {

+				loggerLevel = level;

+			} else {

+				handleError("Logger.setLevel: level supplied to logger " +

+					this.name + " is not an instance of log4javascript.Level");

+			}

+		};

+

+		this.getLevel = function() {

+			return loggerLevel;

+		};

+

+		this.getEffectiveLevel = function() {

+			for (var logger = this; logger !== null; logger = logger.parent) {

+				var level = logger.getLevel();

+				if (level !== null) {

+					return level;

+				}

+			}

+		};

+

+		this.group = function(name, initiallyExpanded) {

+			if (enabled) {

+				var effectiveAppenders = this.getEffectiveAppenders();

+				for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+					effectiveAppenders[i].group(name, initiallyExpanded);

+				}

+			}

+		};

+

+		this.groupEnd = function() {

+			if (enabled) {

+				var effectiveAppenders = this.getEffectiveAppenders();

+				for (var i = 0, len = effectiveAppenders.length; i < len; i++) {

+					effectiveAppenders[i].groupEnd();

+				}

+			}

+		};

+

+		var timers = {};

+

+		this.time = function(name, level) {

+			if (enabled) {

+				if (isUndefined(name)) {

+					handleError("Logger.time: a name for the timer must be supplied");

+				} else if (level && !(level instanceof Level)) {

+					handleError("Logger.time: level supplied to timer " +

+						name + " is not an instance of log4javascript.Level");

+				} else {

+					timers[name] = new Timer(name, level);

+				}

+			}

+		};

+

+		this.timeEnd = function(name) {

+			if (enabled) {

+				if (isUndefined(name)) {

+					handleError("Logger.timeEnd: a name for the timer must be supplied");

+				} else if (timers[name]) {

+					var timer = timers[name];

+					var milliseconds = timer.getElapsedTime();

+					this.log(timer.level, ["Timer " + toStr(name) + " completed in " + milliseconds + "ms"]);

+					delete timers[name];

+				} else {

+					logLog.warn("Logger.timeEnd: no timer found with name " + name);

+				}

+			}

+		};

+

+		this.assert = function(expr) {

+			if (enabled && !expr) {

+				var args = [];

+				for (var i = 1, len = arguments.length; i < len; i++) {

+					args.push(arguments[i]);

+				}

+				args = (args.length > 0) ? args : ["Assertion Failure"];

+				args.push(newLine);

+				args.push(expr);

+				this.log(Level.ERROR, args);

+			}

+		};

+

+		this.toString = function() {

+			return "Logger[" + this.name + "]";

+		};

+	}

+

+	Logger.prototype = {

+		trace: function() {

+			this.log(Level.TRACE, arguments);

+		},

+

+		debug: function() {

+			this.log(Level.DEBUG, arguments);

+		},

+

+		info: function() {

+			this.log(Level.INFO, arguments);

+		},

+

+		warn: function() {

+			this.log(Level.WARN, arguments);

+		},

+

+		error: function() {

+			this.log(Level.ERROR, arguments);

+		},

+

+		fatal: function() {

+			this.log(Level.FATAL, arguments);

+		},

+

+		isEnabledFor: function(level) {

+			return level.isGreaterOrEqual(this.getEffectiveLevel());

+		},

+

+		isTraceEnabled: function() {

+			return this.isEnabledFor(Level.TRACE);

+		},

+

+		isDebugEnabled: function() {

+			return this.isEnabledFor(Level.DEBUG);

+		},

+

+		isInfoEnabled: function() {

+			return this.isEnabledFor(Level.INFO);

+		},

+

+		isWarnEnabled: function() {

+			return this.isEnabledFor(Level.WARN);

+		},

+

+		isErrorEnabled: function() {

+			return this.isEnabledFor(Level.ERROR);

+		},

+

+		isFatalEnabled: function() {

+			return this.isEnabledFor(Level.FATAL);

+		}

+	};

+

+	Logger.prototype.trace.isEntryPoint = true;

+	Logger.prototype.debug.isEntryPoint = true;

+	Logger.prototype.info.isEntryPoint = true;

+	Logger.prototype.warn.isEntryPoint = true;

+	Logger.prototype.error.isEntryPoint = true;

+	Logger.prototype.fatal.isEntryPoint = true;

+

+	/* ---------------------------------------------------------------------- */

+	// Logger access methods

+

+	// Hashtable of loggers keyed by logger name

+	var loggers = {};

+	var loggerNames = [];

+

+	var ROOT_LOGGER_DEFAULT_LEVEL = Level.DEBUG;

+	var rootLogger = new Logger(rootLoggerName);

+	rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);

+

+	log4javascript.getRootLogger = function() {

+		return rootLogger;

+	};

+

+	log4javascript.getLogger = function(loggerName) {

+		// Use default logger if loggerName is not specified or invalid

+		if (!(typeof loggerName == "string")) {

+			loggerName = anonymousLoggerName;

+			logLog.warn("log4javascript.getLogger: non-string logger name "	+

+				toStr(loggerName) + " supplied, returning anonymous logger");

+		}

+

+		// Do not allow retrieval of the root logger by name

+		if (loggerName == rootLoggerName) {

+			handleError("log4javascript.getLogger: root logger may not be obtained by name");

+		}

+

+		// Create the logger for this name if it doesn't already exist

+		if (!loggers[loggerName]) {

+			var logger = new Logger(loggerName);

+			loggers[loggerName] = logger;

+			loggerNames.push(loggerName);

+

+			// Set up parent logger, if it doesn't exist

+			var lastDotIndex = loggerName.lastIndexOf(".");

+			var parentLogger;

+			if (lastDotIndex > -1) {

+				var parentLoggerName = loggerName.substring(0, lastDotIndex);

+				parentLogger = log4javascript.getLogger(parentLoggerName); // Recursively sets up grandparents etc.

+			} else {

+				parentLogger = rootLogger;

+			}

+			parentLogger.addChild(logger);

+		}

+		return loggers[loggerName];

+	};

+

+	var defaultLogger = null;

+	log4javascript.getDefaultLogger = function() {

+		if (!defaultLogger) {

+			defaultLogger = log4javascript.getLogger(defaultLoggerName);

+			var a = new log4javascript.PopUpAppender();

+			defaultLogger.addAppender(a);

+		}

+		return defaultLogger;

+	};

+

+	var nullLogger = null;

+	log4javascript.getNullLogger = function() {

+		if (!nullLogger) {

+			nullLogger = new Logger(nullLoggerName);

+			nullLogger.setLevel(Level.OFF);

+		}

+		return nullLogger;

+	};

+

+	// Destroys all loggers

+	log4javascript.resetConfiguration = function() {

+		rootLogger.setLevel(ROOT_LOGGER_DEFAULT_LEVEL);

+		loggers = {};

+	};

+

+	/* ---------------------------------------------------------------------- */

+	// Logging events

+

+	var LoggingEvent = function(logger, timeStamp, level, messages,

+			exception) {

+		this.logger = logger;

+		this.timeStamp = timeStamp;

+		this.timeStampInMilliseconds = timeStamp.getTime();

+		this.timeStampInSeconds = Math.floor(this.timeStampInMilliseconds / 1000);

+		this.milliseconds = this.timeStamp.getMilliseconds();

+		this.level = level;

+		this.messages = messages;

+		this.exception = exception;

+	};

+

+	LoggingEvent.prototype = {

+		getThrowableStrRep: function() {

+			return this.exception ?

+				getExceptionStringRep(this.exception) : "";

+		},

+		getCombinedMessages: function() {

+			return (this.messages.length == 1) ? this.messages[0] :

+				   this.messages.join(newLine);

+		},

+		toString: function() {

+			return "LoggingEvent[" + this.level + "]";

+		}

+	};

+

+	log4javascript.LoggingEvent = LoggingEvent;

+

+	/* ---------------------------------------------------------------------- */

+	// Layout prototype

+

+	var Layout = function() {

+	};

+

+	Layout.prototype = {

+		defaults: {

+			loggerKey: "logger",

+			timeStampKey: "timestamp",

+			millisecondsKey: "milliseconds",

+			levelKey: "level",

+			messageKey: "message",

+			exceptionKey: "exception",

+			urlKey: "url"

+		},

+		loggerKey: "logger",

+		timeStampKey: "timestamp",

+		millisecondsKey: "milliseconds",

+		levelKey: "level",

+		messageKey: "message",

+		exceptionKey: "exception",

+		urlKey: "url",

+		batchHeader: "",

+		batchFooter: "",

+		batchSeparator: "",

+		returnsPostData: false,

+		overrideTimeStampsSetting: false,

+		useTimeStampsInMilliseconds: null,

+

+		format: function() {

+			handleError("Layout.format: layout supplied has no format() method");

+		},

+

+		ignoresThrowable: function() {

+			handleError("Layout.ignoresThrowable: layout supplied has no ignoresThrowable() method");

+		},

+

+		getContentType: function() {

+			return "text/plain";

+		},

+

+		allowBatching: function() {

+			return true;

+		},

+

+		setTimeStampsInMilliseconds: function(timeStampsInMilliseconds) {

+			this.overrideTimeStampsSetting = true;

+			this.useTimeStampsInMilliseconds = bool(timeStampsInMilliseconds);

+		},

+

+		isTimeStampsInMilliseconds: function() {

+			return this.overrideTimeStampsSetting ?

+				this.useTimeStampsInMilliseconds : useTimeStampsInMilliseconds;

+		},

+

+		getTimeStampValue: function(loggingEvent) {

+			return this.isTimeStampsInMilliseconds() ?

+				loggingEvent.timeStampInMilliseconds : loggingEvent.timeStampInSeconds;

+		},

+

+		getDataValues: function(loggingEvent, combineMessages) {

+			var dataValues = [

+				[this.loggerKey, loggingEvent.logger.name],

+				[this.timeStampKey, this.getTimeStampValue(loggingEvent)],

+				[this.levelKey, loggingEvent.level.name],

+				[this.urlKey, window.location.href],

+				[this.messageKey, combineMessages ? loggingEvent.getCombinedMessages() : loggingEvent.messages]

+			];

+			if (!this.isTimeStampsInMilliseconds()) {

+				dataValues.push([this.millisecondsKey, loggingEvent.milliseconds]);

+			}

+			if (loggingEvent.exception) {

+				dataValues.push([this.exceptionKey, getExceptionStringRep(loggingEvent.exception)]);

+			}

+			if (this.hasCustomFields()) {

+				for (var i = 0, len = this.customFields.length; i < len; i++) {

+					var val = this.customFields[i].value;

+

+					// Check if the value is a function. If so, execute it, passing it the

+					// current layout and the logging event

+					if (typeof val === "function") {

+						val = val(this, loggingEvent);

+					}

+					dataValues.push([this.customFields[i].name, val]);

+				}

+			}

+			return dataValues;

+		},

+

+		setKeys: function(loggerKey, timeStampKey, levelKey, messageKey,

+				exceptionKey, urlKey, millisecondsKey) {

+			this.loggerKey = extractStringFromParam(loggerKey, this.defaults.loggerKey);

+			this.timeStampKey = extractStringFromParam(timeStampKey, this.defaults.timeStampKey);

+			this.levelKey = extractStringFromParam(levelKey, this.defaults.levelKey);

+			this.messageKey = extractStringFromParam(messageKey, this.defaults.messageKey);

+			this.exceptionKey = extractStringFromParam(exceptionKey, this.defaults.exceptionKey);

+			this.urlKey = extractStringFromParam(urlKey, this.defaults.urlKey);

+			this.millisecondsKey = extractStringFromParam(millisecondsKey, this.defaults.millisecondsKey);

+		},

+

+		setCustomField: function(name, value) {

+			var fieldUpdated = false;

+			for (var i = 0, len = this.customFields.length; i < len; i++) {

+				if (this.customFields[i].name === name) {

+					this.customFields[i].value = value;

+					fieldUpdated = true;

+				}

+			}

+			if (!fieldUpdated) {

+				this.customFields.push({"name": name, "value": value});

+			}

+		},

+

+		hasCustomFields: function() {

+			return (this.customFields.length > 0);

+		},

+

+		toString: function() {

+			handleError("Layout.toString: all layouts must override this method");

+		}

+	};

+

+	log4javascript.Layout = Layout;

+

+	/* ---------------------------------------------------------------------- */

+	// Appender prototype

+

+	var Appender = function() {};

+

+	Appender.prototype = new EventSupport();

+

+	Appender.prototype.layout = new PatternLayout();

+	Appender.prototype.threshold = Level.ALL;

+	Appender.prototype.loggers = [];

+

+	// Performs threshold checks before delegating actual logging to the

+	// subclass's specific append method.

+	Appender.prototype.doAppend = function(loggingEvent) {

+		if (enabled && loggingEvent.level.level >= this.threshold.level) {

+			this.append(loggingEvent);

+		}

+	};

+

+	Appender.prototype.append = function(loggingEvent) {};

+

+	Appender.prototype.setLayout = function(layout) {

+		if (layout instanceof Layout) {

+			this.layout = layout;

+		} else {

+			handleError("Appender.setLayout: layout supplied to " +

+				this.toString() + " is not a subclass of Layout");

+		}

+	};

+

+	Appender.prototype.getLayout = function() {

+		return this.layout;

+	};

+

+	Appender.prototype.setThreshold = function(threshold) {

+		if (threshold instanceof Level) {

+			this.threshold = threshold;

+		} else {

+			handleError("Appender.setThreshold: threshold supplied to " +

+				this.toString() + " is not a subclass of Level");

+		}

+	};

+

+	Appender.prototype.getThreshold = function() {

+		return this.threshold;

+	};

+

+	Appender.prototype.setAddedToLogger = function(logger) {

+		this.loggers.push(logger);

+	};

+

+	Appender.prototype.setRemovedFromLogger = function(logger) {

+		array_remove(this.loggers, logger);

+	};

+

+	Appender.prototype.group = emptyFunction;

+	Appender.prototype.groupEnd = emptyFunction;

+

+	Appender.prototype.toString = function() {

+		handleError("Appender.toString: all appenders must override this method");

+	};

+

+	log4javascript.Appender = Appender;

+

+	/* ---------------------------------------------------------------------- */

+	// SimpleLayout 

+

+	function SimpleLayout() {

+		this.customFields = [];

+	}

+

+	SimpleLayout.prototype = new Layout();

+

+	SimpleLayout.prototype.format = function(loggingEvent) {

+		return loggingEvent.level.name + " - " + loggingEvent.getCombinedMessages();

+	};

+

+	SimpleLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	SimpleLayout.prototype.toString = function() {

+	    return "SimpleLayout";

+	};

+

+	log4javascript.SimpleLayout = SimpleLayout;

+	/* ----------------------------------------------------------------------- */

+	// NullLayout 

+

+	function NullLayout() {

+		this.customFields = [];

+	}

+

+	NullLayout.prototype = new Layout();

+

+	NullLayout.prototype.format = function(loggingEvent) {

+		return loggingEvent.messages;

+	};

+

+	NullLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	NullLayout.prototype.toString = function() {

+	    return "NullLayout";

+	};

+

+	log4javascript.NullLayout = NullLayout;

+/* ---------------------------------------------------------------------- */

+	// XmlLayout

+

+	function XmlLayout(combineMessages) {

+		this.combineMessages = extractBooleanFromParam(combineMessages, true);

+		this.customFields = [];

+	}

+

+	XmlLayout.prototype = new Layout();

+

+	XmlLayout.prototype.isCombinedMessages = function() {

+		return this.combineMessages;

+	};

+

+	XmlLayout.prototype.getContentType = function() {

+		return "text/xml";

+	};

+

+	XmlLayout.prototype.escapeCdata = function(str) {

+		return str.replace(/\]\]>/, "]]>]]&gt;<![CDATA[");

+	};

+

+	XmlLayout.prototype.format = function(loggingEvent) {

+		var layout = this;

+		var i, len;

+		function formatMessage(message) {

+			message = (typeof message === "string") ? message : toStr(message);

+			return "<log4javascript:message><![CDATA[" +

+				layout.escapeCdata(message) + "]]></log4javascript:message>";

+		}

+

+		var str = "<log4javascript:event logger=\"" + loggingEvent.logger.name +

+			"\" timestamp=\"" + this.getTimeStampValue(loggingEvent) + "\"";

+		if (!this.isTimeStampsInMilliseconds()) {

+			str += " milliseconds=\"" + loggingEvent.milliseconds + "\"";

+		}

+		str += " level=\"" + loggingEvent.level.name + "\">" + newLine;

+		if (this.combineMessages) {

+			str += formatMessage(loggingEvent.getCombinedMessages());

+		} else {

+			str += "<log4javascript:messages>" + newLine;

+			for (i = 0, len = loggingEvent.messages.length; i < len; i++) {

+				str += formatMessage(loggingEvent.messages[i]) + newLine;

+			}

+			str += "</log4javascript:messages>" + newLine;

+		}

+		if (this.hasCustomFields()) {

+			for (i = 0, len = this.customFields.length; i < len; i++) {

+				str += "<log4javascript:customfield name=\"" +

+					this.customFields[i].name + "\"><![CDATA[" +

+					this.customFields[i].value.toString() +

+					"]]></log4javascript:customfield>" + newLine;

+			}

+		}

+		if (loggingEvent.exception) {

+			str += "<log4javascript:exception><![CDATA[" +

+				getExceptionStringRep(loggingEvent.exception) +

+				"]]></log4javascript:exception>" + newLine;

+		}

+		str += "</log4javascript:event>" + newLine + newLine;

+		return str;

+	};

+

+	XmlLayout.prototype.ignoresThrowable = function() {

+	    return false;

+	};

+

+	XmlLayout.prototype.toString = function() {

+	    return "XmlLayout";

+	};

+

+	log4javascript.XmlLayout = XmlLayout;

+	/* ---------------------------------------------------------------------- */

+	// JsonLayout related

+

+	function escapeNewLines(str) {

+		return str.replace(/\r\n|\r|\n/g, "\\r\\n");

+	}

+

+	function JsonLayout(readable, combineMessages) {

+		this.readable = extractBooleanFromParam(readable, false);

+		this.combineMessages = extractBooleanFromParam(combineMessages, true);

+		this.batchHeader = this.readable ? "[" + newLine : "[";

+		this.batchFooter = this.readable ? "]" + newLine : "]";

+		this.batchSeparator = this.readable ? "," + newLine : ",";

+		this.setKeys();

+		this.colon = this.readable ? ": " : ":";

+		this.tab = this.readable ? "\t" : "";

+		this.lineBreak = this.readable ? newLine : "";

+		this.customFields = [];

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// JsonLayout

+

+	JsonLayout.prototype = new Layout();

+

+	JsonLayout.prototype.isReadable = function() {

+		return this.readable;

+	};

+

+	JsonLayout.prototype.isCombinedMessages = function() {

+		return this.combineMessages;

+	};

+

+    JsonLayout.prototype.format = function(loggingEvent) {

+        var layout = this;

+        var dataValues = this.getDataValues(loggingEvent, this.combineMessages);

+        var str = "{" + this.lineBreak;

+        var i, len;

+

+        function formatValue(val, prefix, expand) {

+            // Check the type of the data value to decide whether quotation marks

+            // or expansion are required

+            var formattedValue;

+            var valType = typeof val;

+            if (val instanceof Date) {

+                formattedValue = String(val.getTime());

+            } else if (expand && (val instanceof Array)) {

+                formattedValue = "[" + layout.lineBreak;

+                for (var i = 0, len = val.length; i < len; i++) {

+                    var childPrefix = prefix + layout.tab;

+                    formattedValue += childPrefix + formatValue(val[i], childPrefix, false);

+                    if (i < val.length - 1) {

+                        formattedValue += ",";

+                    }

+                    formattedValue += layout.lineBreak;

+                }

+                formattedValue += prefix + "]";

+            } else if (valType !== "number" && valType !== "boolean") {

+                formattedValue = "\"" + escapeNewLines(toStr(val).replace(/\"/g, "\\\"")) + "\"";

+            } else {

+                formattedValue = val;

+            }

+            return formattedValue;

+        }

+

+        for (i = 0, len = dataValues.length - 1; i <= len; i++) {

+            str += this.tab + "\"" + dataValues[i][0] + "\"" + this.colon + formatValue(dataValues[i][1], this.tab, true);

+            if (i < len) {

+                str += ",";

+            }

+            str += this.lineBreak;

+        }

+

+        str += "}" + this.lineBreak;

+        return str;

+    };

+

+	JsonLayout.prototype.ignoresThrowable = function() {

+	    return false;

+	};

+

+	JsonLayout.prototype.toString = function() {

+	    return "JsonLayout";

+	};

+

+	JsonLayout.prototype.getContentType = function() {

+		return "application/json";

+	};

+

+	log4javascript.JsonLayout = JsonLayout;

+	/* ---------------------------------------------------------------------- */

+	// HttpPostDataLayout

+

+	function HttpPostDataLayout() {

+		this.setKeys();

+		this.customFields = [];

+		this.returnsPostData = true;

+	}

+

+	HttpPostDataLayout.prototype = new Layout();

+

+	// Disable batching

+	HttpPostDataLayout.prototype.allowBatching = function() {

+		return false;

+	};

+

+	HttpPostDataLayout.prototype.format = function(loggingEvent) {

+		var dataValues = this.getDataValues(loggingEvent);

+		var queryBits = [];

+		for (var i = 0, len = dataValues.length; i < len; i++) {

+			var val = (dataValues[i][1] instanceof Date) ?

+				String(dataValues[i][1].getTime()) : dataValues[i][1];

+			queryBits.push(urlEncode(dataValues[i][0]) + "=" + urlEncode(val));

+		}

+		return queryBits.join("&");

+	};

+

+	HttpPostDataLayout.prototype.ignoresThrowable = function(loggingEvent) {

+	    return false;

+	};

+

+	HttpPostDataLayout.prototype.toString = function() {

+	    return "HttpPostDataLayout";

+	};

+

+	log4javascript.HttpPostDataLayout = HttpPostDataLayout;

+	/* ---------------------------------------------------------------------- */

+	// formatObjectExpansion

+

+	function formatObjectExpansion(obj, depth, indentation) {

+		var objectsExpanded = [];

+

+		function doFormat(obj, depth, indentation) {

+			var i, j, len, childDepth, childIndentation, childLines, expansion,

+				childExpansion;

+

+			if (!indentation) {

+				indentation = "";

+			}

+

+			function formatString(text) {

+				var lines = splitIntoLines(text);

+				for (var j = 1, jLen = lines.length; j < jLen; j++) {

+					lines[j] = indentation + lines[j];

+				}

+				return lines.join(newLine);

+			}

+

+			if (obj === null) {

+				return "null";

+			} else if (typeof obj == "undefined") {

+				return "undefined";

+			} else if (typeof obj == "string") {

+				return formatString(obj);

+			} else if (typeof obj == "object" && array_contains(objectsExpanded, obj)) {

+				try {

+					expansion = toStr(obj);

+				} catch (ex) {

+					expansion = "Error formatting property. Details: " + getExceptionStringRep(ex);

+				}

+				return expansion + " [already expanded]";

+			} else if ((obj instanceof Array) && depth > 0) {

+				objectsExpanded.push(obj);

+				expansion = "[" + newLine;

+				childDepth = depth - 1;

+				childIndentation = indentation + "  ";

+				childLines = [];

+				for (i = 0, len = obj.length; i < len; i++) {

+					try {

+						childExpansion = doFormat(obj[i], childDepth, childIndentation);

+						childLines.push(childIndentation + childExpansion);

+					} catch (ex) {

+						childLines.push(childIndentation + "Error formatting array member. Details: " +

+							getExceptionStringRep(ex) + "");

+					}

+				}

+				expansion += childLines.join("," + newLine) + newLine + indentation + "]";

+				return expansion;

+            } else if (Object.prototype.toString.call(obj) == "[object Date]") {

+                return obj.toString();

+			} else if (typeof obj == "object" && depth > 0) {

+				objectsExpanded.push(obj);

+				expansion = "{" + newLine;

+				childDepth = depth - 1;

+				childIndentation = indentation + "  ";

+				childLines = [];

+				for (i in obj) {

+					try {

+						childExpansion = doFormat(obj[i], childDepth, childIndentation);

+						childLines.push(childIndentation + i + ": " + childExpansion);

+					} catch (ex) {

+						childLines.push(childIndentation + i + ": Error formatting property. Details: " +

+							getExceptionStringRep(ex));

+					}

+				}

+				expansion += childLines.join("," + newLine) + newLine + indentation + "}";

+				return expansion;

+			} else {

+				return formatString(toStr(obj));

+			}

+		}

+		return doFormat(obj, depth, indentation);

+	}

+	/* ---------------------------------------------------------------------- */

+	// Date-related stuff

+

+	var SimpleDateFormat;

+

+	(function() {

+		var regex = /('[^']*')|(G+|y+|M+|w+|W+|D+|d+|F+|E+|a+|H+|k+|K+|h+|m+|s+|S+|Z+)|([a-zA-Z]+)|([^a-zA-Z']+)/;

+		var monthNames = ["January", "February", "March", "April", "May", "June",

+			"July", "August", "September", "October", "November", "December"];

+		var dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];

+		var TEXT2 = 0, TEXT3 = 1, NUMBER = 2, YEAR = 3, MONTH = 4, TIMEZONE = 5;

+		var types = {

+			G : TEXT2,

+			y : YEAR,

+			M : MONTH,

+			w : NUMBER,

+			W : NUMBER,

+			D : NUMBER,

+			d : NUMBER,

+			F : NUMBER,

+			E : TEXT3,

+			a : TEXT2,

+			H : NUMBER,

+			k : NUMBER,

+			K : NUMBER,

+			h : NUMBER,

+			m : NUMBER,

+			s : NUMBER,

+			S : NUMBER,

+			Z : TIMEZONE

+		};

+		var ONE_DAY = 24 * 60 * 60 * 1000;

+		var ONE_WEEK = 7 * ONE_DAY;

+		var DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK = 1;

+

+		var newDateAtMidnight = function(year, month, day) {

+			var d = new Date(year, month, day, 0, 0, 0);

+			d.setMilliseconds(0);

+			return d;

+		};

+

+		Date.prototype.getDifference = function(date) {

+			return this.getTime() - date.getTime();

+		};

+

+		Date.prototype.isBefore = function(d) {

+			return this.getTime() < d.getTime();

+		};

+

+		Date.prototype.getUTCTime = function() {

+			return Date.UTC(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours(), this.getMinutes(),

+					this.getSeconds(), this.getMilliseconds());

+		};

+

+		Date.prototype.getTimeSince = function(d) {

+			return this.getUTCTime() - d.getUTCTime();

+		};

+

+		Date.prototype.getPreviousSunday = function() {

+			// Using midday avoids any possibility of DST messing things up

+			var midday = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 12, 0, 0);

+			var previousSunday = new Date(midday.getTime() - this.getDay() * ONE_DAY);

+			return newDateAtMidnight(previousSunday.getFullYear(), previousSunday.getMonth(),

+					previousSunday.getDate());

+		};

+

+		Date.prototype.getWeekInYear = function(minimalDaysInFirstWeek) {

+			if (isUndefined(this.minimalDaysInFirstWeek)) {

+				minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;

+			}

+			var previousSunday = this.getPreviousSunday();

+			var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);

+			var numberOfSundays = previousSunday.isBefore(startOfYear) ?

+				0 : 1 + Math.floor(previousSunday.getTimeSince(startOfYear) / ONE_WEEK);

+			var numberOfDaysInFirstWeek =  7 - startOfYear.getDay();

+			var weekInYear = numberOfSundays;

+			if (numberOfDaysInFirstWeek < minimalDaysInFirstWeek) {

+				weekInYear--;

+			}

+			return weekInYear;

+		};

+

+		Date.prototype.getWeekInMonth = function(minimalDaysInFirstWeek) {

+			if (isUndefined(this.minimalDaysInFirstWeek)) {

+				minimalDaysInFirstWeek = DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK;

+			}

+			var previousSunday = this.getPreviousSunday();

+			var startOfMonth = newDateAtMidnight(this.getFullYear(), this.getMonth(), 1);

+			var numberOfSundays = previousSunday.isBefore(startOfMonth) ?

+				0 : 1 + Math.floor(previousSunday.getTimeSince(startOfMonth) / ONE_WEEK);

+			var numberOfDaysInFirstWeek =  7 - startOfMonth.getDay();

+			var weekInMonth = numberOfSundays;

+			if (numberOfDaysInFirstWeek >= minimalDaysInFirstWeek) {

+				weekInMonth++;

+			}

+			return weekInMonth;

+		};

+

+		Date.prototype.getDayInYear = function() {

+			var startOfYear = newDateAtMidnight(this.getFullYear(), 0, 1);

+			return 1 + Math.floor(this.getTimeSince(startOfYear) / ONE_DAY);

+		};

+

+		/* ------------------------------------------------------------------ */

+

+		SimpleDateFormat = function(formatString) {

+			this.formatString = formatString;

+		};

+

+		/**

+		 * Sets the minimum number of days in a week in order for that week to

+		 * be considered as belonging to a particular month or year

+		 */

+		SimpleDateFormat.prototype.setMinimalDaysInFirstWeek = function(days) {

+			this.minimalDaysInFirstWeek = days;

+		};

+

+		SimpleDateFormat.prototype.getMinimalDaysInFirstWeek = function() {

+			return isUndefined(this.minimalDaysInFirstWeek)	?

+				DEFAULT_MINIMAL_DAYS_IN_FIRST_WEEK : this.minimalDaysInFirstWeek;

+		};

+

+		var padWithZeroes = function(str, len) {

+			while (str.length < len) {

+				str = "0" + str;

+			}

+			return str;

+		};

+

+		var formatText = function(data, numberOfLetters, minLength) {

+			return (numberOfLetters >= 4) ? data : data.substr(0, Math.max(minLength, numberOfLetters));

+		};

+

+		var formatNumber = function(data, numberOfLetters) {

+			var dataString = "" + data;

+			// Pad with 0s as necessary

+			return padWithZeroes(dataString, numberOfLetters);

+		};

+

+		SimpleDateFormat.prototype.format = function(date) {

+			var formattedString = "";

+			var result;

+			var searchString = this.formatString;

+			while ((result = regex.exec(searchString))) {

+				var quotedString = result[1];

+				var patternLetters = result[2];

+				var otherLetters = result[3];

+				var otherCharacters = result[4];

+

+				// If the pattern matched is quoted string, output the text between the quotes

+				if (quotedString) {

+					if (quotedString == "''") {

+						formattedString += "'";

+					} else {

+						formattedString += quotedString.substring(1, quotedString.length - 1);

+					}

+				} else if (otherLetters) {

+					// Swallow non-pattern letters by doing nothing here

+				} else if (otherCharacters) {

+					// Simply output other characters

+					formattedString += otherCharacters;

+				} else if (patternLetters) {

+					// Replace pattern letters

+					var patternLetter = patternLetters.charAt(0);

+					var numberOfLetters = patternLetters.length;

+					var rawData = "";

+					switch(patternLetter) {

+						case "G":

+							rawData = "AD";

+							break;

+						case "y":

+							rawData = date.getFullYear();

+							break;

+						case "M":

+							rawData = date.getMonth();

+							break;

+						case "w":

+							rawData = date.getWeekInYear(this.getMinimalDaysInFirstWeek());

+							break;

+						case "W":

+							rawData = date.getWeekInMonth(this.getMinimalDaysInFirstWeek());

+							break;

+						case "D":

+							rawData = date.getDayInYear();

+							break;

+						case "d":

+							rawData = date.getDate();

+							break;

+						case "F":

+							rawData = 1 + Math.floor((date.getDate() - 1) / 7);

+							break;

+						case "E":

+							rawData = dayNames[date.getDay()];

+							break;

+						case "a":

+							rawData = (date.getHours() >= 12) ? "PM" : "AM";

+							break;

+						case "H":

+							rawData = date.getHours();

+							break;

+						case "k":

+							rawData = date.getHours() || 24;

+							break;

+						case "K":

+							rawData = date.getHours() % 12;

+							break;

+						case "h":

+							rawData = (date.getHours() % 12) || 12;

+							break;

+						case "m":

+							rawData = date.getMinutes();

+							break;

+						case "s":

+							rawData = date.getSeconds();

+							break;

+						case "S":

+							rawData = date.getMilliseconds();

+							break;

+						case "Z":

+							rawData = date.getTimezoneOffset(); // This returns the number of minutes since GMT was this time.

+							break;

+					}

+					// Format the raw data depending on the type

+					switch(types[patternLetter]) {

+						case TEXT2:

+							formattedString += formatText(rawData, numberOfLetters, 2);

+							break;

+						case TEXT3:

+							formattedString += formatText(rawData, numberOfLetters, 3);

+							break;

+						case NUMBER:

+							formattedString += formatNumber(rawData, numberOfLetters);

+							break;

+						case YEAR:

+							if (numberOfLetters <= 3) {

+								// Output a 2-digit year

+								var dataString = "" + rawData;

+								formattedString += dataString.substr(2, 2);

+							} else {

+								formattedString += formatNumber(rawData, numberOfLetters);

+							}

+							break;

+						case MONTH:

+							if (numberOfLetters >= 3) {

+								formattedString += formatText(monthNames[rawData], numberOfLetters, numberOfLetters);

+							} else {

+								// NB. Months returned by getMonth are zero-based

+								formattedString += formatNumber(rawData + 1, numberOfLetters);

+							}

+							break;

+						case TIMEZONE:

+							var isPositive = (rawData > 0);

+							// The following line looks like a mistake but isn't

+							// because of the way getTimezoneOffset measures.

+							var prefix = isPositive ? "-" : "+";

+							var absData = Math.abs(rawData);

+

+							// Hours

+							var hours = "" + Math.floor(absData / 60);

+							hours = padWithZeroes(hours, 2);

+							// Minutes

+							var minutes = "" + (absData % 60);

+							minutes = padWithZeroes(minutes, 2);

+

+							formattedString += prefix + hours + minutes;

+							break;

+					}

+				}

+				searchString = searchString.substr(result.index + result[0].length);

+			}

+			return formattedString;

+		};

+	})();

+

+	log4javascript.SimpleDateFormat = SimpleDateFormat;

+

+	/* ---------------------------------------------------------------------- */

+	// PatternLayout

+

+	function PatternLayout(pattern) {

+		if (pattern) {

+			this.pattern = pattern;

+		} else {

+			this.pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;

+		}

+		this.customFields = [];

+	}

+

+	PatternLayout.TTCC_CONVERSION_PATTERN = "%r %p %c - %m%n";

+	PatternLayout.DEFAULT_CONVERSION_PATTERN = "%m%n";

+	PatternLayout.ISO8601_DATEFORMAT = "yyyy-MM-dd HH:mm:ss,SSS";

+	PatternLayout.DATETIME_DATEFORMAT = "dd MMM yyyy HH:mm:ss,SSS";

+	PatternLayout.ABSOLUTETIME_DATEFORMAT = "HH:mm:ss,SSS";

+

+	PatternLayout.prototype = new Layout();

+

+	PatternLayout.prototype.format = function(loggingEvent) {

+		var regex = /%(-?[0-9]+)?(\.?[0-9]+)?([acdfmMnpr%])(\{([^\}]+)\})?|([^%]+)/;

+		var formattedString = "";

+		var result;

+		var searchString = this.pattern;

+

+		// Cannot use regex global flag since it doesn't work with exec in IE5

+		while ((result = regex.exec(searchString))) {

+			var matchedString = result[0];

+			var padding = result[1];

+			var truncation = result[2];

+			var conversionCharacter = result[3];

+			var specifier = result[5];

+			var text = result[6];

+

+			// Check if the pattern matched was just normal text

+			if (text) {

+				formattedString += "" + text;

+			} else {

+				// Create a raw replacement string based on the conversion

+				// character and specifier

+				var replacement = "";

+				switch(conversionCharacter) {

+					case "a": // Array of messages

+					case "m": // Message

+						var depth = 0;

+						if (specifier) {

+							depth = parseInt(specifier, 10);

+							if (isNaN(depth)) {

+								handleError("PatternLayout.format: invalid specifier '" +

+									specifier + "' for conversion character '" + conversionCharacter +

+									"' - should be a number");

+								depth = 0;

+							}

+						}

+						var messages = (conversionCharacter === "a") ? loggingEvent.messages[0] : loggingEvent.messages;

+						for (var i = 0, len = messages.length; i < len; i++) {

+							if (i > 0 && (replacement.charAt(replacement.length - 1) !== " ")) {

+								replacement += " ";

+							}

+							if (depth === 0) {

+								replacement += messages[i];

+							} else {

+								replacement += formatObjectExpansion(messages[i], depth);

+							}

+						}

+						break;

+					case "c": // Logger name

+						var loggerName = loggingEvent.logger.name;

+						if (specifier) {

+							var precision = parseInt(specifier, 10);

+							var loggerNameBits = loggingEvent.logger.name.split(".");

+							if (precision >= loggerNameBits.length) {

+								replacement = loggerName;

+							} else {

+								replacement = loggerNameBits.slice(loggerNameBits.length - precision).join(".");

+							}

+						} else {

+							replacement = loggerName;

+						}

+						break;

+					case "d": // Date

+						var dateFormat = PatternLayout.ISO8601_DATEFORMAT;

+						if (specifier) {

+							dateFormat = specifier;

+							// Pick up special cases

+							if (dateFormat == "ISO8601") {

+								dateFormat = PatternLayout.ISO8601_DATEFORMAT;

+							} else if (dateFormat == "ABSOLUTE") {

+								dateFormat = PatternLayout.ABSOLUTETIME_DATEFORMAT;

+							} else if (dateFormat == "DATE") {

+								dateFormat = PatternLayout.DATETIME_DATEFORMAT;

+							}

+						}

+						// Format the date

+						replacement = (new SimpleDateFormat(dateFormat)).format(loggingEvent.timeStamp);

+						break;

+					case "f": // Custom field

+						if (this.hasCustomFields()) {

+							var fieldIndex = 0;

+							if (specifier) {

+								fieldIndex = parseInt(specifier, 10);

+								if (isNaN(fieldIndex)) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - should be a number");

+								} else if (fieldIndex === 0) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - must be greater than zero");

+								} else if (fieldIndex > this.customFields.length) {

+									handleError("PatternLayout.format: invalid specifier '" +

+										specifier + "' for conversion character 'f' - there aren't that many custom fields");

+								} else {

+									fieldIndex = fieldIndex - 1;

+								}

+							}

+                            var val = this.customFields[fieldIndex].value;

+                            if (typeof val == "function") {

+                                val = val(this, loggingEvent);

+                            }

+                            replacement = val;

+						}

+						break;

+					case "n": // New line

+						replacement = newLine;

+						break;

+					case "p": // Level

+						replacement = loggingEvent.level.name;

+						break;

+					case "r": // Milliseconds since log4javascript startup

+						replacement = "" + loggingEvent.timeStamp.getDifference(applicationStartDate);

+						break;

+					case "%": // Literal % sign

+						replacement = "%";

+						break;

+					default:

+						replacement = matchedString;

+						break;

+				}

+				// Format the replacement according to any padding or

+				// truncation specified

+				var l;

+

+				// First, truncation

+				if (truncation) {

+					l = parseInt(truncation.substr(1), 10);

+					var strLen = replacement.length;

+					if (l < strLen) {

+						replacement = replacement.substring(strLen - l, strLen);

+					}

+				}

+				// Next, padding

+				if (padding) {

+					if (padding.charAt(0) == "-") {

+						l = parseInt(padding.substr(1), 10);

+						// Right pad with spaces

+						while (replacement.length < l) {

+							replacement += " ";

+						}

+					} else {

+						l = parseInt(padding, 10);

+						// Left pad with spaces

+						while (replacement.length < l) {

+							replacement = " " + replacement;

+						}

+					}

+				}

+				formattedString += replacement;

+			}

+			searchString = searchString.substr(result.index + result[0].length);

+		}

+		return formattedString;

+	};

+

+	PatternLayout.prototype.ignoresThrowable = function() {

+	    return true;

+	};

+

+	PatternLayout.prototype.toString = function() {

+	    return "PatternLayout";

+	};

+

+	log4javascript.PatternLayout = PatternLayout;

+	/* ---------------------------------------------------------------------- */

+	// AlertAppender

+

+	function AlertAppender() {}

+

+	AlertAppender.prototype = new Appender();

+

+	AlertAppender.prototype.layout = new SimpleLayout();

+

+	AlertAppender.prototype.append = function(loggingEvent) {

+		var formattedMessage = this.getLayout().format(loggingEvent);

+		if (this.getLayout().ignoresThrowable()) {

+			formattedMessage += loggingEvent.getThrowableStrRep();

+		}

+		alert(formattedMessage);

+	};

+

+	AlertAppender.prototype.toString = function() {

+		return "AlertAppender";

+	};

+

+	log4javascript.AlertAppender = AlertAppender;

+	/* ---------------------------------------------------------------------- */

+	// BrowserConsoleAppender (only works in Opera and Safari and Firefox with

+	// Firebug extension)

+

+	function BrowserConsoleAppender() {}

+

+	BrowserConsoleAppender.prototype = new log4javascript.Appender();

+	BrowserConsoleAppender.prototype.layout = new NullLayout();

+	BrowserConsoleAppender.prototype.threshold = Level.DEBUG;

+

+	BrowserConsoleAppender.prototype.append = function(loggingEvent) {

+		var appender = this;

+

+		var getFormattedMessage = function() {

+			var layout = appender.getLayout();

+			var formattedMessage = layout.format(loggingEvent);

+			if (layout.ignoresThrowable() && loggingEvent.exception) {

+				formattedMessage += loggingEvent.getThrowableStrRep();

+			}

+			return formattedMessage;

+		};

+

+		if ((typeof opera != "undefined") && opera.postError) { // Opera

+			opera.postError(getFormattedMessage());

+		} else if (window.console && window.console.log) { // Safari and Firebug

+			var formattedMesage = getFormattedMessage();

+			// Log to Firebug using its logging methods or revert to the console.log

+			// method in Safari

+			if (window.console.debug && Level.DEBUG.isGreaterOrEqual(loggingEvent.level)) {

+				window.console.debug(formattedMesage);

+			} else if (window.console.info && Level.INFO.equals(loggingEvent.level)) {

+				window.console.info(formattedMesage);

+			} else if (window.console.warn && Level.WARN.equals(loggingEvent.level)) {

+				window.console.warn(formattedMesage);

+			} else if (window.console.error && loggingEvent.level.isGreaterOrEqual(Level.ERROR)) {

+				window.console.error(formattedMesage);

+			} else {

+				window.console.log(formattedMesage);

+			}

+		}

+	};

+

+	BrowserConsoleAppender.prototype.group = function(name) {

+		if (window.console && window.console.group) {

+			window.console.group(name);

+		}

+	};

+

+	BrowserConsoleAppender.prototype.groupEnd = function() {

+		if (window.console && window.console.groupEnd) {

+			window.console.groupEnd();

+		}

+	};

+

+	BrowserConsoleAppender.prototype.toString = function() {

+		return "BrowserConsoleAppender";

+	};

+

+	log4javascript.BrowserConsoleAppender = BrowserConsoleAppender;

+	/* ---------------------------------------------------------------------- */

+	// AjaxAppender related

+

+	var xmlHttpFactories = [

+		function() { return new XMLHttpRequest(); },

+		function() { return new ActiveXObject("Msxml2.XMLHTTP"); },

+		function() { return new ActiveXObject("Microsoft.XMLHTTP"); }

+	];

+

+	var getXmlHttp = function(errorHandler) {

+		// This is only run the first time; the value of getXmlHttp gets

+		// replaced with the factory that succeeds on the first run

+		var xmlHttp = null, factory;

+		for (var i = 0, len = xmlHttpFactories.length; i < len; i++) {

+			factory = xmlHttpFactories[i];

+			try {

+				xmlHttp = factory();

+				getXmlHttp = factory;

+				return xmlHttp;

+			} catch (e) {

+			}

+		}

+		// If we're here, all factories have failed, so throw an error

+		if (errorHandler) {

+			errorHandler();

+		} else {

+			handleError("getXmlHttp: unable to obtain XMLHttpRequest object");

+		}

+	};

+

+	function isHttpRequestSuccessful(xmlHttp) {

+		return isUndefined(xmlHttp.status) || xmlHttp.status === 0 ||

+			(xmlHttp.status >= 200 && xmlHttp.status < 300) ||

+			xmlHttp.status == 1223 /* Fix for IE */;

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// AjaxAppender

+

+	function AjaxAppender(url) {

+		var appender = this;

+		var isSupported = true;

+		if (!url) {

+			handleError("AjaxAppender: URL must be specified in constructor");

+			isSupported = false;

+		}

+

+		var timed = this.defaults.timed;

+		var waitForResponse = this.defaults.waitForResponse;

+		var batchSize = this.defaults.batchSize;

+		var timerInterval = this.defaults.timerInterval;

+		var requestSuccessCallback = this.defaults.requestSuccessCallback;

+		var failCallback = this.defaults.failCallback;

+		var postVarName = this.defaults.postVarName;

+		var sendAllOnUnload = this.defaults.sendAllOnUnload;

+		var contentType = this.defaults.contentType;

+		var sessionId = null;

+

+		var queuedLoggingEvents = [];

+		var queuedRequests = [];

+		var headers = [];

+		var sending = false;

+		var initialized = false;

+

+		// Configuration methods. The function scope is used to prevent

+		// direct alteration to the appender configuration properties.

+		function checkCanConfigure(configOptionName) {

+			if (initialized) {

+				handleError("AjaxAppender: configuration option '" +

+					configOptionName +

+					"' may not be set after the appender has been initialized");

+				return false;

+			}

+			return true;

+		}

+

+		this.getSessionId = function() { return sessionId; };

+		this.setSessionId = function(sessionIdParam) {

+			sessionId = extractStringFromParam(sessionIdParam, null);

+			this.layout.setCustomField("sessionid", sessionId);

+		};

+

+		this.setLayout = function(layoutParam) {

+			if (checkCanConfigure("layout")) {

+				this.layout = layoutParam;

+				// Set the session id as a custom field on the layout, if not already present

+				if (sessionId !== null) {

+					this.setSessionId(sessionId);

+				}

+			}

+		};

+

+		this.isTimed = function() { return timed; };

+		this.setTimed = function(timedParam) {

+			if (checkCanConfigure("timed")) {

+				timed = bool(timedParam);

+			}

+		};

+

+		this.getTimerInterval = function() { return timerInterval; };

+		this.setTimerInterval = function(timerIntervalParam) {

+			if (checkCanConfigure("timerInterval")) {

+				timerInterval = extractIntFromParam(timerIntervalParam, timerInterval);

+			}

+		};

+

+		this.isWaitForResponse = function() { return waitForResponse; };

+		this.setWaitForResponse = function(waitForResponseParam) {

+			if (checkCanConfigure("waitForResponse")) {

+				waitForResponse = bool(waitForResponseParam);

+			}

+		};

+

+		this.getBatchSize = function() { return batchSize; };

+		this.setBatchSize = function(batchSizeParam) {

+			if (checkCanConfigure("batchSize")) {

+				batchSize = extractIntFromParam(batchSizeParam, batchSize);

+			}

+		};

+

+		this.isSendAllOnUnload = function() { return sendAllOnUnload; };

+		this.setSendAllOnUnload = function(sendAllOnUnloadParam) {

+			if (checkCanConfigure("sendAllOnUnload")) {

+				sendAllOnUnload = extractBooleanFromParam(sendAllOnUnloadParam, sendAllOnUnload);

+			}

+		};

+

+		this.setRequestSuccessCallback = function(requestSuccessCallbackParam) {

+			requestSuccessCallback = extractFunctionFromParam(requestSuccessCallbackParam, requestSuccessCallback);

+		};

+

+		this.setFailCallback = function(failCallbackParam) {

+			failCallback = extractFunctionFromParam(failCallbackParam, failCallback);

+		};

+

+		this.getPostVarName = function() { return postVarName; };

+		this.setPostVarName = function(postVarNameParam) {

+			if (checkCanConfigure("postVarName")) {

+				postVarName = extractStringFromParam(postVarNameParam, postVarName);

+			}

+		};

+

+		this.getHeaders = function() { return headers; };

+		this.addHeader = function(name, value) {

+			if (name.toLowerCase() == "content-type") {

+				contentType = value;

+			} else {

+				headers.push( { name: name, value: value } );

+			}

+		};

+

+		// Internal functions

+		function sendAll() {

+			if (isSupported && enabled) {

+				sending = true;

+				var currentRequestBatch;

+				if (waitForResponse) {

+					// Send the first request then use this function as the callback once

+					// the response comes back

+					if (queuedRequests.length > 0) {

+						currentRequestBatch = queuedRequests.shift();

+						sendRequest(preparePostData(currentRequestBatch), sendAll);

+					} else {

+						sending = false;

+						if (timed) {

+							scheduleSending();

+						}

+					}

+				} else {

+					// Rattle off all the requests without waiting to see the response

+					while ((currentRequestBatch = queuedRequests.shift())) {

+						sendRequest(preparePostData(currentRequestBatch));

+					}

+					sending = false;

+					if (timed) {

+						scheduleSending();

+					}

+				}

+			}

+		}

+

+		this.sendAll = sendAll;

+

+		// Called when the window unloads. At this point we're past caring about

+		// waiting for responses or timers or incomplete batches - everything

+		// must go, now

+		function sendAllRemaining() {

+			var sendingAnything = false;

+			if (isSupported && enabled) {

+				// Create requests for everything left over, batched as normal

+				var actualBatchSize = appender.getLayout().allowBatching() ? batchSize : 1;

+				var currentLoggingEvent;

+				var batchedLoggingEvents = [];

+				while ((currentLoggingEvent = queuedLoggingEvents.shift())) {

+					batchedLoggingEvents.push(currentLoggingEvent);

+					if (queuedLoggingEvents.length >= actualBatchSize) {

+						// Queue this batch of log entries

+						queuedRequests.push(batchedLoggingEvents);

+						batchedLoggingEvents = [];

+					}

+				}

+				// If there's a partially completed batch, add it

+				if (batchedLoggingEvents.length > 0) {

+					queuedRequests.push(batchedLoggingEvents);

+				}

+				sendingAnything = (queuedRequests.length > 0);

+				waitForResponse = false;

+				timed = false;

+				sendAll();

+			}

+			return sendingAnything;

+		}

+

+		this.sendAllRemaining = sendAllRemaining;

+

+		function preparePostData(batchedLoggingEvents) {

+			// Format the logging events

+			var formattedMessages = [];

+			var currentLoggingEvent;

+			var postData = "";

+			while ((currentLoggingEvent = batchedLoggingEvents.shift())) {

+				var currentFormattedMessage = appender.getLayout().format(currentLoggingEvent);

+				if (appender.getLayout().ignoresThrowable()) {

+					currentFormattedMessage += currentLoggingEvent.getThrowableStrRep();

+				}

+				formattedMessages.push(currentFormattedMessage);

+			}

+			// Create the post data string

+			if (batchedLoggingEvents.length == 1) {

+				postData = formattedMessages.join("");

+			} else {

+				postData = appender.getLayout().batchHeader +

+					formattedMessages.join(appender.getLayout().batchSeparator) +

+					appender.getLayout().batchFooter;

+			}

+			if (contentType == appender.defaults.contentType) {

+				postData = appender.getLayout().returnsPostData ? postData :

+					urlEncode(postVarName) + "=" + urlEncode(postData);

+				// Add the layout name to the post data

+				if (postData.length > 0) {

+					postData += "&";

+				}

+				postData += "layout=" + urlEncode(appender.getLayout().toString());

+			}

+			return postData;

+		}

+

+		function scheduleSending() {

+			window.setTimeout(sendAll, timerInterval);

+		}

+

+		function xmlHttpErrorHandler() {

+			var msg = "AjaxAppender: could not create XMLHttpRequest object. AjaxAppender disabled";

+			handleError(msg);

+			isSupported = false;

+			if (failCallback) {

+				failCallback(msg);

+			}

+		}

+

+		function sendRequest(postData, successCallback) {

+			try {

+				var xmlHttp = getXmlHttp(xmlHttpErrorHandler);

+				if (isSupported) {

+					if (xmlHttp.overrideMimeType) {

+						xmlHttp.overrideMimeType(appender.getLayout().getContentType());

+					}

+					xmlHttp.onreadystatechange = function() {

+						if (xmlHttp.readyState == 4) {

+							if (isHttpRequestSuccessful(xmlHttp)) {

+								if (requestSuccessCallback) {

+									requestSuccessCallback(xmlHttp);

+								}

+								if (successCallback) {

+									successCallback(xmlHttp);

+								}

+							} else {

+								var msg = "AjaxAppender.append: XMLHttpRequest request to URL " +

+									url + " returned status code " + xmlHttp.status;

+								handleError(msg);

+								if (failCallback) {

+									failCallback(msg);

+								}

+							}

+							xmlHttp.onreadystatechange = emptyFunction;

+							xmlHttp = null;

+						}

+					};

+					xmlHttp.open("POST", url, true);

+					try {

+						for (var i = 0, header; header = headers[i++]; ) {

+							xmlHttp.setRequestHeader(header.name, header.value);

+						}

+						xmlHttp.setRequestHeader("Content-Type", contentType);

+					} catch (headerEx) {

+						var msg = "AjaxAppender.append: your browser's XMLHttpRequest implementation" +

+							" does not support setRequestHeader, therefore cannot post data. AjaxAppender disabled";

+						handleError(msg);

+						isSupported = false;

+						if (failCallback) {

+							failCallback(msg);

+						}

+						return;

+					}

+					xmlHttp.send(postData);

+				}

+			} catch (ex) {

+				var errMsg = "AjaxAppender.append: error sending log message to " + url;

+				handleError(errMsg, ex);

+				isSupported = false;

+				if (failCallback) {

+					failCallback(errMsg + ". Details: " + getExceptionStringRep(ex));

+				}

+			}

+		}

+

+		this.append = function(loggingEvent) {

+			if (isSupported) {

+				if (!initialized) {

+					init();

+				}

+				queuedLoggingEvents.push(loggingEvent);

+				var actualBatchSize = this.getLayout().allowBatching() ? batchSize : 1;

+

+				if (queuedLoggingEvents.length >= actualBatchSize) {

+					var currentLoggingEvent;

+					var batchedLoggingEvents = [];

+					while ((currentLoggingEvent = queuedLoggingEvents.shift())) {

+						batchedLoggingEvents.push(currentLoggingEvent);

+					}

+					// Queue this batch of log entries

+					queuedRequests.push(batchedLoggingEvents);

+

+					// If using a timer, the queue of requests will be processed by the

+					// timer function, so nothing needs to be done here.

+					if (!timed && (!waitForResponse || (waitForResponse && !sending))) {

+						sendAll();

+					}

+				}

+			}

+		};

+

+		function init() {

+			initialized = true;

+			// Add unload event to send outstanding messages

+			if (sendAllOnUnload) {

+				var oldBeforeUnload = window.onbeforeunload;

+				window.onbeforeunload = function() {

+					if (oldBeforeUnload) {

+						oldBeforeUnload();

+					}

+					if (sendAllRemaining()) {

+						return "Sending log messages";

+					}

+				};

+			}

+			// Start timer

+			if (timed) {

+				scheduleSending();

+			}

+		}

+	}

+

+	AjaxAppender.prototype = new Appender();

+

+	AjaxAppender.prototype.defaults = {

+		waitForResponse: false,

+		timed: false,

+		timerInterval: 1000,

+		batchSize: 1,

+		sendAllOnUnload: false,

+		requestSuccessCallback: null,

+		failCallback: null,

+		postVarName: "data",

+		contentType: "application/x-www-form-urlencoded"

+	};

+

+	AjaxAppender.prototype.layout = new HttpPostDataLayout();

+

+	AjaxAppender.prototype.toString = function() {

+		return "AjaxAppender";

+	};

+

+	log4javascript.AjaxAppender = AjaxAppender;

+	/* ---------------------------------------------------------------------- */

+	// PopUpAppender and InPageAppender related

+

+	function setCookie(name, value, days, path) {

+	    var expires;

+	    path = path ? "; path=" + path : "";

+		if (days) {

+			var date = new Date();

+			date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));

+			expires = "; expires=" + date.toGMTString();

+		} else {

+		    expires = "";

+	    }

+		document.cookie = escape(name) + "=" + escape(value) + expires + path;

+	}

+

+	function getCookie(name) {

+		var nameEquals = escape(name) + "=";

+		var ca = document.cookie.split(";");

+		for (var i = 0, len = ca.length; i < len; i++) {

+			var c = ca[i];

+			while (c.charAt(0) === " ") {

+			    c = c.substring(1, c.length);

+			}

+			if (c.indexOf(nameEquals) === 0) {

+			    return unescape(c.substring(nameEquals.length, c.length));

+	        }

+		}

+		return null;

+	}

+

+	// Gets the base URL of the location of the log4javascript script.

+	// This is far from infallible.

+	function getBaseUrl() {

+		var scripts = document.getElementsByTagName("script");

+		for (var i = 0, len = scripts.length; i < len; ++i) {

+			if (scripts[i].src.indexOf("log4javascript") != -1) {

+				var lastSlash = scripts[i].src.lastIndexOf("/");

+				return (lastSlash == -1) ? "" : scripts[i].src.substr(0, lastSlash + 1);

+			}

+		}

+        return null;

+    }

+

+	function isLoaded(win) {

+		try {

+			return bool(win.loaded);

+		} catch (ex) {

+			return false;

+		}

+	}

+

+	/* ---------------------------------------------------------------------- */

+	// ConsoleAppender (prototype for PopUpAppender and InPageAppender)

+

+	var ConsoleAppender;

+

+	// Create an anonymous function to protect base console methods

+	(function() {

+		var getConsoleHtmlLines = function() {

+			return [

+'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',

+'<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">',

+'	<head>',

+'		<title>log4javascript</title>',

+'		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />',

+'		<!-- Make IE8 behave like IE7, having gone to all the trouble of making IE work -->',

+'		<meta http-equiv="X-UA-Compatible" content="IE=7" />',

+'		<script type="text/javascript">var isIe = false, isIePre7 = false;</script>',

+'		<!--[if IE]><script type="text/javascript">isIe = true</script><![endif]-->',

+'		<!--[if lt IE 7]><script type="text/javascript">isIePre7 = true</script><![endif]-->',

+'		<script type="text/javascript">',

+'			//<![CDATA[',

+'			var loggingEnabled = true;',

+'			var logQueuedEventsTimer = null;',

+'			var logEntries = [];',

+'			var logEntriesAndSeparators = [];',

+'			var logItems = [];',

+'			var renderDelay = 100;',

+'			var unrenderedLogItemsExist = false;',

+'			var rootGroup, currentGroup = null;',

+'			var loaded = false;',

+'			var currentLogItem = null;',

+'			var logMainContainer;',

+'',

+'			function copyProperties(obj, props) {',

+'				for (var i in props) {',

+'					obj[i] = props[i];',

+'				}',

+'			}',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItem() {',

+'			}',

+'',

+'			LogItem.prototype = {',

+'				mainContainer: null,',

+'				wrappedContainer: null,',

+'				unwrappedContainer: null,',

+'				group: null,',

+'',

+'				appendToLog: function() {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].appendToLog();',

+'					}',

+'					this.group.update();',

+'				},',

+'',

+'				doRemove: function(doUpdate, removeFromGroup) {',

+'					if (this.rendered) {',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].remove();',

+'						}',

+'						this.unwrappedElementContainer = null;',

+'						this.wrappedElementContainer = null;',

+'						this.mainElementContainer = null;',

+'					}',

+'					if (this.group && removeFromGroup) {',

+'						this.group.removeChild(this, doUpdate);',

+'					}',

+'					if (this === currentLogItem) {',

+'						currentLogItem = null;',

+'					}',

+'				},',

+'',

+'				remove: function(doUpdate, removeFromGroup) {',

+'					this.doRemove(doUpdate, removeFromGroup);',

+'				},',

+'',

+'				render: function() {},',

+'',

+'				accept: function(visitor) {',

+'					visitor.visit(this);',

+'				},',

+'',

+'				getUnwrappedDomContainer: function() {',

+'					return this.group.unwrappedElementContainer.contentDiv;',

+'				},',

+'',

+'				getWrappedDomContainer: function() {',

+'					return this.group.wrappedElementContainer.contentDiv;',

+'				},',

+'',

+'				getMainDomContainer: function() {',

+'					return this.group.mainElementContainer.contentDiv;',

+'				}',

+'			};',

+'',

+'			LogItem.serializedItemKeys = {LOG_ENTRY: 0, GROUP_START: 1, GROUP_END: 2};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItemContainerElement() {',

+'			}',

+'',

+'			LogItemContainerElement.prototype = {',

+'				appendToLog: function() {',

+'					var insertBeforeFirst = (newestAtTop && this.containerDomNode.hasChildNodes());',

+'					if (insertBeforeFirst) {',

+'						this.containerDomNode.insertBefore(this.mainDiv, this.containerDomNode.firstChild);',

+'					} else {',

+'						this.containerDomNode.appendChild(this.mainDiv);',

+'					}',

+'				}',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function SeparatorElementContainer(containerDomNode) {',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.className = "separator";',

+'				this.mainDiv.innerHTML = "&nbsp;";',

+'			}',

+'',

+'			SeparatorElementContainer.prototype = new LogItemContainerElement();',

+'',

+'			SeparatorElementContainer.prototype.remove = function() {',

+'				this.mainDiv.parentNode.removeChild(this.mainDiv);',

+'				this.mainDiv = null;',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function Separator() {',

+'				this.rendered = false;',

+'			}',

+'',

+'			Separator.prototype = new LogItem();',

+'',

+'			copyProperties(Separator.prototype, {',

+'				render: function() {',

+'					var containerDomNode = this.group.contentDiv;',

+'					if (isIe) {',

+'						this.unwrappedElementContainer = new SeparatorElementContainer(this.getUnwrappedDomContainer());',

+'						this.wrappedElementContainer = new SeparatorElementContainer(this.getWrappedDomContainer());',

+'						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',

+'					} else {',

+'						this.mainElementContainer = new SeparatorElementContainer(this.getMainDomContainer());',

+'						this.elementContainers = [this.mainElementContainer];',

+'					}',

+'					this.content = this.formattedMessage;',

+'					this.rendered = true;',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function GroupElementContainer(group, containerDomNode, isRoot, isWrapped) {',

+'				this.group = group;',

+'				this.containerDomNode = containerDomNode;',

+'				this.isRoot = isRoot;',

+'				this.isWrapped = isWrapped;',

+'				this.expandable = false;',

+'',

+'				if (this.isRoot) {',

+'					if (isIe) {',

+'						this.contentDiv = logMainContainer.appendChild(document.createElement("div"));',

+'						this.contentDiv.id = this.isWrapped ? "log_wrapped" : "log_unwrapped";',

+'					} else {',

+'						this.contentDiv = logMainContainer;',

+'					}',

+'				} else {',

+'					var groupElementContainer = this;',

+'					',

+'					this.mainDiv = document.createElement("div");',

+'					this.mainDiv.className = "group";',

+'',

+'					this.headingDiv = this.mainDiv.appendChild(document.createElement("div"));',

+'					this.headingDiv.className = "groupheading";',

+'',

+'					this.expander = this.headingDiv.appendChild(document.createElement("span"));',

+'					this.expander.className = "expander unselectable greyedout";',

+'					this.expander.unselectable = true;',

+'					var expanderText = this.group.expanded ? "-" : "+";',

+'					this.expanderTextNode = this.expander.appendChild(document.createTextNode(expanderText));',

+'					',

+'					this.headingDiv.appendChild(document.createTextNode(" " + this.group.name));',

+'',

+'					this.contentDiv = this.mainDiv.appendChild(document.createElement("div"));',

+'					var contentCssClass = this.group.expanded ? "expanded" : "collapsed";',

+'					this.contentDiv.className = "groupcontent " + contentCssClass;',

+'',

+'					this.expander.onclick = function() {',

+'						if (groupElementContainer.group.expandable) {',

+'							groupElementContainer.group.toggleExpanded();',

+'						}',

+'					};',

+'				}',

+'			}',

+'',

+'			GroupElementContainer.prototype = new LogItemContainerElement();',

+'',

+'			copyProperties(GroupElementContainer.prototype, {',

+'				toggleExpanded: function() {',

+'					if (!this.isRoot) {',

+'						var oldCssClass, newCssClass, expanderText;',

+'						if (this.group.expanded) {',

+'							newCssClass = "expanded";',

+'							oldCssClass = "collapsed";',

+'							expanderText = "-";',

+'						} else {',

+'							newCssClass = "collapsed";',

+'							oldCssClass = "expanded";',

+'							expanderText = "+";',

+'						}',

+'						replaceClass(this.contentDiv, newCssClass, oldCssClass);',

+'						this.expanderTextNode.nodeValue = expanderText;',

+'					}',

+'				},',

+'',

+'				remove: function() {',

+'					if (!this.isRoot) {',

+'						this.headingDiv = null;',

+'						this.expander.onclick = null;',

+'						this.expander = null;',

+'						this.expanderTextNode = null;',

+'						this.contentDiv = null;',

+'						this.containerDomNode = null;',

+'						this.mainDiv.parentNode.removeChild(this.mainDiv);',

+'						this.mainDiv = null;',

+'					}',

+'				},',

+'',

+'				reverseChildren: function() {',

+'					// Invert the order of the log entries',

+'					var node = null;',

+'',

+'					// Remove all the log container nodes',

+'					var childDomNodes = [];',

+'					while ((node = this.contentDiv.firstChild)) {',

+'						this.contentDiv.removeChild(node);',

+'						childDomNodes.push(node);',

+'					}',

+'',

+'					// Put them all back in reverse order',

+'					while ((node = childDomNodes.pop())) {',

+'						this.contentDiv.appendChild(node);',

+'					}',

+'				},',

+'',

+'				update: function() {',

+'					if (!this.isRoot) {',

+'						if (this.group.expandable) {',

+'							removeClass(this.expander, "greyedout");',

+'						} else {',

+'							addClass(this.expander, "greyedout");',

+'						}',

+'					}',

+'				},',

+'',

+'				clear: function() {',

+'					if (this.isRoot) {',

+'						this.contentDiv.innerHTML = "";',

+'					}',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function Group(name, isRoot, initiallyExpanded) {',

+'				this.name = name;',

+'				this.group = null;',

+'				this.isRoot = isRoot;',

+'				this.initiallyExpanded = initiallyExpanded;',

+'				this.elementContainers = [];',

+'				this.children = [];',

+'				this.expanded = initiallyExpanded;',

+'				this.rendered = false;',

+'				this.expandable = false;',

+'			}',

+'',

+'			Group.prototype = new LogItem();',

+'',

+'			copyProperties(Group.prototype, {',

+'				addChild: function(logItem) {',

+'					this.children.push(logItem);',

+'					logItem.group = this;',

+'				},',

+'',

+'				render: function() {',

+'					if (isIe) {',

+'						var unwrappedDomContainer, wrappedDomContainer;',

+'						if (this.isRoot) {',

+'							unwrappedDomContainer = logMainContainer;',

+'							wrappedDomContainer = logMainContainer;',

+'						} else {',

+'							unwrappedDomContainer = this.getUnwrappedDomContainer();',

+'							wrappedDomContainer = this.getWrappedDomContainer();',

+'						}',

+'						this.unwrappedElementContainer = new GroupElementContainer(this, unwrappedDomContainer, this.isRoot, false);',

+'						this.wrappedElementContainer = new GroupElementContainer(this, wrappedDomContainer, this.isRoot, true);',

+'						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',

+'					} else {',

+'						var mainDomContainer = this.isRoot ? logMainContainer : this.getMainDomContainer();',

+'						this.mainElementContainer = new GroupElementContainer(this, mainDomContainer, this.isRoot, false);',

+'						this.elementContainers = [this.mainElementContainer];',

+'					}',

+'					this.rendered = true;',

+'				},',

+'',

+'				toggleExpanded: function() {',

+'					this.expanded = !this.expanded;',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].toggleExpanded();',

+'					}',

+'				},',

+'',

+'				expand: function() {',

+'					if (!this.expanded) {',

+'						this.toggleExpanded();',

+'					}',

+'				},',

+'',

+'				accept: function(visitor) {',

+'					visitor.visitGroup(this);',

+'				},',

+'',

+'				reverseChildren: function() {',

+'					if (this.rendered) {',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].reverseChildren();',

+'						}',

+'					}',

+'				},',

+'',

+'				update: function() {',

+'					var previouslyExpandable = this.expandable;',

+'					this.expandable = (this.children.length !== 0);',

+'					if (this.expandable !== previouslyExpandable) {',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].update();',

+'						}',

+'					}',

+'				},',

+'',

+'				flatten: function() {',

+'					var visitor = new GroupFlattener();',

+'					this.accept(visitor);',

+'					return visitor.logEntriesAndSeparators;',

+'				},',

+'',

+'				removeChild: function(child, doUpdate) {',

+'					array_remove(this.children, child);',

+'					child.group = null;',

+'					if (doUpdate) {',

+'						this.update();',

+'					}',

+'				},',

+'',

+'				remove: function(doUpdate, removeFromGroup) {',

+'					for (var i = 0, len = this.children.length; i < len; i++) {',

+'						this.children[i].remove(false, false);',

+'					}',

+'					this.children = [];',

+'					this.update();',

+'					if (this === currentGroup) {',

+'						currentGroup = this.group;',

+'					}',

+'					this.doRemove(doUpdate, removeFromGroup);',

+'				},',

+'',

+'				serialize: function(items) {',

+'					items.push([LogItem.serializedItemKeys.GROUP_START, this.name]);',

+'					for (var i = 0, len = this.children.length; i < len; i++) {',

+'						this.children[i].serialize(items);',

+'					}',

+'					if (this !== currentGroup) {',

+'						items.push([LogItem.serializedItemKeys.GROUP_END]);',

+'					}',

+'				},',

+'',

+'				clear: function() {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].clear();',

+'					}',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryElementContainer() {',

+'			}',

+'',

+'			LogEntryElementContainer.prototype = new LogItemContainerElement();',

+'',

+'			copyProperties(LogEntryElementContainer.prototype, {',

+'				remove: function() {',

+'					this.doRemove();',

+'				},',

+'',

+'				doRemove: function() {',

+'					this.mainDiv.parentNode.removeChild(this.mainDiv);',

+'					this.mainDiv = null;',

+'					this.contentElement = null;',

+'					this.containerDomNode = null;',

+'				},',

+'',

+'				setContent: function(content, wrappedContent) {',

+'					if (content === this.formattedMessage) {',

+'						this.contentElement.innerHTML = "";',

+'						this.contentElement.appendChild(document.createTextNode(this.formattedMessage));',

+'					} else {',

+'						this.contentElement.innerHTML = content;',

+'					}',

+'				},',

+'',

+'				setSearchMatch: function(isMatch) {',

+'					var oldCssClass = isMatch ? "searchnonmatch" : "searchmatch";',

+'					var newCssClass = isMatch ? "searchmatch" : "searchnonmatch";',

+'					replaceClass(this.mainDiv, newCssClass, oldCssClass);',

+'				},',

+'',

+'				clearSearch: function() {',

+'					removeClass(this.mainDiv, "searchmatch");',

+'					removeClass(this.mainDiv, "searchnonmatch");',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryWrappedElementContainer(logEntry, containerDomNode) {',

+'				this.logEntry = logEntry;',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.appendChild(document.createTextNode(this.logEntry.formattedMessage));',

+'				this.mainDiv.className = "logentry wrapped " + this.logEntry.level;',

+'				this.contentElement = this.mainDiv;',

+'			}',

+'',

+'			LogEntryWrappedElementContainer.prototype = new LogEntryElementContainer();',

+'',

+'			LogEntryWrappedElementContainer.prototype.setContent = function(content, wrappedContent) {',

+'				if (content === this.formattedMessage) {',

+'					this.contentElement.innerHTML = "";',

+'					this.contentElement.appendChild(document.createTextNode(this.formattedMessage));',

+'				} else {',

+'					this.contentElement.innerHTML = wrappedContent;',

+'				}',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryUnwrappedElementContainer(logEntry, containerDomNode) {',

+'				this.logEntry = logEntry;',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.className = "logentry unwrapped " + this.logEntry.level;',

+'				this.pre = this.mainDiv.appendChild(document.createElement("pre"));',

+'				this.pre.appendChild(document.createTextNode(this.logEntry.formattedMessage));',

+'				this.pre.className = "unwrapped";',

+'				this.contentElement = this.pre;',

+'			}',

+'',

+'			LogEntryUnwrappedElementContainer.prototype = new LogEntryElementContainer();',

+'',

+'			LogEntryUnwrappedElementContainer.prototype.remove = function() {',

+'				this.doRemove();',

+'				this.pre = null;',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntryMainElementContainer(logEntry, containerDomNode) {',

+'				this.logEntry = logEntry;',

+'				this.containerDomNode = containerDomNode;',

+'				this.mainDiv = document.createElement("div");',

+'				this.mainDiv.className = "logentry nonielogentry " + this.logEntry.level;',

+'				this.contentElement = this.mainDiv.appendChild(document.createElement("span"));',

+'				this.contentElement.appendChild(document.createTextNode(this.logEntry.formattedMessage));',

+'			}',

+'',

+'			LogEntryMainElementContainer.prototype = new LogEntryElementContainer();',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogEntry(level, formattedMessage) {',

+'				this.level = level;',

+'				this.formattedMessage = formattedMessage;',

+'				this.rendered = false;',

+'			}',

+'',

+'			LogEntry.prototype = new LogItem();',

+'',

+'			copyProperties(LogEntry.prototype, {',

+'				render: function() {',

+'					var logEntry = this;',

+'					var containerDomNode = this.group.contentDiv;',

+'',

+'					// Support for the CSS attribute white-space in IE for Windows is',

+'					// non-existent pre version 6 and slightly odd in 6, so instead',

+'					// use two different HTML elements',

+'					if (isIe) {',

+'						this.formattedMessage = this.formattedMessage.replace(/\\r\\n/g, "\\r"); // Workaround for IE\'s treatment of white space',

+'						this.unwrappedElementContainer = new LogEntryUnwrappedElementContainer(this, this.getUnwrappedDomContainer());',

+'						this.wrappedElementContainer = new LogEntryWrappedElementContainer(this, this.getWrappedDomContainer());',

+'						this.elementContainers = [this.unwrappedElementContainer, this.wrappedElementContainer];',

+'					} else {',

+'						this.mainElementContainer = new LogEntryMainElementContainer(this, this.getMainDomContainer());',

+'						this.elementContainers = [this.mainElementContainer];',

+'					}',

+'					this.content = this.formattedMessage;',

+'					this.rendered = true;',

+'				},',

+'',

+'				setContent: function(content, wrappedContent) {',

+'					if (content != this.content) {',

+'						if (isIe && (content !== this.formattedMessage)) {',

+'							content = content.replace(/\\r\\n/g, "\\r"); // Workaround for IE\'s treatment of white space',

+'						}',

+'						for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'							this.elementContainers[i].setContent(content, wrappedContent);',

+'						}',

+'						this.content = content;',

+'					}',

+'				},',

+'',

+'				getSearchMatches: function() {',

+'					var matches = [];',

+'					var i, len;',

+'					if (isIe) {',

+'						var unwrappedEls = getElementsByClass(this.unwrappedElementContainer.mainDiv, "searchterm", "span");',

+'						var wrappedEls = getElementsByClass(this.wrappedElementContainer.mainDiv, "searchterm", "span");',

+'						for (i = 0, len = unwrappedEls.length; i < len; i++) {',

+'							matches[i] = new Match(this.level, null, unwrappedEls[i], wrappedEls[i]);',

+'						}',

+'					} else {',

+'						var els = getElementsByClass(this.mainElementContainer.mainDiv, "searchterm", "span");',

+'						for (i = 0, len = els.length; i < len; i++) {',

+'							matches[i] = new Match(this.level, els[i]);',

+'						}',

+'					}',

+'					return matches;',

+'				},',

+'',

+'				setSearchMatch: function(isMatch) {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].setSearchMatch(isMatch);',

+'					}',

+'				},',

+'',

+'				clearSearch: function() {',

+'					for (var i = 0, len = this.elementContainers.length; i < len; i++) {',

+'						this.elementContainers[i].clearSearch();',

+'					}',

+'				},',

+'',

+'				accept: function(visitor) {',

+'					visitor.visitLogEntry(this);',

+'				},',

+'',

+'				serialize: function(items) {',

+'					items.push([LogItem.serializedItemKeys.LOG_ENTRY, this.level, this.formattedMessage]);',

+'				}',

+'			});',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItemVisitor() {',

+'			}',

+'',

+'			LogItemVisitor.prototype = {',

+'				visit: function(logItem) {',

+'				},',

+'',

+'				visitParent: function(logItem) {',

+'					if (logItem.group) {',

+'						logItem.group.accept(this);',

+'					}',

+'				},',

+'',

+'				visitChildren: function(logItem) {',

+'					for (var i = 0, len = logItem.children.length; i < len; i++) {',

+'						logItem.children[i].accept(this);',

+'					}',

+'				},',

+'',

+'				visitLogEntry: function(logEntry) {',

+'					this.visit(logEntry);',

+'				},',

+'',

+'				visitSeparator: function(separator) {',

+'					this.visit(separator);',

+'				},',

+'',

+'				visitGroup: function(group) {',

+'					this.visit(group);',

+'				}',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function GroupFlattener() {',

+'				this.logEntriesAndSeparators = [];',

+'			}',

+'',

+'			GroupFlattener.prototype = new LogItemVisitor();',

+'',

+'			GroupFlattener.prototype.visitGroup = function(group) {',

+'				this.visitChildren(group);',

+'			};',

+'',

+'			GroupFlattener.prototype.visitLogEntry = function(logEntry) {',

+'				this.logEntriesAndSeparators.push(logEntry);',

+'			};',

+'',

+'			GroupFlattener.prototype.visitSeparator = function(separator) {',

+'				this.logEntriesAndSeparators.push(separator);',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			window.onload = function() {',

+'				// Sort out document.domain',

+'				if (location.search) {',

+'					var queryBits = unescape(location.search).substr(1).split("&"), nameValueBits;',

+'					for (var i = 0, len = queryBits.length; i < len; i++) {',

+'						nameValueBits = queryBits[i].split("=");',

+'						if (nameValueBits[0] == "log4javascript_domain") {',

+'							document.domain = nameValueBits[1];',

+'							break;',

+'						}',

+'					}',

+'				}',

+'',

+'				// Create DOM objects',

+'				logMainContainer = $("log");',

+'				if (isIePre7) {',

+'					addClass(logMainContainer, "oldIe");',

+'				}',

+'',

+'				rootGroup = new Group("root", true);',

+'				rootGroup.render();',

+'				currentGroup = rootGroup;',

+'				',

+'				setCommandInputWidth();',

+'				setLogContainerHeight();',

+'				toggleLoggingEnabled();',

+'				toggleSearchEnabled();',

+'				toggleSearchFilter();',

+'				toggleSearchHighlight();',

+'				applyFilters();',

+'				checkAllLevels();',

+'				toggleWrap();',

+'				toggleNewestAtTop();',

+'				toggleScrollToLatest();',

+'				renderQueuedLogItems();',

+'				loaded = true;',

+'				$("command").value = "";',

+'				$("command").autocomplete = "off";',

+'				$("command").onkeydown = function(evt) {',

+'					evt = getEvent(evt);',

+'					if (evt.keyCode == 10 || evt.keyCode == 13) { // Return/Enter',

+'						evalCommandLine();',

+'						stopPropagation(evt);',

+'					} else if (evt.keyCode == 27) { // Escape',

+'						this.value = "";',

+'						this.focus();',

+'					} else if (evt.keyCode == 38 && commandHistory.length > 0) { // Up',

+'						currentCommandIndex = Math.max(0, currentCommandIndex - 1);',

+'						this.value = commandHistory[currentCommandIndex];',

+'						moveCaretToEnd(this);',

+'					} else if (evt.keyCode == 40 && commandHistory.length > 0) { // Down',

+'						currentCommandIndex = Math.min(commandHistory.length - 1, currentCommandIndex + 1);',

+'						this.value = commandHistory[currentCommandIndex];',

+'						moveCaretToEnd(this);',

+'					}',

+'				};',

+'',

+'				// Prevent the keypress moving the caret in Firefox',

+'				$("command").onkeypress = function(evt) {',

+'					evt = getEvent(evt);',

+'					if (evt.keyCode == 38 && commandHistory.length > 0 && evt.preventDefault) { // Up',

+'						evt.preventDefault();',

+'					}',

+'				};',

+'',

+'				// Prevent the keyup event blurring the input in Opera',

+'				$("command").onkeyup = function(evt) {',

+'					evt = getEvent(evt);',

+'					if (evt.keyCode == 27 && evt.preventDefault) { // Up',

+'						evt.preventDefault();',

+'						this.focus();',

+'					}',

+'				};',

+'',

+'				// Add document keyboard shortcuts',

+'				document.onkeydown = function keyEventHandler(evt) {',

+'					evt = getEvent(evt);',

+'					switch (evt.keyCode) {',

+'						case 69: // Ctrl + shift + E: re-execute last command',

+'							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',

+'								evalLastCommand();',

+'								cancelKeyEvent(evt);',

+'								return false;',

+'							}',

+'							break;',

+'						case 75: // Ctrl + shift + K: focus search',

+'							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',

+'								focusSearch();',

+'								cancelKeyEvent(evt);',

+'								return false;',

+'							}',

+'							break;',

+'						case 40: // Ctrl + shift + down arrow: focus command line',

+'						case 76: // Ctrl + shift + L: focus command line',

+'							if (evt.shiftKey && (evt.ctrlKey || evt.metaKey)) {',

+'								focusCommandLine();',

+'								cancelKeyEvent(evt);',

+'								return false;',

+'							}',

+'							break;',

+'					}',

+'				};',

+'',

+'				// Workaround to make sure log div starts at the correct size',

+'				setTimeout(setLogContainerHeight, 20);',

+'',

+'				setShowCommandLine(showCommandLine);',

+'				doSearch();',

+'			};',

+'',

+'			window.onunload = function() {',

+'				if (mainWindowExists()) {',

+'					appender.unload();',

+'				}',

+'				appender = null;',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function toggleLoggingEnabled() {',

+'				setLoggingEnabled($("enableLogging").checked);',

+'			}',

+'',

+'			function setLoggingEnabled(enable) {',

+'				loggingEnabled = enable;',

+'			}',

+'',

+'			var appender = null;',

+'',

+'			function setAppender(appenderParam) {',

+'				appender = appenderParam;',

+'			}',

+'',

+'			function setShowCloseButton(showCloseButton) {',

+'				$("closeButton").style.display = showCloseButton ? "inline" : "none";',

+'			}',

+'',

+'			function setShowHideButton(showHideButton) {',

+'				$("hideButton").style.display = showHideButton ? "inline" : "none";',

+'			}',

+'',

+'			var newestAtTop = false;',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function LogItemContentReverser() {',

+'			}',

+'			',

+'			LogItemContentReverser.prototype = new LogItemVisitor();',

+'			',

+'			LogItemContentReverser.prototype.visitGroup = function(group) {',

+'				group.reverseChildren();',

+'				this.visitChildren(group);',

+'			};',

+'',

+'			/*----------------------------------------------------------------*/',

+'',

+'			function setNewestAtTop(isNewestAtTop) {',

+'				var oldNewestAtTop = newestAtTop;',

+'				var i, iLen, j, jLen;',

+'				newestAtTop = Boolean(isNewestAtTop);',

+'				if (oldNewestAtTop != newestAtTop) {',

+'					var visitor = new LogItemContentReverser();',

+'					rootGroup.accept(visitor);',

+'',

+'					// Reassemble the matches array',

+'					if (currentSearch) {',

+'						var currentMatch = currentSearch.matches[currentMatchIndex];',

+'						var matchIndex = 0;',

+'						var matches = [];',

+'						var actOnLogEntry = function(logEntry) {',

+'							var logEntryMatches = logEntry.getSearchMatches();',

+'							for (j = 0, jLen = logEntryMatches.length; j < jLen; j++) {',

+'								matches[matchIndex] = logEntryMatches[j];',

+'								if (currentMatch && logEntryMatches[j].equals(currentMatch)) {',

+'									currentMatchIndex = matchIndex;',

+'								}',

+'								matchIndex++;',

+'							}',

+'						};',

+'						if (newestAtTop) {',

+'							for (i = logEntries.length - 1; i >= 0; i--) {',

+'								actOnLogEntry(logEntries[i]);',

+'							}',

+'						} else {',

+'							for (i = 0, iLen = logEntries.length; i < iLen; i++) {',

+'								actOnLogEntry(logEntries[i]);',

+'							}',

+'						}',

+'						currentSearch.matches = matches;',

+'						if (currentMatch) {',

+'							currentMatch.setCurrent();',

+'						}',

+'					} else if (scrollToLatest) {',

+'						doScrollToLatest();',

+'					}',

+'				}',

+'				$("newestAtTop").checked = isNewestAtTop;',

+'			}',

+'',

+'			function toggleNewestAtTop() {',

+'				var isNewestAtTop = $("newestAtTop").checked;',

+'				setNewestAtTop(isNewestAtTop);',

+'			}',

+'',

+'			var scrollToLatest = true;',

+'',

+'			function setScrollToLatest(isScrollToLatest) {',

+'				scrollToLatest = isScrollToLatest;',

+'				if (scrollToLatest) {',

+'					doScrollToLatest();',

+'				}',

+'				$("scrollToLatest").checked = isScrollToLatest;',

+'			}',

+'',

+'			function toggleScrollToLatest() {',

+'				var isScrollToLatest = $("scrollToLatest").checked;',

+'				setScrollToLatest(isScrollToLatest);',

+'			}',

+'',

+'			function doScrollToLatest() {',

+'				var l = logMainContainer;',

+'				if (typeof l.scrollTop != "undefined") {',

+'					if (newestAtTop) {',

+'						l.scrollTop = 0;',

+'					} else {',

+'						var latestLogEntry = l.lastChild;',

+'						if (latestLogEntry) {',

+'							l.scrollTop = l.scrollHeight;',

+'						}',

+'					}',

+'				}',

+'			}',

+'',

+'			var closeIfOpenerCloses = true;',

+'',

+'			function setCloseIfOpenerCloses(isCloseIfOpenerCloses) {',

+'				closeIfOpenerCloses = isCloseIfOpenerCloses;',

+'			}',

+'',

+'			var maxMessages = null;',

+'',

+'			function setMaxMessages(max) {',

+'				maxMessages = max;',

+'				pruneLogEntries();',

+'			}',

+'',

+'			var showCommandLine = false;',

+'',

+'			function setShowCommandLine(isShowCommandLine) {',

+'				showCommandLine = isShowCommandLine;',

+'				if (loaded) {',

+'					$("commandLine").style.display = showCommandLine ? "block" : "none";',

+'					setCommandInputWidth();',

+'					setLogContainerHeight();',

+'				}',

+'			}',

+'',

+'			function focusCommandLine() {',

+'				if (loaded) {',

+'					$("command").focus();',

+'				}',

+'			}',

+'',

+'			function focusSearch() {',

+'				if (loaded) {',

+'					$("searchBox").focus();',

+'				}',

+'			}',

+'',

+'			function getLogItems() {',

+'				var items = [];',

+'				for (var i = 0, len = logItems.length; i < len; i++) {',

+'					logItems[i].serialize(items);',

+'				}',

+'				return items;',

+'			}',

+'',

+'			function setLogItems(items) {',

+'				var loggingReallyEnabled = loggingEnabled;',

+'				// Temporarily turn logging on',

+'				loggingEnabled = true;',

+'				for (var i = 0, len = items.length; i < len; i++) {',

+'					switch (items[i][0]) {',

+'						case LogItem.serializedItemKeys.LOG_ENTRY:',

+'							log(items[i][1], items[i][2]);',

+'							break;',

+'						case LogItem.serializedItemKeys.GROUP_START:',

+'							group(items[i][1]);',

+'							break;',

+'						case LogItem.serializedItemKeys.GROUP_END:',

+'							groupEnd();',

+'							break;',

+'					}',

+'				}',

+'				loggingEnabled = loggingReallyEnabled;',

+'			}',

+'',

+'			function log(logLevel, formattedMessage) {',

+'				if (loggingEnabled) {',

+'					var logEntry = new LogEntry(logLevel, formattedMessage);',

+'					logEntries.push(logEntry);',

+'					logEntriesAndSeparators.push(logEntry);',

+'					logItems.push(logEntry);',

+'					currentGroup.addChild(logEntry);',

+'					if (loaded) {',

+'						if (logQueuedEventsTimer !== null) {',

+'							clearTimeout(logQueuedEventsTimer);',

+'						}',

+'						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);',

+'						unrenderedLogItemsExist = true;',

+'					}',

+'				}',

+'			}',

+'',

+'			function renderQueuedLogItems() {',

+'				logQueuedEventsTimer = null;',

+'				var pruned = pruneLogEntries();',

+'',

+'				// Render any unrendered log entries and apply the current search to them',

+'				var initiallyHasMatches = currentSearch ? currentSearch.hasMatches() : false;',

+'				for (var i = 0, len = logItems.length; i < len; i++) {',

+'					if (!logItems[i].rendered) {',

+'						logItems[i].render();',

+'						logItems[i].appendToLog();',

+'						if (currentSearch && (logItems[i] instanceof LogEntry)) {',

+'							currentSearch.applyTo(logItems[i]);',

+'						}',

+'					}',

+'				}',

+'				if (currentSearch) {',

+'					if (pruned) {',

+'						if (currentSearch.hasVisibleMatches()) {',

+'							if (currentMatchIndex === null) {',

+'								setCurrentMatchIndex(0);',

+'							}',

+'							displayMatches();',

+'						} else {',

+'							displayNoMatches();',

+'						}',

+'					} else if (!initiallyHasMatches && currentSearch.hasVisibleMatches()) {',

+'						setCurrentMatchIndex(0);',

+'						displayMatches();',

+'					}',

+'				}',

+'				if (scrollToLatest) {',

+'					doScrollToLatest();',

+'				}',

+'				unrenderedLogItemsExist = false;',

+'			}',

+'',

+'			function pruneLogEntries() {',

+'				if ((maxMessages !== null) && (logEntriesAndSeparators.length > maxMessages)) {',

+'					var numberToDelete = logEntriesAndSeparators.length - maxMessages;',

+'					var prunedLogEntries = logEntriesAndSeparators.slice(0, numberToDelete);',

+'					if (currentSearch) {',

+'						currentSearch.removeMatches(prunedLogEntries);',

+'					}',

+'					var group;',

+'					for (var i = 0; i < numberToDelete; i++) {',

+'						group = logEntriesAndSeparators[i].group;',

+'						array_remove(logItems, logEntriesAndSeparators[i]);',

+'						array_remove(logEntries, logEntriesAndSeparators[i]);',

+'						logEntriesAndSeparators[i].remove(true, true);',

+'						if (group.children.length === 0 && group !== currentGroup && group !== rootGroup) {',

+'							array_remove(logItems, group);',

+'							group.remove(true, true);',

+'						}',

+'					}',

+'					logEntriesAndSeparators = array_removeFromStart(logEntriesAndSeparators, numberToDelete);',

+'					return true;',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function group(name, startExpanded) {',

+'				if (loggingEnabled) {',

+'					initiallyExpanded = (typeof startExpanded === "undefined") ? true : Boolean(startExpanded);',

+'					var newGroup = new Group(name, false, initiallyExpanded);',

+'					currentGroup.addChild(newGroup);',

+'					currentGroup = newGroup;',

+'					logItems.push(newGroup);',

+'					if (loaded) {',

+'						if (logQueuedEventsTimer !== null) {',

+'							clearTimeout(logQueuedEventsTimer);',

+'						}',

+'						logQueuedEventsTimer = setTimeout(renderQueuedLogItems, renderDelay);',

+'						unrenderedLogItemsExist = true;',

+'					}',

+'				}',

+'			}',

+'',

+'			function groupEnd() {',

+'				currentGroup = (currentGroup === rootGroup) ? rootGroup : currentGroup.group;',

+'			}',

+'',

+'			function mainPageReloaded() {',

+'				currentGroup = rootGroup;',

+'				var separator = new Separator();',

+'				logEntriesAndSeparators.push(separator);',

+'				logItems.push(separator);',

+'				currentGroup.addChild(separator);',

+'			}',

+'',

+'			function closeWindow() {',

+'				if (appender && mainWindowExists()) {',

+'					appender.close(true);',

+'				} else {',

+'					window.close();',

+'				}',

+'			}',

+'',

+'			function hide() {',

+'				if (appender && mainWindowExists()) {',

+'					appender.hide();',

+'				}',

+'			}',

+'',

+'			var mainWindow = window;',

+'			var windowId = "log4javascriptConsoleWindow_" + new Date().getTime() + "_" + ("" + Math.random()).substr(2);',

+'',

+'			function setMainWindow(win) {',

+'				mainWindow = win;',

+'				mainWindow[windowId] = window;',

+'				// If this is a pop-up, poll the opener to see if it\'s closed',

+'				if (opener && closeIfOpenerCloses) {',

+'					pollOpener();',

+'				}',

+'			}',

+'',

+'			function pollOpener() {',

+'				if (closeIfOpenerCloses) {',

+'					if (mainWindowExists()) {',

+'						setTimeout(pollOpener, 500);',

+'					} else {',

+'						closeWindow();',

+'					}',

+'				}',

+'			}',

+'',

+'			function mainWindowExists() {',

+'				try {',

+'					return (mainWindow && !mainWindow.closed &&',

+'						mainWindow[windowId] == window);',

+'				} catch (ex) {}',

+'				return false;',

+'			}',

+'',

+'			var logLevels = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"];',

+'',

+'			function getCheckBox(logLevel) {',

+'				return $("switch_" + logLevel);',

+'			}',

+'',

+'			function getIeWrappedLogContainer() {',

+'				return $("log_wrapped");',

+'			}',

+'',

+'			function getIeUnwrappedLogContainer() {',

+'				return $("log_unwrapped");',

+'			}',

+'',

+'			function applyFilters() {',

+'				for (var i = 0; i < logLevels.length; i++) {',

+'					if (getCheckBox(logLevels[i]).checked) {',

+'						addClass(logMainContainer, logLevels[i]);',

+'					} else {',

+'						removeClass(logMainContainer, logLevels[i]);',

+'					}',

+'				}',

+'				updateSearchFromFilters();',

+'			}',

+'',

+'			function toggleAllLevels() {',

+'				var turnOn = $("switch_ALL").checked;',

+'				for (var i = 0; i < logLevels.length; i++) {',

+'					getCheckBox(logLevels[i]).checked = turnOn;',

+'					if (turnOn) {',

+'						addClass(logMainContainer, logLevels[i]);',

+'					} else {',

+'						removeClass(logMainContainer, logLevels[i]);',

+'					}',

+'				}',

+'			}',

+'',

+'			function checkAllLevels() {',

+'				for (var i = 0; i < logLevels.length; i++) {',

+'					if (!getCheckBox(logLevels[i]).checked) {',

+'						getCheckBox("ALL").checked = false;',

+'						return;',

+'					}',

+'				}',

+'				getCheckBox("ALL").checked = true;',

+'			}',

+'',

+'			function clearLog() {',

+'				rootGroup.clear();',

+'				currentGroup = rootGroup;',

+'				logEntries = [];',

+'				logItems = [];',

+'				logEntriesAndSeparators = [];',

+' 				doSearch();',

+'			}',

+'',

+'			function toggleWrap() {',

+'				var enable = $("wrap").checked;',

+'				if (enable) {',

+'					addClass(logMainContainer, "wrap");',

+'				} else {',

+'					removeClass(logMainContainer, "wrap");',

+'				}',

+'				refreshCurrentMatch();',

+'			}',

+'',

+'			/* ------------------------------------------------------------------- */',

+'',

+'			// Search',

+'',

+'			var searchTimer = null;',

+'',

+'			function scheduleSearch() {',

+'				try {',

+'					clearTimeout(searchTimer);',

+'				} catch (ex) {',

+'					// Do nothing',

+'				}',

+'				searchTimer = setTimeout(doSearch, 500);',

+'			}',

+'',

+'			function Search(searchTerm, isRegex, searchRegex, isCaseSensitive) {',

+'				this.searchTerm = searchTerm;',

+'				this.isRegex = isRegex;',

+'				this.searchRegex = searchRegex;',

+'				this.isCaseSensitive = isCaseSensitive;',

+'				this.matches = [];',

+'			}',

+'',

+'			Search.prototype = {',

+'				hasMatches: function() {',

+'					return this.matches.length > 0;',

+'				},',

+'',

+'				hasVisibleMatches: function() {',

+'					if (this.hasMatches()) {',

+'						for (var i = 0; i < this.matches.length; i++) {',

+'							if (this.matches[i].isVisible()) {',

+'								return true;',

+'							}',

+'						}',

+'					}',

+'					return false;',

+'				},',

+'',

+'				match: function(logEntry) {',

+'					var entryText = String(logEntry.formattedMessage);',

+'					var matchesSearch = false;',

+'					if (this.isRegex) {',

+'						matchesSearch = this.searchRegex.test(entryText);',

+'					} else if (this.isCaseSensitive) {',

+'						matchesSearch = (entryText.indexOf(this.searchTerm) > -1);',

+'					} else {',

+'						matchesSearch = (entryText.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1);',

+'					}',

+'					return matchesSearch;',

+'				},',

+'',

+'				getNextVisibleMatchIndex: function() {',

+'					for (var i = currentMatchIndex + 1; i < this.matches.length; i++) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					// Start again from the first match',

+'					for (i = 0; i <= currentMatchIndex; i++) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					return -1;',

+'				},',

+'',

+'				getPreviousVisibleMatchIndex: function() {',

+'					for (var i = currentMatchIndex - 1; i >= 0; i--) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					// Start again from the last match',

+'					for (var i = this.matches.length - 1; i >= currentMatchIndex; i--) {',

+'						if (this.matches[i].isVisible()) {',

+'							return i;',

+'						}',

+'					}',

+'					return -1;',

+'				},',

+'',

+'				applyTo: function(logEntry) {',

+'					var doesMatch = this.match(logEntry);',

+'					if (doesMatch) {',

+'						logEntry.group.expand();',

+'						logEntry.setSearchMatch(true);',

+'						var logEntryContent;',

+'						var wrappedLogEntryContent;',

+'						var searchTermReplacementStartTag = "<span class=\\\"searchterm\\\">";',

+'						var searchTermReplacementEndTag = "<" + "/span>";',

+'						var preTagName = isIe ? "pre" : "span";',

+'						var preStartTag = "<" + preTagName + " class=\\\"pre\\\">";',

+'						var preEndTag = "<" + "/" + preTagName + ">";',

+'						var startIndex = 0;',

+'						var searchIndex, matchedText, textBeforeMatch;',

+'						if (this.isRegex) {',

+'							var flags = this.isCaseSensitive ? "g" : "gi";',

+'							var capturingRegex = new RegExp("(" + this.searchRegex.source + ")", flags);',

+'',

+'							// Replace the search term with temporary tokens for the start and end tags',

+'							var rnd = ("" + Math.random()).substr(2);',

+'							var startToken = "%%s" + rnd + "%%";',

+'							var endToken = "%%e" + rnd + "%%";',

+'							logEntryContent = logEntry.formattedMessage.replace(capturingRegex, startToken + "$1" + endToken);',

+'',

+'							// Escape the HTML to get rid of angle brackets',

+'							logEntryContent = escapeHtml(logEntryContent);',

+'',

+'							// Substitute the proper HTML back in for the search match',

+'							var result;',

+'							var searchString = logEntryContent;',

+'							logEntryContent = "";',

+'							wrappedLogEntryContent = "";',

+'							while ((searchIndex = searchString.indexOf(startToken, startIndex)) > -1) {',

+'								var endTokenIndex = searchString.indexOf(endToken, searchIndex);',

+'								matchedText = searchString.substring(searchIndex + startToken.length, endTokenIndex);',

+'								textBeforeMatch = searchString.substring(startIndex, searchIndex);',

+'								logEntryContent += preStartTag + textBeforeMatch + preEndTag;',

+'								logEntryContent += searchTermReplacementStartTag + preStartTag + matchedText +',

+'									preEndTag + searchTermReplacementEndTag;',

+'								if (isIe) {',

+'									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +',

+'										matchedText + searchTermReplacementEndTag;',

+'								}',

+'								startIndex = endTokenIndex + endToken.length;',

+'							}',

+'							logEntryContent += preStartTag + searchString.substr(startIndex) + preEndTag;',

+'							if (isIe) {',

+'								wrappedLogEntryContent += searchString.substr(startIndex);',

+'							}',

+'						} else {',

+'							logEntryContent = "";',

+'							wrappedLogEntryContent = "";',

+'							var searchTermReplacementLength = searchTermReplacementStartTag.length +',

+'								this.searchTerm.length + searchTermReplacementEndTag.length;',

+'							var searchTermLength = this.searchTerm.length;',

+'							var searchTermLowerCase = this.searchTerm.toLowerCase();',

+'							var logTextLowerCase = logEntry.formattedMessage.toLowerCase();',

+'							while ((searchIndex = logTextLowerCase.indexOf(searchTermLowerCase, startIndex)) > -1) {',

+'								matchedText = escapeHtml(logEntry.formattedMessage.substr(searchIndex, this.searchTerm.length));',

+'								textBeforeMatch = escapeHtml(logEntry.formattedMessage.substring(startIndex, searchIndex));',

+'								var searchTermReplacement = searchTermReplacementStartTag +',

+'									preStartTag + matchedText + preEndTag + searchTermReplacementEndTag;',

+'								logEntryContent += preStartTag + textBeforeMatch + preEndTag + searchTermReplacement;',

+'								if (isIe) {',

+'									wrappedLogEntryContent += textBeforeMatch + searchTermReplacementStartTag +',

+'										matchedText + searchTermReplacementEndTag;',

+'								}',

+'								startIndex = searchIndex + searchTermLength;',

+'							}',

+'							var textAfterLastMatch = escapeHtml(logEntry.formattedMessage.substr(startIndex));',

+'							logEntryContent += preStartTag + textAfterLastMatch + preEndTag;',

+'							if (isIe) {',

+'								wrappedLogEntryContent += textAfterLastMatch;',

+'							}',

+'						}',

+'						logEntry.setContent(logEntryContent, wrappedLogEntryContent);',

+'						var logEntryMatches = logEntry.getSearchMatches();',

+'						this.matches = this.matches.concat(logEntryMatches);',

+'					} else {',

+'						logEntry.setSearchMatch(false);',

+'						logEntry.setContent(logEntry.formattedMessage, logEntry.formattedMessage);',

+'					}',

+'					return doesMatch;',

+'				},',

+'',

+'				removeMatches: function(logEntries) {',

+'					var matchesToRemoveCount = 0;',

+'					var currentMatchRemoved = false;',

+'					var matchesToRemove = [];',

+'					var i, iLen, j, jLen;',

+'',

+'					// Establish the list of matches to be removed',

+'					for (i = 0, iLen = this.matches.length; i < iLen; i++) {',

+'						for (j = 0, jLen = logEntries.length; j < jLen; j++) {',

+'							if (this.matches[i].belongsTo(logEntries[j])) {',

+'								matchesToRemove.push(this.matches[i]);',

+'								if (i === currentMatchIndex) {',

+'									currentMatchRemoved = true;',

+'								}',

+'							}',

+'						}',

+'					}',

+'',

+'					// Set the new current match index if the current match has been deleted',

+'					// This will be the first match that appears after the first log entry being',

+'					// deleted, if one exists; otherwise, it\'s the first match overall',

+'					var newMatch = currentMatchRemoved ? null : this.matches[currentMatchIndex];',

+'					if (currentMatchRemoved) {',

+'						for (i = currentMatchIndex, iLen = this.matches.length; i < iLen; i++) {',

+'							if (this.matches[i].isVisible() && !array_contains(matchesToRemove, this.matches[i])) {',

+'								newMatch = this.matches[i];',

+'								break;',

+'							}',

+'						}',

+'					}',

+'',

+'					// Remove the matches',

+'					for (i = 0, iLen = matchesToRemove.length; i < iLen; i++) {',

+'						array_remove(this.matches, matchesToRemove[i]);',

+'						matchesToRemove[i].remove();',

+'					}',

+'',

+'					// Set the new match, if one exists',

+'					if (this.hasVisibleMatches()) {',

+'						if (newMatch === null) {',

+'							setCurrentMatchIndex(0);',

+'						} else {',

+'							// Get the index of the new match',

+'							var newMatchIndex = 0;',

+'							for (i = 0, iLen = this.matches.length; i < iLen; i++) {',

+'								if (newMatch === this.matches[i]) {',

+'									newMatchIndex = i;',

+'									break;',

+'								}',

+'							}',

+'							setCurrentMatchIndex(newMatchIndex);',

+'						}',

+'					} else {',

+'						currentMatchIndex = null;',

+'						displayNoMatches();',

+'					}',

+'				}',

+'			};',

+'',

+'			function getPageOffsetTop(el, container) {',

+'				var currentEl = el;',

+'				var y = 0;',

+'				while (currentEl && currentEl != container) {',

+'					y += currentEl.offsetTop;',

+'					currentEl = currentEl.offsetParent;',

+'				}',

+'				return y;',

+'			}',

+'',

+'			function scrollIntoView(el) {',

+'				var logContainer = logMainContainer;',

+'				// Check if the whole width of the element is visible and centre if not',

+'				if (!$("wrap").checked) {',

+'					var logContainerLeft = logContainer.scrollLeft;',

+'					var logContainerRight = logContainerLeft  + logContainer.offsetWidth;',

+'					var elLeft = el.offsetLeft;',

+'					var elRight = elLeft + el.offsetWidth;',

+'					if (elLeft < logContainerLeft || elRight > logContainerRight) {',

+'						logContainer.scrollLeft = elLeft - (logContainer.offsetWidth - el.offsetWidth) / 2;',

+'					}',

+'				}',

+'				// Check if the whole height of the element is visible and centre if not',

+'				var logContainerTop = logContainer.scrollTop;',

+'				var logContainerBottom = logContainerTop  + logContainer.offsetHeight;',

+'				var elTop = getPageOffsetTop(el) - getToolBarsHeight();',

+'				var elBottom = elTop + el.offsetHeight;',

+'				if (elTop < logContainerTop || elBottom > logContainerBottom) {',

+'					logContainer.scrollTop = elTop - (logContainer.offsetHeight - el.offsetHeight) / 2;',

+'				}',

+'			}',

+'',

+'			function Match(logEntryLevel, spanInMainDiv, spanInUnwrappedPre, spanInWrappedDiv) {',

+'				this.logEntryLevel = logEntryLevel;',

+'				this.spanInMainDiv = spanInMainDiv;',

+'				if (isIe) {',

+'					this.spanInUnwrappedPre = spanInUnwrappedPre;',

+'					this.spanInWrappedDiv = spanInWrappedDiv;',

+'				}',

+'				this.mainSpan = isIe ? spanInUnwrappedPre : spanInMainDiv;',

+'			}',

+'',

+'			Match.prototype = {',

+'				equals: function(match) {',

+'					return this.mainSpan === match.mainSpan;',

+'				},',

+'',

+'				setCurrent: function() {',

+'					if (isIe) {',

+'						addClass(this.spanInUnwrappedPre, "currentmatch");',

+'						addClass(this.spanInWrappedDiv, "currentmatch");',

+'						// Scroll the visible one into view',

+'						var elementToScroll = $("wrap").checked ? this.spanInWrappedDiv : this.spanInUnwrappedPre;',

+'						scrollIntoView(elementToScroll);',

+'					} else {',

+'						addClass(this.spanInMainDiv, "currentmatch");',

+'						scrollIntoView(this.spanInMainDiv);',

+'					}',

+'				},',

+'',

+'				belongsTo: function(logEntry) {',

+'					if (isIe) {',

+'						return isDescendant(this.spanInUnwrappedPre, logEntry.unwrappedPre);',

+'					} else {',

+'						return isDescendant(this.spanInMainDiv, logEntry.mainDiv);',

+'					}',

+'				},',

+'',

+'				setNotCurrent: function() {',

+'					if (isIe) {',

+'						removeClass(this.spanInUnwrappedPre, "currentmatch");',

+'						removeClass(this.spanInWrappedDiv, "currentmatch");',

+'					} else {',

+'						removeClass(this.spanInMainDiv, "currentmatch");',

+'					}',

+'				},',

+'',

+'				isOrphan: function() {',

+'					return isOrphan(this.mainSpan);',

+'				},',

+'',

+'				isVisible: function() {',

+'					return getCheckBox(this.logEntryLevel).checked;',

+'				},',

+'',

+'				remove: function() {',

+'					if (isIe) {',

+'						this.spanInUnwrappedPre = null;',

+'						this.spanInWrappedDiv = null;',

+'					} else {',

+'						this.spanInMainDiv = null;',

+'					}',

+'				}',

+'			};',

+'',

+'			var currentSearch = null;',

+'			var currentMatchIndex = null;',

+'',

+'			function doSearch() {',

+'				var searchBox = $("searchBox");',

+'				var searchTerm = searchBox.value;',

+'				var isRegex = $("searchRegex").checked;',

+'				var isCaseSensitive = $("searchCaseSensitive").checked;',

+'				var i;',

+'',

+'				if (searchTerm === "") {',

+'					$("searchReset").disabled = true;',

+'					$("searchNav").style.display = "none";',

+'					removeClass(document.body, "searching");',

+'					removeClass(searchBox, "hasmatches");',

+'					removeClass(searchBox, "nomatches");',

+'					for (i = 0; i < logEntries.length; i++) {',

+'						logEntries[i].clearSearch();',

+'						logEntries[i].setContent(logEntries[i].formattedMessage, logEntries[i].formattedMessage);',

+'					}',

+'					currentSearch = null;',

+'					setLogContainerHeight();',

+'				} else {',

+'					$("searchReset").disabled = false;',

+'					$("searchNav").style.display = "block";',

+'					var searchRegex;',

+'					var regexValid;',

+'					if (isRegex) {',

+'						try {',

+'							searchRegex = isCaseSensitive ? new RegExp(searchTerm, "g") : new RegExp(searchTerm, "gi");',

+'							regexValid = true;',

+'							replaceClass(searchBox, "validregex", "invalidregex");',

+'							searchBox.title = "Valid regex";',

+'						} catch (ex) {',

+'							regexValid = false;',

+'							replaceClass(searchBox, "invalidregex", "validregex");',

+'							searchBox.title = "Invalid regex: " + (ex.message ? ex.message : (ex.description ? ex.description : "unknown error"));',

+'							return;',

+'						}',

+'					} else {',

+'						searchBox.title = "";',

+'						removeClass(searchBox, "validregex");',

+'						removeClass(searchBox, "invalidregex");',

+'					}',

+'					addClass(document.body, "searching");',

+'					currentSearch = new Search(searchTerm, isRegex, searchRegex, isCaseSensitive);',

+'					for (i = 0; i < logEntries.length; i++) {',

+'						currentSearch.applyTo(logEntries[i]);',

+'					}',

+'					setLogContainerHeight();',

+'',

+'					// Highlight the first search match',

+'					if (currentSearch.hasVisibleMatches()) {',

+'						setCurrentMatchIndex(0);',

+'						displayMatches();',

+'					} else {',

+'						displayNoMatches();',

+'					}',

+'				}',

+'			}',

+'',

+'			function updateSearchFromFilters() {',

+'				if (currentSearch) {',

+'					if (currentSearch.hasMatches()) {',

+'						if (currentMatchIndex === null) {',

+'							currentMatchIndex = 0;',

+'						}',

+'						var currentMatch = currentSearch.matches[currentMatchIndex];',

+'						if (currentMatch.isVisible()) {',

+'							displayMatches();',

+'							setCurrentMatchIndex(currentMatchIndex);',

+'						} else {',

+'							currentMatch.setNotCurrent();',

+'							// Find the next visible match, if one exists',

+'							var nextVisibleMatchIndex = currentSearch.getNextVisibleMatchIndex();',

+'							if (nextVisibleMatchIndex > -1) {',

+'								setCurrentMatchIndex(nextVisibleMatchIndex);',

+'								displayMatches();',

+'							} else {',

+'								displayNoMatches();',

+'							}',

+'						}',

+'					} else {',

+'						displayNoMatches();',

+'					}',

+'				}',

+'			}',

+'',

+'			function refreshCurrentMatch() {',

+'				if (currentSearch && currentSearch.hasVisibleMatches()) {',

+'					setCurrentMatchIndex(currentMatchIndex);',

+'				}',

+'			}',

+'',

+'			function displayMatches() {',

+'				replaceClass($("searchBox"), "hasmatches", "nomatches");',

+'				$("searchBox").title = "" + currentSearch.matches.length + " matches found";',

+'				$("searchNav").style.display = "block";',

+'				setLogContainerHeight();',

+'			}',

+'',

+'			function displayNoMatches() {',

+'				replaceClass($("searchBox"), "nomatches", "hasmatches");',

+'				$("searchBox").title = "No matches found";',

+'				$("searchNav").style.display = "none";',

+'				setLogContainerHeight();',

+'			}',

+'',

+'			function toggleSearchEnabled(enable) {',

+'				enable = (typeof enable == "undefined") ? !$("searchDisable").checked : enable;',

+'				$("searchBox").disabled = !enable;',

+'				$("searchReset").disabled = !enable;',

+'				$("searchRegex").disabled = !enable;',

+'				$("searchNext").disabled = !enable;',

+'				$("searchPrevious").disabled = !enable;',

+'				$("searchCaseSensitive").disabled = !enable;',

+'				$("searchNav").style.display = (enable && ($("searchBox").value !== "") &&',

+'						currentSearch && currentSearch.hasVisibleMatches()) ?',

+'					"block" : "none";',

+'				if (enable) {',

+'					removeClass($("search"), "greyedout");',

+'					addClass(document.body, "searching");',

+'					if ($("searchHighlight").checked) {',

+'						addClass(logMainContainer, "searchhighlight");',

+'					} else {',

+'						removeClass(logMainContainer, "searchhighlight");',

+'					}',

+'					if ($("searchFilter").checked) {',

+'						addClass(logMainContainer, "searchfilter");',

+'					} else {',

+'						removeClass(logMainContainer, "searchfilter");',

+'					}',

+'					$("searchDisable").checked = !enable;',

+'				} else {',

+'					addClass($("search"), "greyedout");',

+'					removeClass(document.body, "searching");',

+'					removeClass(logMainContainer, "searchhighlight");',

+'					removeClass(logMainContainer, "searchfilter");',

+'				}',

+'				setLogContainerHeight();',

+'			}',

+'',

+'			function toggleSearchFilter() {',

+'				var enable = $("searchFilter").checked;',

+'				if (enable) {',

+'					addClass(logMainContainer, "searchfilter");',

+'				} else {',

+'					removeClass(logMainContainer, "searchfilter");',

+'				}',

+'				refreshCurrentMatch();',

+'			}',

+'',

+'			function toggleSearchHighlight() {',

+'				var enable = $("searchHighlight").checked;',

+'				if (enable) {',

+'					addClass(logMainContainer, "searchhighlight");',

+'				} else {',

+'					removeClass(logMainContainer, "searchhighlight");',

+'				}',

+'			}',

+'',

+'			function clearSearch() {',

+'				$("searchBox").value = "";',

+'				doSearch();',

+'			}',

+'',

+'			function searchNext() {',

+'				if (currentSearch !== null && currentMatchIndex !== null) {',

+'					currentSearch.matches[currentMatchIndex].setNotCurrent();',

+'					var nextMatchIndex = currentSearch.getNextVisibleMatchIndex();',

+'					if (nextMatchIndex > currentMatchIndex || confirm("Reached the end of the page. Start from the top?")) {',

+'						setCurrentMatchIndex(nextMatchIndex);',

+'					}',

+'				}',

+'			}',

+'',

+'			function searchPrevious() {',

+'				if (currentSearch !== null && currentMatchIndex !== null) {',

+'					currentSearch.matches[currentMatchIndex].setNotCurrent();',

+'					var previousMatchIndex = currentSearch.getPreviousVisibleMatchIndex();',

+'					if (previousMatchIndex < currentMatchIndex || confirm("Reached the start of the page. Continue from the bottom?")) {',

+'						setCurrentMatchIndex(previousMatchIndex);',

+'					}',

+'				}',

+'			}',

+'',

+'			function setCurrentMatchIndex(index) {',

+'				currentMatchIndex = index;',

+'				currentSearch.matches[currentMatchIndex].setCurrent();',

+'			}',

+'',

+'			/* ------------------------------------------------------------------------- */',

+'',

+'			// CSS Utilities',

+'',

+'			function addClass(el, cssClass) {',

+'				if (!hasClass(el, cssClass)) {',

+'					if (el.className) {',

+'						el.className += " " + cssClass;',

+'					} else {',

+'						el.className = cssClass;',

+'					}',

+'				}',

+'			}',

+'',

+'			function hasClass(el, cssClass) {',

+'				if (el.className) {',

+'					var classNames = el.className.split(" ");',

+'					return array_contains(classNames, cssClass);',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function removeClass(el, cssClass) {',

+'				if (hasClass(el, cssClass)) {',

+'					// Rebuild the className property',

+'					var existingClasses = el.className.split(" ");',

+'					var newClasses = [];',

+'					for (var i = 0, len = existingClasses.length; i < len; i++) {',

+'						if (existingClasses[i] != cssClass) {',

+'							newClasses[newClasses.length] = existingClasses[i];',

+'						}',

+'					}',

+'					el.className = newClasses.join(" ");',

+'				}',

+'			}',

+'',

+'			function replaceClass(el, newCssClass, oldCssClass) {',

+'				removeClass(el, oldCssClass);',

+'				addClass(el, newCssClass);',

+'			}',

+'',

+'			/* ------------------------------------------------------------------------- */',

+'',

+'			// Other utility functions',

+'',

+'			function getElementsByClass(el, cssClass, tagName) {',

+'				var elements = el.getElementsByTagName(tagName);',

+'				var matches = [];',

+'				for (var i = 0, len = elements.length; i < len; i++) {',

+'					if (hasClass(elements[i], cssClass)) {',

+'						matches.push(elements[i]);',

+'					}',

+'				}',

+'				return matches;',

+'			}',

+'',

+'			// Syntax borrowed from Prototype library',

+'			function $(id) {',

+'				return document.getElementById(id);',

+'			}',

+'',

+'			function isDescendant(node, ancestorNode) {',

+'				while (node != null) {',

+'					if (node === ancestorNode) {',

+'						return true;',

+'					}',

+'					node = node.parentNode;',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function isOrphan(node) {',

+'				var currentNode = node;',

+'				while (currentNode) {',

+'					if (currentNode == document.body) {',

+'						return false;',

+'					}',

+'					currentNode = currentNode.parentNode;',

+'				}',

+'				return true;',

+'			}',

+'',

+'			function escapeHtml(str) {',

+'				return str.replace(/&/g, "&amp;").replace(/[<]/g, "&lt;").replace(/>/g, "&gt;");',

+'			}',

+'',

+'			function getWindowWidth() {',

+'				if (window.innerWidth) {',

+'					return window.innerWidth;',

+'				} else if (document.documentElement && document.documentElement.clientWidth) {',

+'					return document.documentElement.clientWidth;',

+'				} else if (document.body) {',

+'					return document.body.clientWidth;',

+'				}',

+'				return 0;',

+'			}',

+'',

+'			function getWindowHeight() {',

+'				if (window.innerHeight) {',

+'					return window.innerHeight;',

+'				} else if (document.documentElement && document.documentElement.clientHeight) {',

+'					return document.documentElement.clientHeight;',

+'				} else if (document.body) {',

+'					return document.body.clientHeight;',

+'				}',

+'				return 0;',

+'			}',

+'',

+'			function getToolBarsHeight() {',

+'				return $("switches").offsetHeight;',

+'			}',

+'',

+'			function getChromeHeight() {',

+'				var height = getToolBarsHeight();',

+'				if (showCommandLine) {',

+'					height += $("commandLine").offsetHeight;',

+'				}',

+'				return height;',

+'			}',

+'',

+'			function setLogContainerHeight() {',

+'				if (logMainContainer) {',

+'					var windowHeight = getWindowHeight();',

+'					$("body").style.height = getWindowHeight() + "px";',

+'					logMainContainer.style.height = "" +',

+'						Math.max(0, windowHeight - getChromeHeight()) + "px";',

+'				}',

+'			}',

+'',

+'			function setCommandInputWidth() {',

+'				if (showCommandLine) {',

+'					$("command").style.width = "" + Math.max(0, $("commandLineContainer").offsetWidth -',

+'						($("evaluateButton").offsetWidth + 13)) + "px";',

+'				}',

+'			}',

+'',

+'			window.onresize = function() {',

+'				setCommandInputWidth();',

+'				setLogContainerHeight();',

+'			};',

+'',

+'			if (!Array.prototype.push) {',

+'				Array.prototype.push = function() {',

+'			        for (var i = 0, len = arguments.length; i < len; i++){',

+'			            this[this.length] = arguments[i];',

+'			        }',

+'			        return this.length;',

+'				};',

+'			}',

+'',

+'			if (!Array.prototype.pop) {',

+'				Array.prototype.pop = function() {',

+'					if (this.length > 0) {',

+'						var val = this[this.length - 1];',

+'						this.length = this.length - 1;',

+'						return val;',

+'					}',

+'				};',

+'			}',

+'',

+'			if (!Array.prototype.shift) {',

+'				Array.prototype.shift = function() {',

+'					if (this.length > 0) {',

+'						var firstItem = this[0];',

+'						for (var i = 0, len = this.length - 1; i < len; i++) {',

+'							this[i] = this[i + 1];',

+'						}',

+'						this.length = this.length - 1;',

+'						return firstItem;',

+'					}',

+'				};',

+'			}',

+'',

+'			if (!Array.prototype.splice) {',

+'				Array.prototype.splice = function(startIndex, deleteCount) {',

+'					var itemsAfterDeleted = this.slice(startIndex + deleteCount);',

+'					var itemsDeleted = this.slice(startIndex, startIndex + deleteCount);',

+'					this.length = startIndex;',

+'					// Copy the arguments into a proper Array object',

+'					var argumentsArray = [];',

+'					for (var i = 0, len = arguments.length; i < len; i++) {',

+'						argumentsArray[i] = arguments[i];',

+'					}',

+'					var itemsToAppend = (argumentsArray.length > 2) ?',

+'						itemsAfterDeleted = argumentsArray.slice(2).concat(itemsAfterDeleted) : itemsAfterDeleted;',

+'					for (i = 0, len = itemsToAppend.length; i < len; i++) {',

+'						this.push(itemsToAppend[i]);',

+'					}',

+'					return itemsDeleted;',

+'				};',

+'			}',

+'',

+'			function array_remove(arr, val) {',

+'				var index = -1;',

+'				for (var i = 0, len = arr.length; i < len; i++) {',

+'					if (arr[i] === val) {',

+'						index = i;',

+'						break;',

+'					}',

+'				}',

+'				if (index >= 0) {',

+'					arr.splice(index, 1);',

+'					return index;',

+'				} else {',

+'					return false;',

+'				}',

+'			}',

+'',

+'			function array_removeFromStart(array, numberToRemove) {',

+'				if (Array.prototype.splice) {',

+'					array.splice(0, numberToRemove);',

+'				} else {',

+'					for (var i = numberToRemove, len = array.length; i < len; i++) {',

+'						array[i - numberToRemove] = array[i];',

+'					}',

+'					array.length = array.length - numberToRemove;',

+'				}',

+'				return array;',

+'			}',

+'',

+'			function array_contains(arr, val) {',

+'				for (var i = 0, len = arr.length; i < len; i++) {',

+'					if (arr[i] == val) {',

+'						return true;',

+'					}',

+'				}',

+'				return false;',

+'			}',

+'',

+'			function getErrorMessage(ex) {',

+'				if (ex.message) {',

+'					return ex.message;',

+'				} else if (ex.description) {',

+'					return ex.description;',

+'				}',

+'				return "" + ex;',

+'			}',

+'',

+'			function moveCaretToEnd(input) {',

+'				if (input.setSelectionRange) {',

+'					input.focus();',

+'					var length = input.value.length;',

+'					input.setSelectionRange(length, length);',

+'				} else if (input.createTextRange) {',

+'					var range = input.createTextRange();',

+'					range.collapse(false);',

+'					range.select();',

+'				}',

+'				input.focus();',

+'			}',

+'',

+'			function stopPropagation(evt) {',

+'				if (evt.stopPropagation) {',

+'					evt.stopPropagation();',

+'				} else if (typeof evt.cancelBubble != "undefined") {',

+'					evt.cancelBubble = true;',

+'				}',

+'			}',

+'',

+'			function getEvent(evt) {',

+'				return evt ? evt : event;',

+'			}',

+'',

+'			function getTarget(evt) {',

+'				return evt.target ? evt.target : evt.srcElement;',

+'			}',

+'',

+'			function getRelatedTarget(evt) {',

+'				if (evt.relatedTarget) {',

+'					return evt.relatedTarget;',

+'				} else if (evt.srcElement) {',

+'					switch(evt.type) {',

+'						case "mouseover":',

+'							return evt.fromElement;',

+'						case "mouseout":',

+'							return evt.toElement;',

+'						default:',

+'							return evt.srcElement;',

+'					}',

+'				}',

+'			}',

+'',

+'			function cancelKeyEvent(evt) {',

+'				evt.returnValue = false;',

+'				stopPropagation(evt);',

+'			}',

+'',

+'			function evalCommandLine() {',

+'				var expr = $("command").value;',

+'				evalCommand(expr);',

+'				$("command").value = "";',

+'			}',

+'',

+'			function evalLastCommand() {',

+'				if (lastCommand != null) {',

+'					evalCommand(lastCommand);',

+'				}',

+'			}',

+'',

+'			var lastCommand = null;',

+'			var commandHistory = [];',

+'			var currentCommandIndex = 0;',

+'',

+'			function evalCommand(expr) {',

+'				if (appender) {',

+'					appender.evalCommandAndAppend(expr);',

+'				} else {',

+'					var prefix = ">>> " + expr + "\\r\\n";',

+'					try {',

+'						log("INFO", prefix + eval(expr));',

+'					} catch (ex) {',

+'						log("ERROR", prefix + "Error: " + getErrorMessage(ex));',

+'					}',

+'				}',

+'				// Update command history',

+'				if (expr != commandHistory[commandHistory.length - 1]) {',

+'					commandHistory.push(expr);',

+'					// Update the appender',

+'					if (appender) {',

+'						appender.storeCommandHistory(commandHistory);',

+'					}',

+'				}',

+'				currentCommandIndex = (expr == commandHistory[currentCommandIndex]) ? currentCommandIndex + 1 : commandHistory.length;',

+'				lastCommand = expr;',

+'			}',

+'			//]]>',

+'		</script>',

+'		<style type="text/css">',

+'			body {',

+'				background-color: white;',

+'				color: black;',

+'				padding: 0;',

+'				margin: 0;',

+'				font-family: tahoma, verdana, arial, helvetica, sans-serif;',

+'				overflow: hidden;',

+'			}',

+'',

+'			div#switchesContainer input {',

+'				margin-bottom: 0;',

+'			}',

+'',

+'			div.toolbar {',

+'				border-top: solid #ffffff 1px;',

+'				border-bottom: solid #aca899 1px;',

+'				background-color: #f1efe7;',

+'				padding: 3px 5px;',

+'				font-size: 68.75%;',

+'			}',

+'',

+'			div.toolbar, div#search input {',

+'				font-family: tahoma, verdana, arial, helvetica, sans-serif;',

+'			}',

+'',

+'			div.toolbar input.button {',

+'				padding: 0 5px;',

+'				font-size: 100%;',

+'			}',

+'',

+'			div.toolbar input.hidden {',

+'				display: none;',

+'			}',

+'',

+'			div#switches input#clearButton {',

+'				margin-left: 20px;',

+'			}',

+'',

+'			div#levels label {',

+'				font-weight: bold;',

+'			}',

+'',

+'			div#levels label, div#options label {',

+'				margin-right: 5px;',

+'			}',

+'',

+'			div#levels label#wrapLabel {',

+'				font-weight: normal;',

+'			}',

+'',

+'			div#search label {',

+'				margin-right: 10px;',

+'			}',

+'',

+'			div#search label.searchboxlabel {',

+'				margin-right: 0;',

+'			}',

+'',

+'			div#search input {',

+'				font-size: 100%;',

+'			}',

+'',

+'			div#search input.validregex {',

+'				color: green;',

+'			}',

+'',

+'			div#search input.invalidregex {',

+'				color: red;',

+'			}',

+'',

+'			div#search input.nomatches {',

+'				color: white;',

+'				background-color: #ff6666;',

+'			}',

+'',

+'			div#search input.nomatches {',

+'				color: white;',

+'				background-color: #ff6666;',

+'			}',

+'',

+'			div#searchNav {',

+'				display: none;',

+'			}',

+'',

+'			div#commandLine {',

+'				display: none;',

+'			}',

+'',

+'			div#commandLine input#command {',

+'				font-size: 100%;',

+'				font-family: Courier New, Courier;',

+'			}',

+'',

+'			div#commandLine input#evaluateButton {',

+'			}',

+'',

+'			*.greyedout {',

+'				color: gray !important;',

+'				border-color: gray !important;',

+'			}',

+'',

+'			*.greyedout *.alwaysenabled { color: black; }',

+'',

+'			*.unselectable {',

+'				-khtml-user-select: none;',

+'				-moz-user-select: none;',

+'				user-select: none;',

+'			}',

+'',

+'			div#log {',

+'				font-family: Courier New, Courier;',

+'				font-size: 75%;',

+'				width: 100%;',

+'				overflow: auto;',

+'				clear: both;',

+'				position: relative;',

+'			}',

+'',

+'			div.group {',

+'				border-color: #cccccc;',

+'				border-style: solid;',

+'				border-width: 1px 0 1px 1px;',

+'				overflow: visible;',

+'			}',

+'',

+'			div.oldIe div.group, div.oldIe div.group *, div.oldIe *.logentry {',

+'				height: 1%;',

+'			}',

+'',

+'			div.group div.groupheading span.expander {',

+'				border: solid black 1px;',

+'				font-family: Courier New, Courier;',

+'				font-size: 0.833em;',

+'				background-color: #eeeeee;',

+'				position: relative;',

+'				top: -1px;',

+'				color: black;',

+'				padding: 0 2px;',

+'				cursor: pointer;',

+'				cursor: hand;',

+'				height: 1%;',

+'			}',

+'',

+'			div.group div.groupcontent {',

+'				margin-left: 10px;',

+'				padding-bottom: 2px;',

+'				overflow: visible;',

+'			}',

+'',

+'			div.group div.expanded {',

+'				display: block;',

+'			}',

+'',

+'			div.group div.collapsed {',

+'				display: none;',

+'			}',

+'',

+'			*.logentry {',

+'				overflow: visible;',

+'				display: none;',

+'				white-space: pre;',

+'			}',

+'',

+'			span.pre {',

+'				white-space: pre;',

+'			}',

+'			',

+'			pre.unwrapped {',

+'				display: inline !important;',

+'			}',

+'',

+'			pre.unwrapped pre.pre, div.wrapped pre.pre {',

+'				display: inline;',

+'			}',

+'',

+'			div.wrapped pre.pre {',

+'				white-space: normal;',

+'			}',

+'',

+'			div.wrapped {',

+'				display: none;',

+'			}',

+'',

+'			body.searching *.logentry span.currentmatch {',

+'				color: white !important;',

+'				background-color: green !important;',

+'			}',

+'',

+'			body.searching div.searchhighlight *.logentry span.searchterm {',

+'				color: black;',

+'				background-color: yellow;',

+'			}',

+'',

+'			div.wrap *.logentry {',

+'				white-space: normal !important;',

+'				border-width: 0 0 1px 0;',

+'				border-color: #dddddd;',

+'				border-style: dotted;',

+'			}',

+'',

+'			div.wrap #log_wrapped, #log_unwrapped {',

+'				display: block;',

+'			}',

+'',

+'			div.wrap #log_unwrapped, #log_wrapped {',

+'				display: none;',

+'			}',

+'',

+'			div.wrap *.logentry span.pre {',

+'				overflow: visible;',

+'				white-space: normal;',

+'			}',

+'',

+'			div.wrap *.logentry pre.unwrapped {',

+'				display: none;',

+'			}',

+'',

+'			div.wrap *.logentry span.wrapped {',

+'				display: inline;',

+'			}',

+'',

+'			div.searchfilter *.searchnonmatch {',

+'				display: none !important;',

+'			}',

+'',

+'			div#log *.TRACE, label#label_TRACE {',

+'				color: #666666;',

+'			}',

+'',

+'			div#log *.DEBUG, label#label_DEBUG {',

+'				color: green;',

+'			}',

+'',

+'			div#log *.INFO, label#label_INFO {',

+'				color: #000099;',

+'			}',

+'',

+'			div#log *.WARN, label#label_WARN {',

+'				color: #999900;',

+'			}',

+'',

+'			div#log *.ERROR, label#label_ERROR {',

+'				color: red;',

+'			}',

+'',

+'			div#log *.FATAL, label#label_FATAL {',

+'				color: #660066;',

+'			}',

+'',

+'			div.TRACE#log *.TRACE,',

+'			div.DEBUG#log *.DEBUG,',

+'			div.INFO#log *.INFO,',

+'			div.WARN#log *.WARN,',

+'			div.ERROR#log *.ERROR,',

+'			div.FATAL#log *.FATAL {',

+'				display: block;',

+'			}',

+'',

+'			div#log div.separator {',

+'				background-color: #cccccc;',

+'				margin: 5px 0;',

+'				line-height: 1px;',

+'			}',

+'		</style>',

+'	</head>',

+'',

+'	<body id="body">',

+'		<div id="switchesContainer">',

+'			<div id="switches">',

+'				<div id="levels" class="toolbar">',

+'					Filters:',

+'					<input type="checkbox" id="switch_TRACE" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide trace messages" /><label for="switch_TRACE" id="label_TRACE">trace</label>',

+'					<input type="checkbox" id="switch_DEBUG" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide debug messages" /><label for="switch_DEBUG" id="label_DEBUG">debug</label>',

+'					<input type="checkbox" id="switch_INFO" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide info messages" /><label for="switch_INFO" id="label_INFO">info</label>',

+'					<input type="checkbox" id="switch_WARN" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide warn messages" /><label for="switch_WARN" id="label_WARN">warn</label>',

+'					<input type="checkbox" id="switch_ERROR" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide error messages" /><label for="switch_ERROR" id="label_ERROR">error</label>',

+'					<input type="checkbox" id="switch_FATAL" onclick="applyFilters(); checkAllLevels()" checked="checked" title="Show/hide fatal messages" /><label for="switch_FATAL" id="label_FATAL">fatal</label>',

+'					<input type="checkbox" id="switch_ALL" onclick="toggleAllLevels(); applyFilters()" checked="checked" title="Show/hide all messages" /><label for="switch_ALL" id="label_ALL">all</label>',

+'				</div>',

+'				<div id="search" class="toolbar">',

+'					<label for="searchBox" class="searchboxlabel">Search:</label> <input type="text" id="searchBox" onclick="toggleSearchEnabled(true)" onkeyup="scheduleSearch()" size="20" />',

+'					<input type="button" id="searchReset" disabled="disabled" value="Reset" onclick="clearSearch()" class="button" title="Reset the search" />',

+'					<input type="checkbox" id="searchRegex" onclick="doSearch()" title="If checked, search is treated as a regular expression" /><label for="searchRegex">Regex</label>',

+'					<input type="checkbox" id="searchCaseSensitive" onclick="doSearch()" title="If checked, search is case sensitive" /><label for="searchCaseSensitive">Match case</label>',

+'					<input type="checkbox" id="searchDisable" onclick="toggleSearchEnabled()" title="Enable/disable search" /><label for="searchDisable" class="alwaysenabled">Disable</label>',

+'					<div id="searchNav">',

+'						<input type="button" id="searchNext" disabled="disabled" value="Next" onclick="searchNext()" class="button" title="Go to the next matching log entry" />',

+'						<input type="button" id="searchPrevious" disabled="disabled" value="Previous" onclick="searchPrevious()" class="button" title="Go to the previous matching log entry" />',

+'						<input type="checkbox" id="searchFilter" onclick="toggleSearchFilter()" title="If checked, non-matching log entries are filtered out" /><label for="searchFilter">Filter</label>',

+'						<input type="checkbox" id="searchHighlight" onclick="toggleSearchHighlight()" title="Highlight matched search terms" /><label for="searchHighlight" class="alwaysenabled">Highlight all</label>',

+'					</div>',

+'				</div>',

+'				<div id="options" class="toolbar">',

+'					Options:',

+'					<input type="checkbox" id="enableLogging" onclick="toggleLoggingEnabled()" checked="checked" title="Enable/disable logging" /><label for="enableLogging" id="enableLoggingLabel">Log</label>',

+'					<input type="checkbox" id="wrap" onclick="toggleWrap()" title="Enable / disable word wrap" /><label for="wrap" id="wrapLabel">Wrap</label>',

+'					<input type="checkbox" id="newestAtTop" onclick="toggleNewestAtTop()" title="If checked, causes newest messages to appear at the top" /><label for="newestAtTop" id="newestAtTopLabel">Newest at the top</label>',

+'					<input type="checkbox" id="scrollToLatest" onclick="toggleScrollToLatest()" checked="checked" title="If checked, window automatically scrolls to a new message when it is added" /><label for="scrollToLatest" id="scrollToLatestLabel">Scroll to latest</label>',

+'					<input type="button" id="clearButton" value="Clear" onclick="clearLog()" class="button" title="Clear all log messages"  />',

+'					<input type="button" id="hideButton" value="Hide" onclick="hide()" class="hidden button" title="Hide the console" />',

+'					<input type="button" id="closeButton" value="Close" onclick="closeWindow()" class="hidden button" title="Close the window" />',

+'				</div>',

+'			</div>',

+'		</div>',

+'		<div id="log" class="TRACE DEBUG INFO WARN ERROR FATAL"></div>',

+'		<div id="commandLine" class="toolbar">',

+'			<div id="commandLineContainer">',

+'				<input type="text" id="command" title="Enter a JavaScript command here and hit return or press \'Evaluate\'" />',

+'				<input type="button" id="evaluateButton" value="Evaluate" class="button" title="Evaluate the command" onclick="evalCommandLine()" />',

+'			</div>',

+'		</div>',

+'	</body>',

+'</html>',

+''

+];

+		};

+

+		var defaultCommandLineFunctions = [];

+

+		ConsoleAppender = function() {};

+

+		var consoleAppenderIdCounter = 1;

+		ConsoleAppender.prototype = new Appender();

+

+		ConsoleAppender.prototype.create = function(inPage, container,

+				lazyInit, initiallyMinimized, useDocumentWrite, width, height, focusConsoleWindow) {

+			var appender = this;

+

+			// Common properties

+			var initialized = false;

+			var consoleWindowCreated = false;

+			var consoleWindowLoaded = false;

+			var consoleClosed = false;

+

+			var queuedLoggingEvents = [];

+			var isSupported = true;

+			var consoleAppenderId = consoleAppenderIdCounter++;

+

+			// Local variables

+			initiallyMinimized = extractBooleanFromParam(initiallyMinimized, this.defaults.initiallyMinimized);

+			lazyInit = extractBooleanFromParam(lazyInit, this.defaults.lazyInit);

+			useDocumentWrite = extractBooleanFromParam(useDocumentWrite, this.defaults.useDocumentWrite);

+			var newestMessageAtTop = this.defaults.newestMessageAtTop;

+			var scrollToLatestMessage = this.defaults.scrollToLatestMessage;

+			width = width ? width : this.defaults.width;

+			height = height ? height : this.defaults.height;

+			var maxMessages = this.defaults.maxMessages;

+			var showCommandLine = this.defaults.showCommandLine;

+			var commandLineObjectExpansionDepth = this.defaults.commandLineObjectExpansionDepth;

+			var showHideButton = this.defaults.showHideButton;

+            var showCloseButton = this.defaults.showCloseButton;

+            var showLogEntryDeleteButtons = this.defaults.showLogEntryDeleteButtons;

+

+			this.setLayout(this.defaults.layout);

+

+			// Functions whose implementations vary between subclasses

+			var init, createWindow, safeToAppend, getConsoleWindow, open;

+

+			// Configuration methods. The function scope is used to prevent

+			// direct alteration to the appender configuration properties.

+			var appenderName = inPage ? "InPageAppender" : "PopUpAppender";

+			var checkCanConfigure = function(configOptionName) {

+				if (consoleWindowCreated) {

+					handleError(appenderName + ": configuration option '" + configOptionName + "' may not be set after the appender has been initialized");

+					return false;

+				}

+				return true;

+			};

+

+			var consoleWindowExists = function() {

+				return (consoleWindowLoaded && isSupported && !consoleClosed);

+			};

+

+			this.isNewestMessageAtTop = function() { return newestMessageAtTop; };

+			this.setNewestMessageAtTop = function(newestMessageAtTopParam) {

+				newestMessageAtTop = bool(newestMessageAtTopParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setNewestAtTop(newestMessageAtTop);

+				}

+			};

+

+			this.isScrollToLatestMessage = function() { return scrollToLatestMessage; };

+			this.setScrollToLatestMessage = function(scrollToLatestMessageParam) {

+				scrollToLatestMessage = bool(scrollToLatestMessageParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setScrollToLatest(scrollToLatestMessage);

+				}

+			};

+

+			this.getWidth = function() { return width; };

+			this.setWidth = function(widthParam) {

+				if (checkCanConfigure("width")) {

+					width = extractStringFromParam(widthParam, width);

+				}

+			};

+

+			this.getHeight = function() { return height; };

+			this.setHeight = function(heightParam) {

+				if (checkCanConfigure("height")) {

+					height = extractStringFromParam(heightParam, height);

+				}

+			};

+

+			this.getMaxMessages = function() { return maxMessages; };

+			this.setMaxMessages = function(maxMessagesParam) {

+				maxMessages = extractIntFromParam(maxMessagesParam, maxMessages);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setMaxMessages(maxMessages);

+				}

+			};

+

+			this.isShowCommandLine = function() { return showCommandLine; };

+			this.setShowCommandLine = function(showCommandLineParam) {

+				showCommandLine = bool(showCommandLineParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setShowCommandLine(showCommandLine);

+				}

+			};

+

+			this.isShowHideButton = function() { return showHideButton; };

+			this.setShowHideButton = function(showHideButtonParam) {

+				showHideButton = bool(showHideButtonParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setShowHideButton(showHideButton);

+				}

+			};

+

+			this.isShowCloseButton = function() { return showCloseButton; };

+			this.setShowCloseButton = function(showCloseButtonParam) {

+				showCloseButton = bool(showCloseButtonParam);

+				if (consoleWindowExists()) {

+					getConsoleWindow().setShowCloseButton(showCloseButton);

+				}

+			};

+

+			this.getCommandLineObjectExpansionDepth = function() { return commandLineObjectExpansionDepth; };

+			this.setCommandLineObjectExpansionDepth = function(commandLineObjectExpansionDepthParam) {

+				commandLineObjectExpansionDepth = extractIntFromParam(commandLineObjectExpansionDepthParam, commandLineObjectExpansionDepth);

+			};

+

+			var minimized = initiallyMinimized;

+			this.isInitiallyMinimized = function() { return initiallyMinimized; };

+			this.setInitiallyMinimized = function(initiallyMinimizedParam) {

+				if (checkCanConfigure("initiallyMinimized")) {

+					initiallyMinimized = bool(initiallyMinimizedParam);

+					minimized = initiallyMinimized;

+				}

+			};

+

+			this.isUseDocumentWrite = function() { return useDocumentWrite; };

+			this.setUseDocumentWrite = function(useDocumentWriteParam) {

+				if (checkCanConfigure("useDocumentWrite")) {

+					useDocumentWrite = bool(useDocumentWriteParam);

+				}

+			};

+

+			// Common methods

+			function QueuedLoggingEvent(loggingEvent, formattedMessage) {

+				this.loggingEvent = loggingEvent;

+				this.levelName = loggingEvent.level.name;

+				this.formattedMessage = formattedMessage;

+			}

+

+			QueuedLoggingEvent.prototype.append = function() {

+				getConsoleWindow().log(this.levelName, this.formattedMessage);

+			};

+

+			function QueuedGroup(name, initiallyExpanded) {

+				this.name = name;

+				this.initiallyExpanded = initiallyExpanded;

+			}

+

+			QueuedGroup.prototype.append = function() {

+				getConsoleWindow().group(this.name, this.initiallyExpanded);

+			};

+

+			function QueuedGroupEnd() {}

+

+			QueuedGroupEnd.prototype.append = function() {

+				getConsoleWindow().groupEnd();

+			};

+

+			var checkAndAppend = function() {

+				// Next line forces a check of whether the window has been closed

+				safeToAppend();

+				if (!initialized) {

+					init();

+				} else if (consoleClosed && reopenWhenClosed) {

+					createWindow();

+				}

+				if (safeToAppend()) {

+					appendQueuedLoggingEvents();

+				}

+			};

+

+			this.append = function(loggingEvent) {

+				if (isSupported) {

+					// Format the message

+					var formattedMessage = appender.getLayout().format(loggingEvent);

+					if (this.getLayout().ignoresThrowable()) {

+						formattedMessage += loggingEvent.getThrowableStrRep();

+					}

+					queuedLoggingEvents.push(new QueuedLoggingEvent(loggingEvent, formattedMessage));

+					checkAndAppend();

+				}

+			};

+

+            this.group = function(name, initiallyExpanded) {

+				if (isSupported) {

+					queuedLoggingEvents.push(new QueuedGroup(name, initiallyExpanded));

+					checkAndAppend();

+				}

+			};

+

+            this.groupEnd = function() {

+				if (isSupported) {

+					queuedLoggingEvents.push(new QueuedGroupEnd());

+					checkAndAppend();

+				}

+			};

+

+			var appendQueuedLoggingEvents = function() {

+				var currentLoggingEvent;

+				while (queuedLoggingEvents.length > 0) {

+					queuedLoggingEvents.shift().append();

+				}

+				if (focusConsoleWindow) {

+					getConsoleWindow().focus();

+				}

+			};

+

+			this.setAddedToLogger = function(logger) {

+				this.loggers.push(logger);

+				if (enabled && !lazyInit) {

+					init();

+				}

+			};

+

+			this.clear = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().clearLog();

+				}

+				queuedLoggingEvents.length = 0;

+			};

+

+			this.focus = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().focus();

+				}

+			};

+

+			this.focusCommandLine = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().focusCommandLine();

+				}

+			};

+

+			this.focusSearch = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().focusSearch();

+				}

+			};

+

+			var commandWindow = window;

+

+			this.getCommandWindow = function() { return commandWindow; };

+			this.setCommandWindow = function(commandWindowParam) {

+				commandWindow = commandWindowParam;

+			};

+

+			this.executeLastCommand = function() {

+				if (consoleWindowExists()) {

+					getConsoleWindow().evalLastCommand();

+				}

+			};

+

+			var commandLayout = new PatternLayout("%m");

+			this.getCommandLayout = function() { return commandLayout; };

+			this.setCommandLayout = function(commandLayoutParam) {

+				commandLayout = commandLayoutParam;

+			};

+

+			this.evalCommandAndAppend = function(expr) {

+				var commandReturnValue = { appendResult: true, isError: false };

+				var commandOutput = "";

+				// Evaluate the command

+				try {

+					var result, i;

+					// The next three lines constitute a workaround for IE. Bizarrely, iframes seem to have no

+					// eval method on the window object initially, but once execScript has been called on

+					// it once then the eval method magically appears. See http://www.thismuchiknow.co.uk/?p=25

+					if (!commandWindow.eval && commandWindow.execScript) {

+						commandWindow.execScript("null");

+					}

+

+					var commandLineFunctionsHash = {};

+					for (i = 0, len = commandLineFunctions.length; i < len; i++) {

+						commandLineFunctionsHash[commandLineFunctions[i][0]] = commandLineFunctions[i][1];

+					}

+

+					// Keep an array of variables that are being changed in the command window so that they

+					// can be restored to their original values afterwards

+					var objectsToRestore = [];

+					var addObjectToRestore = function(name) {

+						objectsToRestore.push([name, commandWindow[name]]);

+					};

+

+					addObjectToRestore("appender");

+					commandWindow.appender = appender;

+

+					addObjectToRestore("commandReturnValue");

+					commandWindow.commandReturnValue = commandReturnValue;

+

+					addObjectToRestore("commandLineFunctionsHash");

+					commandWindow.commandLineFunctionsHash = commandLineFunctionsHash;

+

+					var addFunctionToWindow = function(name) {

+						addObjectToRestore(name);

+						commandWindow[name] = function() {

+							return this.commandLineFunctionsHash[name](appender, arguments, commandReturnValue);

+						};

+					};

+

+					for (i = 0, len = commandLineFunctions.length; i < len; i++) {

+						addFunctionToWindow(commandLineFunctions[i][0]);

+					}

+

+					// Another bizarre workaround to get IE to eval in the global scope

+					if (commandWindow === window && commandWindow.execScript) {

+						addObjectToRestore("evalExpr");

+						addObjectToRestore("result");

+						window.evalExpr = expr;

+						commandWindow.execScript("window.result=eval(window.evalExpr);");

+						result = window.result;

+ 					} else {

+ 						result = commandWindow.eval(expr);

+ 					}

+					commandOutput = isUndefined(result) ? result : formatObjectExpansion(result, commandLineObjectExpansionDepth);

+

+					// Restore variables in the command window to their original state

+					for (i = 0, len = objectsToRestore.length; i < len; i++) {

+						commandWindow[objectsToRestore[i][0]] = objectsToRestore[i][1];

+					}

+				} catch (ex) {

+					commandOutput = "Error evaluating command: " + getExceptionStringRep(ex);

+					commandReturnValue.isError = true;

+				}

+				// Append command output

+				if (commandReturnValue.appendResult) {

+					var message = ">>> " + expr;

+					if (!isUndefined(commandOutput)) {

+						message += newLine + commandOutput;

+					}

+					var level = commandReturnValue.isError ? Level.ERROR : Level.INFO;

+					var loggingEvent = new LoggingEvent(null, new Date(), level, [message], null);

+					var mainLayout = this.getLayout();

+					this.setLayout(commandLayout);

+					this.append(loggingEvent);

+					this.setLayout(mainLayout);

+				}

+			};

+

+			var commandLineFunctions = defaultCommandLineFunctions.concat([]);

+

+			this.addCommandLineFunction = function(functionName, commandLineFunction) {

+				commandLineFunctions.push([functionName, commandLineFunction]);

+			};

+

+			var commandHistoryCookieName = "log4javascriptCommandHistory";

+			this.storeCommandHistory = function(commandHistory) {

+				setCookie(commandHistoryCookieName, commandHistory.join(","));

+			};

+

+			var writeHtml = function(doc) {

+				var lines = getConsoleHtmlLines();

+				doc.open();

+				for (var i = 0, len = lines.length; i < len; i++) {

+					doc.writeln(lines[i]);

+				}

+				doc.close();

+			};

+

+			// Set up event listeners

+			this.setEventTypes(["load", "unload"]);

+

+			var consoleWindowLoadHandler = function() {

+				var win = getConsoleWindow();

+				win.setAppender(appender);

+				win.setNewestAtTop(newestMessageAtTop);

+				win.setScrollToLatest(scrollToLatestMessage);

+				win.setMaxMessages(maxMessages);

+				win.setShowCommandLine(showCommandLine);

+				win.setShowHideButton(showHideButton);

+				win.setShowCloseButton(showCloseButton);

+				win.setMainWindow(window);

+

+				// Restore command history stored in cookie

+				var storedValue = getCookie(commandHistoryCookieName);

+				if (storedValue) {

+					win.commandHistory = storedValue.split(",");

+					win.currentCommandIndex = win.commandHistory.length;

+				}

+

+				appender.dispatchEvent("load", { "win" : win });

+			};

+

+			this.unload = function() {

+				logLog.debug("unload " + this + ", caller: " + this.unload.caller);

+				if (!consoleClosed) {

+					logLog.debug("really doing unload " + this);

+					consoleClosed = true;

+					consoleWindowLoaded = false;

+					consoleWindowCreated = false;

+					appender.dispatchEvent("unload", {});

+				}

+			};

+

+			var pollConsoleWindow = function(windowTest, interval, successCallback, errorMessage) {

+				function doPoll() {

+					try {

+						// Test if the console has been closed while polling

+						if (consoleClosed) {

+							clearInterval(poll);

+						}

+						if (windowTest(getConsoleWindow())) {

+							clearInterval(poll);

+							successCallback();

+						}

+					} catch (ex) {

+						clearInterval(poll);

+						isSupported = false;

+						handleError(errorMessage, ex);

+					}

+				}

+

+				// Poll the pop-up since the onload event is not reliable

+				var poll = setInterval(doPoll, interval);

+			};

+

+			var getConsoleUrl = function() {

+				var documentDomainSet = (document.domain != location.hostname);

+				return useDocumentWrite ? "" : getBaseUrl() + "console_uncompressed.html" +

+											   (documentDomainSet ? "?log4javascript_domain=" + escape(document.domain) : "");

+			};

+

+			// Define methods and properties that vary between subclasses

+			if (inPage) {

+				// InPageAppender

+

+				var containerElement = null;

+

+				// Configuration methods. The function scope is used to prevent

+				// direct alteration to the appender configuration properties.

+				var cssProperties = [];

+				this.addCssProperty = function(name, value) {

+					if (checkCanConfigure("cssProperties")) {

+						cssProperties.push([name, value]);

+					}

+				};

+

+				// Define useful variables

+				var windowCreationStarted = false;

+				var iframeContainerDiv;

+				var iframeId = uniqueId + "_InPageAppender_" + consoleAppenderId;

+

+				this.hide = function() {

+					if (initialized && consoleWindowCreated) {

+						if (consoleWindowExists()) {

+							getConsoleWindow().$("command").blur();

+						}

+						iframeContainerDiv.style.display = "none";

+						minimized = true;

+					}

+				};

+

+				this.show = function() {

+					if (initialized) {

+						if (consoleWindowCreated) {

+							iframeContainerDiv.style.display = "block";

+							this.setShowCommandLine(showCommandLine); // Force IE to update

+							minimized = false;

+						} else if (!windowCreationStarted) {

+							createWindow(true);

+						}

+					}

+				};

+

+				this.isVisible = function() {

+					return !minimized && !consoleClosed;

+				};

+

+				this.close = function(fromButton) {

+					if (!consoleClosed && (!fromButton || confirm("This will permanently remove the console from the page. No more messages will be logged. Do you wish to continue?"))) {

+						iframeContainerDiv.parentNode.removeChild(iframeContainerDiv);

+						this.unload();

+					}

+				};

+

+				// Create open, init, getConsoleWindow and safeToAppend functions

+				open = function() {

+					var initErrorMessage = "InPageAppender.open: unable to create console iframe";

+

+					function finalInit() {

+						try {

+							if (!initiallyMinimized) {

+								appender.show();

+							}

+							consoleWindowLoadHandler();

+							consoleWindowLoaded = true;

+							appendQueuedLoggingEvents();

+						} catch (ex) {

+							isSupported = false;

+							handleError(initErrorMessage, ex);

+						}

+					}

+

+					function writeToDocument() {

+						try {

+							var windowTest = function(win) { return isLoaded(win); };

+							if (useDocumentWrite) {

+								writeHtml(getConsoleWindow().document);

+							}

+							if (windowTest(getConsoleWindow())) {

+								finalInit();

+							} else {

+								pollConsoleWindow(windowTest, 100, finalInit, initErrorMessage);

+							}

+						} catch (ex) {

+							isSupported = false;

+							handleError(initErrorMessage, ex);

+						}

+					}

+

+					minimized = false;

+					iframeContainerDiv = containerElement.appendChild(document.createElement("div"));

+

+					iframeContainerDiv.style.width = width;

+					iframeContainerDiv.style.height = height;

+					iframeContainerDiv.style.border = "solid gray 1px";

+

+					for (var i = 0, len = cssProperties.length; i < len; i++) {

+						iframeContainerDiv.style[cssProperties[i][0]] = cssProperties[i][1];

+					}

+

+					var iframeSrc = useDocumentWrite ? "" : " src='" + getConsoleUrl() + "'";

+

+					// Adding an iframe using the DOM would be preferable, but it doesn't work

+					// in IE5 on Windows, or in Konqueror prior to version 3.5 - in Konqueror

+					// it creates the iframe fine but I haven't been able to find a way to obtain

+					// the iframe's window object

+					iframeContainerDiv.innerHTML = "<iframe id='" + iframeId + "' name='" + iframeId +

+						"' width='100%' height='100%' frameborder='0'" + iframeSrc +

+						" scrolling='no'></iframe>";

+					consoleClosed = false;

+

+					// Write the console HTML to the iframe

+					var iframeDocumentExistsTest = function(win) {

+						try {

+							return bool(win) && bool(win.document);

+						} catch (ex) {

+							return false;

+						}

+					};

+					if (iframeDocumentExistsTest(getConsoleWindow())) {

+						writeToDocument();

+					} else {

+						pollConsoleWindow(iframeDocumentExistsTest, 100, writeToDocument, initErrorMessage);

+					}

+					consoleWindowCreated = true;

+				};

+

+				createWindow = function(show) {

+					if (show || !initiallyMinimized) {

+						var pageLoadHandler = function() {

+							if (!container) {

+								// Set up default container element

+								containerElement = document.createElement("div");

+								containerElement.style.position = "fixed";

+								containerElement.style.left = "0";

+								containerElement.style.right = "0";

+								containerElement.style.bottom = "0";

+								document.body.appendChild(containerElement);

+								appender.addCssProperty("borderWidth", "1px 0 0 0");

+								appender.addCssProperty("zIndex", 1000000); // Can't find anything authoritative that says how big z-index can be

+								open();

+							} else {

+								try {

+									var el = document.getElementById(container);

+									if (el.nodeType == 1) {

+										containerElement = el;

+									}

+									open();

+								} catch (ex) {

+									handleError("InPageAppender.init: invalid container element '" + container + "' supplied", ex);

+								}

+							}

+						};

+

+						// Test the type of the container supplied. First, check if it's an element

+						if (pageLoaded && container && container.appendChild) {

+							containerElement = container;

+							open();

+						} else if (pageLoaded) {

+							pageLoadHandler();

+						} else {

+							log4javascript.addEventListener("load", pageLoadHandler);

+						}

+						windowCreationStarted = true;

+					}

+				};

+

+				init = function() {

+					createWindow();

+					initialized = true;

+				};

+

+				getConsoleWindow = function() {

+					var iframe = window.frames[iframeId];

+					if (iframe) {

+						return iframe;

+					}

+				};

+

+				safeToAppend = function() {

+					if (isSupported && !consoleClosed) {

+						if (consoleWindowCreated && !consoleWindowLoaded && getConsoleWindow() && isLoaded(getConsoleWindow())) {

+							consoleWindowLoaded = true;

+						}

+						return consoleWindowLoaded;

+					}

+					return false;

+				};

+			} else {

+				// PopUpAppender

+

+				// Extract params

+				var useOldPopUp = appender.defaults.useOldPopUp;

+				var complainAboutPopUpBlocking = appender.defaults.complainAboutPopUpBlocking;

+				var reopenWhenClosed = this.defaults.reopenWhenClosed;

+

+				// Configuration methods. The function scope is used to prevent

+				// direct alteration to the appender configuration properties.

+				this.isUseOldPopUp = function() { return useOldPopUp; };

+				this.setUseOldPopUp = function(useOldPopUpParam) {

+					if (checkCanConfigure("useOldPopUp")) {

+						useOldPopUp = bool(useOldPopUpParam);

+					}

+				};

+

+				this.isComplainAboutPopUpBlocking = function() { return complainAboutPopUpBlocking; };

+				this.setComplainAboutPopUpBlocking = function(complainAboutPopUpBlockingParam) {

+					if (checkCanConfigure("complainAboutPopUpBlocking")) {

+						complainAboutPopUpBlocking = bool(complainAboutPopUpBlockingParam);

+					}

+				};

+

+				this.isFocusPopUp = function() { return focusConsoleWindow; };

+				this.setFocusPopUp = function(focusPopUpParam) {

+					// This property can be safely altered after logging has started

+					focusConsoleWindow = bool(focusPopUpParam);

+				};

+

+				this.isReopenWhenClosed = function() { return reopenWhenClosed; };

+				this.setReopenWhenClosed = function(reopenWhenClosedParam) {

+					// This property can be safely altered after logging has started

+					reopenWhenClosed = bool(reopenWhenClosedParam);

+				};

+

+				this.close = function() {

+					logLog.debug("close " + this);

+					try {

+						popUp.close();

+						this.unload();

+					} catch (ex) {

+						// Do nothing

+					}

+				};

+

+				this.hide = function() {

+					logLog.debug("hide " + this);

+					if (consoleWindowExists()) {

+						this.close();

+					}

+				};

+

+				this.show = function() {

+					logLog.debug("show " + this);

+					if (!consoleWindowCreated) {

+						open();

+					}

+				};

+

+				this.isVisible = function() {

+					return safeToAppend();

+				};

+

+				// Define useful variables

+				var popUp;

+

+				// Create open, init, getConsoleWindow and safeToAppend functions

+				open = function() {

+					var windowProperties = "width=" + width + ",height=" + height + ",status,resizable";

+					var frameInfo = "";

+					try {

+						var frameEl = window.frameElement;

+						if (frameEl) {

+							frameInfo = "_" + frameEl.tagName + "_" + (frameEl.name || frameEl.id || "");

+						}

+					} catch (e) {

+						frameInfo = "_inaccessibleParentFrame";

+					}

+					var windowName = "PopUp_" + location.host.replace(/[^a-z0-9]/gi, "_") + "_" + consoleAppenderId + frameInfo;

+					if (!useOldPopUp || !useDocumentWrite) {

+						// Ensure a previous window isn't used by using a unique name

+						windowName = windowName + "_" + uniqueId;

+					}

+

+					var checkPopUpClosed = function(win) {

+						if (consoleClosed) {

+							return true;

+						} else {

+							try {

+								return bool(win) && win.closed;

+							} catch(ex) {}

+						}

+						return false;

+					};

+

+					var popUpClosedCallback = function() {

+						if (!consoleClosed) {

+							appender.unload();

+						}

+					};

+

+					function finalInit() {

+						getConsoleWindow().setCloseIfOpenerCloses(!useOldPopUp || !useDocumentWrite);

+						consoleWindowLoadHandler();

+						consoleWindowLoaded = true;

+						appendQueuedLoggingEvents();

+						pollConsoleWindow(checkPopUpClosed, 500, popUpClosedCallback,

+								"PopUpAppender.checkPopUpClosed: error checking pop-up window");

+					}

+

+					try {

+						popUp = window.open(getConsoleUrl(), windowName, windowProperties);

+						consoleClosed = false;

+						consoleWindowCreated = true;

+						if (popUp && popUp.document) {

+							if (useDocumentWrite && useOldPopUp && isLoaded(popUp)) {

+								popUp.mainPageReloaded();

+								finalInit();

+							} else {

+								if (useDocumentWrite) {

+									writeHtml(popUp.document);

+								}

+								// Check if the pop-up window object is available

+								var popUpLoadedTest = function(win) { return bool(win) && isLoaded(win); };

+								if (isLoaded(popUp)) {

+									finalInit();

+								} else {

+									pollConsoleWindow(popUpLoadedTest, 100, finalInit,

+											"PopUpAppender.init: unable to create console window");

+								}

+							}

+						} else {

+							isSupported = false;

+							logLog.warn("PopUpAppender.init: pop-ups blocked, please unblock to use PopUpAppender");

+							if (complainAboutPopUpBlocking) {

+								handleError("log4javascript: pop-up windows appear to be blocked. Please unblock them to use pop-up logging.");

+							}

+						}

+					} catch (ex) {

+						handleError("PopUpAppender.init: error creating pop-up", ex);

+					}

+				};

+

+				createWindow = function() {

+					if (!initiallyMinimized) {

+						open();

+					}

+				};

+

+				init = function() {

+					createWindow();

+					initialized = true;

+				};

+

+				getConsoleWindow = function() {

+					return popUp;

+				};

+

+				safeToAppend = function() {

+					if (isSupported && !isUndefined(popUp) && !consoleClosed) {

+						if (popUp.closed ||

+								(consoleWindowLoaded && isUndefined(popUp.closed))) { // Extra check for Opera

+							appender.unload();

+							logLog.debug("PopUpAppender: pop-up closed");

+							return false;

+						}

+						if (!consoleWindowLoaded && isLoaded(popUp)) {

+							consoleWindowLoaded = true;

+						}

+					}

+					return isSupported && consoleWindowLoaded && !consoleClosed;

+				};

+			}

+

+			// Expose getConsoleWindow so that automated tests can check the DOM

+			this.getConsoleWindow = getConsoleWindow;

+		};

+

+		ConsoleAppender.addGlobalCommandLineFunction = function(functionName, commandLineFunction) {

+			defaultCommandLineFunctions.push([functionName, commandLineFunction]);

+		};

+

+		/* ------------------------------------------------------------------ */

+

+		function PopUpAppender(lazyInit, initiallyMinimized, useDocumentWrite,

+							   width, height) {

+			this.create(false, null, lazyInit, initiallyMinimized,

+					useDocumentWrite, width, height, this.defaults.focusPopUp);

+		}

+

+		PopUpAppender.prototype = new ConsoleAppender();

+

+		PopUpAppender.prototype.defaults = {

+			layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),

+			initiallyMinimized: false,

+			focusPopUp: false,

+			lazyInit: true,

+			useOldPopUp: true,

+			complainAboutPopUpBlocking: true,

+			newestMessageAtTop: false,

+			scrollToLatestMessage: true,

+			width: "600",

+			height: "400",

+			reopenWhenClosed: false,

+			maxMessages: null,

+			showCommandLine: true,

+			commandLineObjectExpansionDepth: 1,

+			showHideButton: false,

+			showCloseButton: true,

+            showLogEntryDeleteButtons: true,

+            useDocumentWrite: true

+		};

+

+		PopUpAppender.prototype.toString = function() {

+			return "PopUpAppender";

+		};

+

+		log4javascript.PopUpAppender = PopUpAppender;

+

+		/* ------------------------------------------------------------------ */

+

+		function InPageAppender(container, lazyInit, initiallyMinimized,

+								useDocumentWrite, width, height) {

+			this.create(true, container, lazyInit, initiallyMinimized,

+					useDocumentWrite, width, height, false);

+		}

+

+		InPageAppender.prototype = new ConsoleAppender();

+

+		InPageAppender.prototype.defaults = {

+			layout: new PatternLayout("%d{HH:mm:ss} %-5p - %m{1}%n"),

+			initiallyMinimized: false,

+			lazyInit: true,

+			newestMessageAtTop: false,

+			scrollToLatestMessage: true,

+			width: "100%",

+			height: "220px",

+			maxMessages: null,

+			showCommandLine: true,

+			commandLineObjectExpansionDepth: 1,

+			showHideButton: false,

+			showCloseButton: false,

+            showLogEntryDeleteButtons: true,

+            useDocumentWrite: true

+		};

+

+		InPageAppender.prototype.toString = function() {

+			return "InPageAppender";

+		};

+

+		log4javascript.InPageAppender = InPageAppender;

+

+		// Next line for backwards compatibility

+		log4javascript.InlineAppender = InPageAppender;

+	})();

+	/* ---------------------------------------------------------------------- */

+	// Console extension functions

+

+	function padWithSpaces(str, len) {

+		if (str.length < len) {

+			var spaces = [];

+			var numberOfSpaces = Math.max(0, len - str.length);

+			for (var i = 0; i < numberOfSpaces; i++) {

+				spaces[i] = " ";

+			}

+			str += spaces.join("");

+		}

+		return str;

+	}

+

+	(function() {

+		function dir(obj) {

+			var maxLen = 0;

+			// Obtain the length of the longest property name

+			for (var p in obj) {

+				maxLen = Math.max(toStr(p).length, maxLen);

+			}

+			// Create the nicely formatted property list

+			var propList = [];

+			for (p in obj) {

+				var propNameStr = "  " + padWithSpaces(toStr(p), maxLen + 2);

+				var propVal;

+				try {

+					propVal = splitIntoLines(toStr(obj[p])).join(padWithSpaces(newLine, maxLen + 6));

+				} catch (ex) {

+					propVal = "[Error obtaining property. Details: " + getExceptionMessage(ex) + "]";

+				}

+				propList.push(propNameStr + propVal);

+			}

+			return propList.join(newLine);

+		}

+

+		var nodeTypes = {

+			ELEMENT_NODE: 1,

+			ATTRIBUTE_NODE: 2,

+			TEXT_NODE: 3,

+			CDATA_SECTION_NODE: 4,

+			ENTITY_REFERENCE_NODE: 5,

+			ENTITY_NODE: 6,

+			PROCESSING_INSTRUCTION_NODE: 7,

+			COMMENT_NODE: 8,

+			DOCUMENT_NODE: 9,

+			DOCUMENT_TYPE_NODE: 10,

+			DOCUMENT_FRAGMENT_NODE: 11,

+			NOTATION_NODE: 12

+		};

+

+		var preFormattedElements = ["script", "pre"];

+

+		// This should be the definitive list, as specified by the XHTML 1.0 Transitional DTD

+		var emptyElements = ["br", "img", "hr", "param", "link", "area", "input", "col", "base", "meta"];

+		var indentationUnit = "  ";

+

+		// Create and return an XHTML string from the node specified

+		function getXhtml(rootNode, includeRootNode, indentation, startNewLine, preformatted) {

+			includeRootNode = (typeof includeRootNode == "undefined") ? true : !!includeRootNode;

+			if (typeof indentation != "string") {

+				indentation = "";

+			}

+			startNewLine = !!startNewLine;

+			preformatted = !!preformatted;

+			var xhtml;

+

+			function isWhitespace(node) {

+				return ((node.nodeType == nodeTypes.TEXT_NODE) && /^[ \t\r\n]*$/.test(node.nodeValue));

+			}

+

+			function fixAttributeValue(attrValue) {

+				return attrValue.toString().replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/"/g, "&quot;");

+			}

+

+			function getStyleAttributeValue(el) {

+				var stylePairs = el.style.cssText.split(";");

+				var styleValue = "";

+				var isFirst = true;

+				for (var j = 0, len = stylePairs.length; j < len; j++) {

+					var nameValueBits = stylePairs[j].split(":");

+					var props = [];

+					if (!/^\s*$/.test(nameValueBits[0])) {

+						props.push(trim(nameValueBits[0]).toLowerCase() + ":" + trim(nameValueBits[1]));

+					}

+					styleValue = props.join(";");

+				}

+				return styleValue;

+			}

+

+			function getNamespace(el) {

+				if (el.prefix) {

+					return el.prefix;

+				} else if (el.outerHTML) {

+					var regex = new RegExp("<([^:]+):" + el.tagName + "[^>]*>", "i");

+					if (regex.test(el.outerHTML)) {

+						return RegExp.$1.toLowerCase();

+					}

+				}

+                return "";

+			}

+

+			var lt = "<";

+			var gt = ">";

+

+			if (includeRootNode && rootNode.nodeType != nodeTypes.DOCUMENT_FRAGMENT_NODE) {

+				switch (rootNode.nodeType) {

+					case nodeTypes.ELEMENT_NODE:

+						var tagName = rootNode.tagName.toLowerCase();

+						xhtml = startNewLine ? newLine + indentation : "";

+						xhtml += lt;

+						// Allow for namespaces, where present

+						var prefix = getNamespace(rootNode);

+						var hasPrefix = !!prefix;

+						if (hasPrefix) {

+							xhtml += prefix + ":";

+						}

+						xhtml += tagName;

+						for (i = 0, len = rootNode.attributes.length; i < len; i++) {

+							var currentAttr = rootNode.attributes[i];

+							// Check the attribute is valid.

+							if (!	currentAttr.specified ||

+									currentAttr.nodeValue === null ||

+									currentAttr.nodeName.toLowerCase() === "style" ||

+									typeof currentAttr.nodeValue !== "string" ||

+									currentAttr.nodeName.indexOf("_moz") === 0) {

+								continue;

+							}

+							xhtml += " " + currentAttr.nodeName.toLowerCase() + "=\"";

+							xhtml += fixAttributeValue(currentAttr.nodeValue);

+							xhtml += "\"";

+						}

+						// Style needs to be done separately as it is not reported as an

+						// attribute in IE

+						if (rootNode.style.cssText) {

+							var styleValue = getStyleAttributeValue(rootNode);

+							if (styleValue !== "") {

+								xhtml += " style=\"" + getStyleAttributeValue(rootNode) + "\"";

+							}

+						}

+						if (array_contains(emptyElements, tagName) ||

+								(hasPrefix && !rootNode.hasChildNodes())) {

+							xhtml += "/" + gt;

+						} else {

+							xhtml += gt;

+							// Add output for childNodes collection (which doesn't include attribute nodes)

+							var childStartNewLine = !(rootNode.childNodes.length === 1 &&

+								rootNode.childNodes[0].nodeType === nodeTypes.TEXT_NODE);

+							var childPreformatted = array_contains(preFormattedElements, tagName);

+							for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {

+								xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit,

+									childStartNewLine, childPreformatted);

+							}

+							// Add the end tag

+							var endTag = lt + "/" + tagName + gt;

+							xhtml += childStartNewLine ? newLine + indentation + endTag : endTag;

+						}

+						return xhtml;

+					case nodeTypes.TEXT_NODE:

+						if (isWhitespace(rootNode)) {

+							xhtml = "";

+						} else {

+							if (preformatted) {

+								xhtml = rootNode.nodeValue;

+							} else {

+								// Trim whitespace from each line of the text node

+								var lines = splitIntoLines(trim(rootNode.nodeValue));

+								var trimmedLines = [];

+								for (var i = 0, len = lines.length; i < len; i++) {

+									trimmedLines[i] = trim(lines[i]);

+								}

+								xhtml = trimmedLines.join(newLine + indentation);

+							}

+							if (startNewLine) {

+								xhtml = newLine + indentation + xhtml;

+							}

+						}

+						return xhtml;

+					case nodeTypes.CDATA_SECTION_NODE:

+						return "<![CDA" + "TA[" + rootNode.nodeValue + "]" + "]>" + newLine;

+					case nodeTypes.DOCUMENT_NODE:

+						xhtml = "";

+						// Add output for childNodes collection (which doesn't include attribute nodes)

+						for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {

+							xhtml += getXhtml(rootNode.childNodes[i], true, indentation);

+						}

+						return xhtml;

+					default:

+						return "";

+				}

+			} else {

+				xhtml = "";

+				// Add output for childNodes collection (which doesn't include attribute nodes)

+				for (var i = 0, len = rootNode.childNodes.length; i < len; i++) {

+					xhtml += getXhtml(rootNode.childNodes[i], true, indentation + indentationUnit);

+				}

+				return xhtml;

+			}

+		}

+

+		function createCommandLineFunctions() {

+			ConsoleAppender.addGlobalCommandLineFunction("$", function(appender, args, returnValue) {

+				return document.getElementById(args[0]);

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("dir", function(appender, args, returnValue) {

+				var lines = [];

+				for (var i = 0, len = args.length; i < len; i++) {

+					lines[i] = dir(args[i]);

+				}

+				return lines.join(newLine + newLine);

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("dirxml", function(appender, args, returnValue) {

+				var lines = [];

+				for (var i = 0, len = args.length; i < len; i++) {

+					var win = appender.getCommandWindow();

+					lines[i] = getXhtml(args[i]);

+				}

+				return lines.join(newLine + newLine);

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("cd", function(appender, args, returnValue) {

+				var win, message;

+				if (args.length === 0 || args[0] === "") {

+					win = window;

+					message = "Command line set to run in main window";

+				} else {

+					if (args[0].window == args[0]) {

+						win = args[0];

+						message = "Command line set to run in frame '" + args[0].name + "'";

+					} else {

+						win = window.frames[args[0]];

+						if (win) {

+							message = "Command line set to run in frame '" + args[0] + "'";

+						} else {

+							returnValue.isError = true;

+							message = "Frame '" + args[0] + "' does not exist";

+							win = appender.getCommandWindow();

+						}

+					}

+				}

+				appender.setCommandWindow(win);

+				return message;

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("clear", function(appender, args, returnValue) {

+				returnValue.appendResult = false;

+				appender.clear();

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("keys", function(appender, args, returnValue) {

+				var keys = [];

+				for (var k in args[0]) {

+					keys.push(k);

+				}

+				return keys;

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("values", function(appender, args, returnValue) {

+				var values = [];

+				for (var k in args[0]) {

+					try {

+						values.push(args[0][k]);

+					} catch (ex) {

+						logLog.warn("values(): Unable to obtain value for key " + k + ". Details: " + getExceptionMessage(ex));

+					}

+				}

+				return values;

+			});

+

+			ConsoleAppender.addGlobalCommandLineFunction("expansionDepth", function(appender, args, returnValue) {

+				var expansionDepth = parseInt(args[0], 10);

+				if (isNaN(expansionDepth) || expansionDepth < 0) {

+					returnValue.isError = true;

+					return "" + args[0] + " is not a valid expansion depth";

+				} else {

+					appender.setCommandLineObjectExpansionDepth(expansionDepth);

+					return "Object expansion depth set to " + expansionDepth;

+				}

+			});

+		}

+

+		function init() {

+			// Add command line functions

+			createCommandLineFunctions();

+		}

+

+		/* ------------------------------------------------------------------ */

+

+		init();

+	})();

+

+	/* ---------------------------------------------------------------------- */

+	// Main load

+

+   log4javascript.setDocumentReady = function() {

+       pageLoaded = true;

+       log4javascript.dispatchEvent("load", {});

+   };

+

+    if (window.addEventListener) {

+        window.addEventListener("load", log4javascript.setDocumentReady, false);

+    } else if (window.attachEvent) {

+        window.attachEvent("onload", log4javascript.setDocumentReady);

+    } else {

+        var oldOnload = window.onload;

+        if (typeof window.onload != "function") {

+            window.onload = log4javascript.setDocumentReady;

+        } else {

+            window.onload = function(evt) {

+                if (oldOnload) {

+                    oldOnload(evt);

+                }

+                log4javascript.setDocumentReady();

+            };

+        }

+    }

+

+    // Ensure that the log4javascript object is available in the window. This

+    // is necessary for log4javascript to be available in IE if loaded using

+    // Dojo's module system

+    window.log4javascript = log4javascript;

+

+    return log4javascript;

+})();
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/main.css b/planetstack/core/static/log4javascript-1.4.6/main.css
new file mode 100644
index 0000000..5ac3df3
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/main.css
@@ -0,0 +1,300 @@
+body {

+	font-family: Verdana, Arial, Helvetica, Sans-serif;

+	font-size: 75%;

+	color: black;

+	background-color: #eeeeee;

+	text-align: center;

+	padding: 0px;

+	margin: 0px;

+}

+

+div#container {

+	width: 770px;

+	text-align: left;

+	line-height: 150%;

+	border-width: 0px 1px 1px 1px;

+	border-color: #cccccc;

+	border-style: solid;

+	background-color: white;

+	color: black;

+	padding: 10px;

+	margin: 0px auto 10px auto;

+}

+

+div#header {

+	margin: 0px;

+}

+

+div#header h1 {

+	font-family: Courier New, Courier, Monospace, Serif;

+	padding: 8px 0 15px 0;

+	margin: 0px;

+	font-size: 200%;

+	font-weight: bold;

+	text-align: right;

+}

+

+div#header h1 a {

+	color: black;

+}

+

+div#nav {

+	font-size: 91.66%;

+	font-weight: bold;

+	padding-top: 5px;

+	padding-bottom: 5px;

+	border-bottom: solid #cccccc 1px;

+	text-align: right;

+	background-color: #f0f0fa;

+}

+

+div#container.nonav div#content {

+	float: none;

+	width: auto;

+}

+

+*.externallinkinfo {

+	float: right;

+	font-style: italic;

+}

+

+div#content h1 {

+	padding: 10px 3px 5px 3px;

+	margin: 5px 0px;

+	font-size: 175%;

+	font-weight: normal;

+}

+

+div#content h2 {

+	background-color: darkgreen;

+	color: white;

+	padding: 0px 3px;

+	font-size: 116.66%;

+	font-weight: bold;

+}

+

+div#content h2 a {

+	color: white;

+}

+

+div#content h3 {

+	padding: 0px 3px;

+	font-size: 116.66%;

+	font-weight: bold;

+	border-style: solid;

+	border-color: #003399;

+	border-width: 1px 0px;

+}

+

+div#content h4 {

+	padding: 0px 3px;

+	font-size: 100%;

+	font-weight: bold;

+	border-top: solid #eeeeee 1px;

+}

+

+div#content h5 {

+	padding: 0px;

+	margin: 3px 0px;

+}

+

+div#footer {

+	margin-top: 20px;

+	padding: 2px;

+	border-top: solid #cccccc 1px;

+	font-size: 91.66%;

+}

+

+a {

+	color: #003399;

+	text-decoration: none;

+}

+

+a:hover {

+	text-decoration: underline;

+}

+

+a.bold {

+	font-weight: bold;

+}

+

+a.underlined {

+	text-decoration: underline;

+}

+

+a img {

+	border-width: 0px;

+}

+

+br.clear {

+	clear: both;

+}

+

+table {

+	font-size: 100%;

+}

+

+/* Code */

+pre, code {

+	font-family: Courier New, Courier;

+	font-size: 108.33%;

+}

+

+pre.code, pre.console {

+	border: solid 1px #cccccc;

+	padding: 3px;

+}

+

+pre.code {

+	background-color: #eeeeee;

+}

+

+*.trace {

+	color: #666666;

+}

+

+*.debug {

+	color: green;

+}

+

+*.info {

+	color: #000099;

+}

+

+*.warn {

+	color: #999900;

+}

+

+*.error {

+	color: red;

+}

+

+*.fatal {

+	color: #660066;

+}

+

+

+div.example, div.panel {

+	border: solid 1px #cccccc;

+	background-color: #f5f5f5;

+	padding: 3px;

+	margin-bottom: 10px;

+}

+

+div.panel h2 {

+	margin: 5px 0px;

+}

+

+div.padded {

+	padding: 10px;

+}

+

+div.hidden {

+	display: none;

+}

+

+div.active {

+	background-color: #fcfffc;

+	border-color: green;

+}

+

+label.rightofinput, input.rightoflabel {

+	margin-right: 20px;

+}

+

+/* 'Back to top' link */

+p.linktotop {

+	text-align: right;

+}

+

+ul.propertieslist li.method, ul.propertieslist li.property {

+	margin: 0;

+	padding: 0px 0px 15px 0px;

+}

+

+ul.propertieslist li *.name {

+	font-size: 116.66%;

+	font-weight: bold;

+}

+

+ul.propertieslist li.method div.methodsignature {

+	margin: 10px 0px;

+	font-size: 116.66%;

+	background-color: #eeeeee;

+}

+

+ul.propertieslist li.method *.paramsheading {

+	font-weight: bold;

+}

+

+ul.propertieslist li.method *.params {

+	padding-top: 5px;

+	padding-bottom: 5px;

+}

+

+ul.propertieslist li.method *.params li.param {

+	padding-bottom: 10px;

+}

+

+ul.propertieslist li.method *.params li.param *.paramname {

+	font-style: italic;

+}

+

+div.serverlog {

+	height: 200px;

+	/*border: solid 1px #cccccc;*/

+}

+

+div#inPageConsole {

+	margin-top: 10px;

+}

+

+div.iframecontainer {

+	background-color: white;

+	border: solid #cccccc 1px;

+	width: 100%;

+}

+

+div.veryprominent {

+	background-color: darkgreen;

+	color: white;

+	font-weight: bold;

+	padding: 10px;

+	font-size: 133.33%;

+	margin-bottom: 10px;

+}

+

+div.veryprominent a {

+	color: white;

+}

+

+*.largetext {

+	font-size: 116.66%;

+}

+

+div#leftcolumn {

+	float: left;

+	width: 160px;

+}

+

+div#rightcolumn {

+	float: right;

+	width: 580px;

+}

+

+td.fullsupport {

+	background-color: lightgreen;

+}

+

+td.partialsupport {

+	background-color: gold;

+}

+

+td.nosupport {

+	background-color: lightcoral;

+}

+

+p.editions {

+	text-align: right;

+	font-style: italic;

+}
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/test/index.html b/planetstack/core/static/log4javascript-1.4.6/test/index.html
new file mode 100644
index 0000000..e01f13c
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/test/index.html
@@ -0,0 +1,15 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - Tests</title>

+	</head>

+	<body>

+		<ul>

+			<li><a href="log4javascript.html">Standard edition tests</a></li>

+			<li><a href="log4javascript_uncompressed.html">Standard edition uncompressed tests</a></li>

+			<li><a href="log4javascript_production.html">Production edition tests</a></li>

+			<li><a href="log4javascript_production_uncompressed.html">Production edition uncompressed tests</a></li>

+		</ul>

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/test/log4javascript.html b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript.html
new file mode 100644
index 0000000..8e426b9
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - log4javascript - Tests</title>

+		<script type="text/javascript" src="../js/log4javascript.js"></script>

+		<script type="text/javascript" src="../js/stubs/log4javascript.js"></script>

+		<script type="text/javascript" src="xntest.js"></script>

+		<script type="text/javascript" src="../js/tests/log4javascript.js"></script>

+		<link rel="stylesheet" type="text/css" href="tests.css"/>

+	</head>

+	<body>

+		<div id="messages"></div>

+		<div id="inlineAppenderContainer"></div>

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_lite.html b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_lite.html
new file mode 100644
index 0000000..508dc83
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_lite.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - log4javascript_lite - Tests</title>

+		<script type="text/javascript" src="../js/log4javascript_lite.js"></script>

+		<script type="text/javascript" src="../js/stubs/log4javascript_lite.js"></script>

+		<script type="text/javascript" src="xntest.js"></script>

+		<script type="text/javascript" src="../js/tests/log4javascript_lite.js"></script>

+		<link rel="stylesheet" type="text/css" href="tests.css"/>

+	</head>

+	<body>

+		<div id="messages"></div>

+		<div id="inlineAppenderContainer"></div>

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_lite_uncompressed.html b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_lite_uncompressed.html
new file mode 100644
index 0000000..968019c
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_lite_uncompressed.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - log4javascript_lite_uncompressed - Tests</title>

+		<script type="text/javascript" src="../js/log4javascript_lite_uncompressed.js"></script>

+		<script type="text/javascript" src="../js/stubs/log4javascript_lite_uncompressed.js"></script>

+		<script type="text/javascript" src="xntest.js"></script>

+		<script type="text/javascript" src="../js/tests/log4javascript_lite_uncompressed.js"></script>

+		<link rel="stylesheet" type="text/css" href="tests.css"/>

+	</head>

+	<body>

+		<div id="messages"></div>

+		<div id="inlineAppenderContainer"></div>

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_production.html b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_production.html
new file mode 100644
index 0000000..e5308b1
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_production.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - log4javascript_production - Tests</title>

+		<script type="text/javascript" src="../js/log4javascript_production.js"></script>

+		<script type="text/javascript" src="../js/stubs/log4javascript_production.js"></script>

+		<script type="text/javascript" src="xntest.js"></script>

+		<script type="text/javascript" src="../js/tests/log4javascript_production.js"></script>

+		<link rel="stylesheet" type="text/css" href="tests.css"/>

+	</head>

+	<body>

+		<div id="messages"></div>

+		<div id="inlineAppenderContainer"></div>

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_production_uncompressed.html b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_production_uncompressed.html
new file mode 100644
index 0000000..21f84d7
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_production_uncompressed.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - log4javascript_production_uncompressed - Tests</title>

+		<script type="text/javascript" src="../js/log4javascript_production_uncompressed.js"></script>

+		<script type="text/javascript" src="../js/stubs/log4javascript_production_uncompressed.js"></script>

+		<script type="text/javascript" src="xntest.js"></script>

+		<script type="text/javascript" src="../js/tests/log4javascript_production_uncompressed.js"></script>

+		<link rel="stylesheet" type="text/css" href="tests.css"/>

+	</head>

+	<body>

+		<div id="messages"></div>

+		<div id="inlineAppenderContainer"></div>

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_uncompressed.html b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_uncompressed.html
new file mode 100644
index 0000000..3db9241
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/test/log4javascript_uncompressed.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - log4javascript_uncompressed - Tests</title>

+		<script type="text/javascript" src="../js/log4javascript_uncompressed.js"></script>

+		<script type="text/javascript" src="../js/stubs/log4javascript_uncompressed.js"></script>

+		<script type="text/javascript" src="xntest.js"></script>

+		<script type="text/javascript" src="../js/tests/log4javascript_uncompressed.js"></script>

+		<link rel="stylesheet" type="text/css" href="tests.css"/>

+	</head>

+	<body>

+		<div id="messages"></div>

+		<div id="inlineAppenderContainer"></div>

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/test/main.html b/planetstack/core/static/log4javascript-1.4.6/test/main.html
new file mode 100644
index 0000000..176098f
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/test/main.html
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">

+	<head>

+		<title>log4javascript - %%build:edition%% - Tests</title>

+		<script type="text/javascript" src="../js/%%build:edition%%.js"></script>

+		<script type="text/javascript" src="../js/stubs/%%build:edition%%.js"></script>

+		<script type="text/javascript" src="xntest.js"></script>

+		<script type="text/javascript" src="../js/tests/%%build:edition%%.js"></script>

+		<link rel="stylesheet" type="text/css" href="tests.css"/>

+	</head>

+	<body>

+		<div id="messages"></div>

+		<div id="inlineAppenderContainer"></div>

+	</body>

+</html>

diff --git a/planetstack/core/static/log4javascript-1.4.6/test/tests.css b/planetstack/core/static/log4javascript-1.4.6/test/tests.css
new file mode 100644
index 0000000..9cddef8
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/test/tests.css
@@ -0,0 +1,88 @@
+body {

+	font-family: verdana, arial, helvetica, sans-serif;

+	font-size: 81.25%;

+}

+

+h2 {

+	font-size: 100%;

+	padding: 0;

+	margin: 0.1em 0 0.1em 0;

+}

+

+div.xn_test_suite_container {

+	border: solid #cccccc 1px;

+	padding: 2px 5px;

+	margin: 2px 0px;

+}

+

+div.xn_test_progressbar_container {

+	border: solid black 1px;

+}

+

+div.xn_test_progressbar_container *.success {

+	background-color: #00ff00;

+}

+

+div.xn_test_progressbar_container *.failure {

+	background-color: red;

+}

+

+div.xn_test_overallprogressbar_container {

+	position: relative;

+}

+

+div.xn_test_overallprogressbar_container h1 {

+	margin: 0;

+	padding: 2px;

+	font-size: 125%;

+	font-weight: bold;

+	white-space: nowrap;

+}

+

+dl *.success {

+	color: green;

+}

+

+dl *.failure {

+	color: red;

+}

+

+span.xn_test_expander {

+	padding: 0;

+	border: solid black 1px;

+	cursor: pointer;

+	cursor: hand;

+	line-height: 100%; 

+	font-weight: bold;

+	margin-right: 1em;

+	font-size: 11px;

+}

+

+dl.xn_test_expanded {

+	display: block;

+}

+

+dl.xn_test_collapsed {

+	display: none;

+}

+

+div.xn_test_suite_success {

+	border: solid 2px limegreen;

+}

+

+div.xn_test_suite_failure {

+	border: solid 2px red;

+}

+

+pre.xn_test_log_report {

+	background-color: #f5f5f5;

+	padding: 3px;

+	border: solid gray 1px;

+	font-size: 11px;

+	font-family: Courier New, Courier, monospace;

+}

+

+code.xn_test_stacktrace {

+	color: red;

+	overflow: 

+}
\ No newline at end of file
diff --git a/planetstack/core/static/log4javascript-1.4.6/test/xntest.js b/planetstack/core/static/log4javascript-1.4.6/test/xntest.js
new file mode 100644
index 0000000..1b8f475
--- /dev/null
+++ b/planetstack/core/static/log4javascript-1.4.6/test/xntest.js
@@ -0,0 +1,739 @@
+// Next three methods are primarily for IE5, which is missing them
+if (!Array.prototype.push) {
+	Array.prototype.push = function() {
+		for (var i = 0; i < arguments.length; i++){
+				this[this.length] = arguments[i];
+		}
+		return this.length;
+	};
+}
+
+if (!Array.prototype.shift) {
+	Array.prototype.shift = function() {
+		if (this.length > 0) {
+			var firstItem = this[0];
+			for (var i = 0; i < this.length - 1; i++) {
+				this[i] = this[i + 1];
+			}
+			this.length = this.length - 1;
+			return firstItem;
+		}
+	};
+}
+
+if (!Function.prototype.apply) {
+	Function.prototype.apply = function(obj, args) {
+		var methodName = "__apply__";
+		if (typeof obj[methodName] != "undefined") {
+			methodName += (String(Math.random())).substr(2);
+		}
+		obj[methodName] = this;
+
+		var argsStrings = new Array(args.length);
+		for (var i = 0; i < args.length; i++) {
+			argsStrings[i] = "args[" + i + "]";
+		}
+		var script = "obj." + methodName + "(" + argsStrings.join(",") + ")";
+		var returnValue = eval(script);
+		delete obj[methodName];
+		return returnValue;
+	};
+}
+
+/* -------------------------------------------------------------------------- */
+
+var xn = new Object();
+
+(function() {
+	// Utility functions
+
+	// Event listeners
+	var getListenersPropertyName = function(eventName) {
+		return "__listeners__" + eventName;
+	};
+
+	var addEventListener = function(node, eventName, listener, useCapture) {
+		useCapture = Boolean(useCapture);
+		if (node.addEventListener) {
+			node.addEventListener(eventName, listener, useCapture);
+		} else if (node.attachEvent) {
+			node.attachEvent("on" + eventName, listener);
+		} else {
+			var propertyName = getListenersPropertyName(eventName);
+			if (!node[propertyName]) {
+				node[propertyName] = new Array();
+
+				// Set event handler
+				node["on" + eventName] = function(evt) {
+					evt = module.getEvent(evt);
+					var listenersPropertyName = getListenersPropertyName(eventName);
+
+					// Clone the array of listeners to leave the original untouched
+					var listeners = cloneArray(this[listenersPropertyName]);
+					var currentListener;
+
+					// Call each listener in turn
+					while (currentListener = listeners.shift()) {
+						currentListener.call(this, evt);
+					}
+				};
+			}
+			node[propertyName].push(listener);
+		}
+	};
+
+	// Clones an array
+	var cloneArray = function(arr) {
+		var clonedArray = [];
+		for (var i = 0; i < arr.length; i++) {
+			clonedArray[i] = arr[i];
+		}
+		return clonedArray;
+	}
+
+	var isFunction = function(f) {
+		if (!f){ return false; }
+		return (f instanceof Function || typeof f == "function");
+	};
+
+	// CSS Utilities
+	
+	function array_contains(arr, val) {
+		for (var i = 0, len = arr.length; i < len; i++) {
+			if (arr[i] === val) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	function addClass(el, cssClass) {
+		if (!hasClass(el, cssClass)) {
+			if (el.className) {
+				el.className += " " + cssClass;
+			} else {
+				el.className = cssClass;
+			}
+		}
+	}
+
+	function hasClass(el, cssClass) {
+		if (el.className) {
+			var classNames = el.className.split(" ");
+			return array_contains(classNames, cssClass);
+		}
+		return false;
+	}
+
+	function removeClass(el, cssClass) {
+		if (hasClass(el, cssClass)) {
+			// Rebuild the className property
+			var existingClasses = el.className.split(" ");
+			var newClasses = [];
+			for (var i = 0; i < existingClasses.length; i++) {
+				if (existingClasses[i] != cssClass) {
+					newClasses[newClasses.length] = existingClasses[i];
+				}
+			}
+			el.className = newClasses.join(" ");
+		}
+	}
+
+	function replaceClass(el, newCssClass, oldCssClass) {
+		removeClass(el, oldCssClass);
+		addClass(el, newCssClass);
+	}
+
+	function getExceptionStringRep(ex) {
+		if (ex) {
+			var exStr = "Exception: ";
+			if (ex.message) {
+				exStr += ex.message;
+			} else if (ex.description) {
+				exStr += ex.description;
+			}
+			if (ex.lineNumber) {
+				exStr += " on line number " + ex.lineNumber;
+			}
+			if (ex.fileName) {
+				exStr += " in file " + ex.fileName;
+			}
+			return exStr;
+		}
+		return null;
+	}
+
+
+	/* ---------------------------------------------------------------------- */
+
+	/* Configure the test logger try to use FireBug */
+	var log, error;
+	if (window["console"] && typeof console.log == "function") {
+		log = function() {
+			if (xn.test.enableTestDebug) {
+				console.log.apply(console, arguments);
+			}
+		};
+		error = function() {
+			if (xn.test.enableTestDebug) {
+				console.error.apply(console, arguments);
+			}
+		};
+	} else {
+		log = function() {};
+	}
+
+	/* Set up something to report to */
+
+	var initialized = false;
+	var container;
+	var progressBarContainer, progressBar, overallSummaryText;
+	var currentTest = null;
+	var suites = [];
+	var totalTestCount = 0;
+	var currentTestIndex = 0;
+	var testFailed = false;
+	var testsPassedCount = 0;
+	var startTime;
+	
+	var log4javascriptEnabled = false;
+	
+	var nextSuiteIndex = 0;
+	
+	function runNextSuite() {
+		if (nextSuiteIndex < suites.length) {
+			suites[nextSuiteIndex++].run();
+		}
+	}
+	
+	var init = function() {
+		if (initialized) { return true; }
+		
+		container = document.createElement("div");
+		
+		// Create the overall progress bar
+		progressBarContainer = container.appendChild(document.createElement("div"));
+		progressBarContainer.className = "xn_test_progressbar_container xn_test_overallprogressbar_container";
+		progressBar = progressBarContainer.appendChild(document.createElement("div"));
+		progressBar.className = "success";
+
+		document.body.appendChild(container);
+
+		var h1 = progressBar.appendChild(document.createElement("h1"));
+		overallSummaryText = h1.appendChild(document.createTextNode(""));
+
+		initialized = true;
+		
+		// Set up logging
+		log4javascriptEnabled = !!log4javascript && xn.test.enable_log4javascript;
+		
+		function TestLogAppender() {}
+		
+		if (log4javascriptEnabled) {
+			TestLogAppender.prototype = new log4javascript.Appender();
+			TestLogAppender.prototype.layout = new log4javascript.PatternLayout("%d{HH:mm:ss,SSS} %-5p %m");
+			TestLogAppender.prototype.append = function(loggingEvent) {
+				var formattedMessage = this.getLayout().format(loggingEvent);
+				if (this.getLayout().ignoresThrowable()) {
+					formattedMessage += loggingEvent.getThrowableStrRep();
+				}
+				currentTest.addLogMessage(formattedMessage);
+			};
+			
+			var appender = new TestLogAppender();
+			appender.setThreshold(log4javascript.Level.ALL);
+			log4javascript.getRootLogger().addAppender(appender);
+			log4javascript.getRootLogger().setLevel(log4javascript.Level.ALL);
+		}
+
+		startTime = new Date();
+
+		// First, build each suite
+		for (var i = 0; i < suites.length; i++) {
+			suites[i].build();
+			totalTestCount += suites[i].tests.length;
+		}
+		
+		// Now run each suite
+		runNextSuite();
+	};
+	
+	function updateProgressBar() {
+		progressBar.style.width = "" + parseInt(100 * (currentTestIndex) / totalTestCount) + "%";
+		var s = (totalTestCount === 1) ? "" : "s";
+		var timeTaken = new Date().getTime() - startTime.getTime();
+		overallSummaryText.nodeValue = "" + testsPassedCount + " of " + totalTestCount + " test" + s + " passed in " + timeTaken + "ms";
+	}
+
+	addEventListener(window, "load", init);
+
+	/* ---------------------------------------------------------------------- */
+
+	/* Test Suite */
+	var Suite = function(name, callback, hideSuccessful) {
+		this.name = name;
+		this.callback = callback;
+		this.hideSuccessful = hideSuccessful;
+		this.tests = [];
+		this.log = log;
+		this.error = error;
+		this.expanded = true;
+		suites.push(this);
+	}
+
+	Suite.prototype.test = function(name, callback, setUp, tearDown) {
+		this.log("adding a test named " + name)
+		var t = new Test(name, callback, this, setUp, tearDown);
+		this.tests.push(t);
+	};
+
+	Suite.prototype.build = function() {
+		// Build the elements used by the suite
+		var suite = this;
+		this.testFailed = false;
+		this.container = document.createElement("div");
+		this.container.className = "xn_test_suite_container";
+
+		var heading = document.createElement("h2");
+		this.expander = document.createElement("span");
+		this.expander.className = "xn_test_expander";
+		this.expander.onclick = function() {
+			if (suite.expanded) {
+				suite.collapse();
+			} else {
+				suite.expand();
+			}
+		};
+		heading.appendChild(this.expander);
+		
+		this.headingTextNode = document.createTextNode(this.name);
+		heading.appendChild(this.headingTextNode);
+		this.container.appendChild(heading);
+
+		this.reportContainer = document.createElement("dl");
+		this.container.appendChild(this.reportContainer);
+
+		this.progressBarContainer = document.createElement("div");
+		this.progressBarContainer.className = "xn_test_progressbar_container";
+		this.progressBar = document.createElement("div");
+		this.progressBar.className = "success";
+		this.progressBar.innerHTML = "&nbsp;";
+		this.progressBarContainer.appendChild(this.progressBar);
+		this.reportContainer.appendChild(this.progressBarContainer);
+
+		this.expand();
+
+		container.appendChild(this.container);
+
+		// invoke callback to build the tests
+		this.callback.apply(this, [this]);
+	};
+
+	Suite.prototype.run = function() {
+		this.log("running suite '%s'", this.name)
+		this.startTime = new Date();
+
+		// now run the first test
+		this._currentIndex = 0;
+		this.runNextTest();
+	};
+
+	Suite.prototype.updateProgressBar = function() {
+		// Update progress bar
+		this.progressBar.style.width = "" + parseInt(100 * (this._currentIndex) / this.tests.length) + "%";
+		//log(this._currentIndex + ", " + this.tests.length + ", " + progressBar.style.width + ", " + progressBar.className);
+	};
+
+	Suite.prototype.expand = function() {
+		this.expander.innerHTML = "-";
+		replaceClass(this.reportContainer, "xn_test_expanded", "xn_test_collapsed");
+		this.expanded = true;
+	};
+
+	Suite.prototype.collapse = function() {
+		this.expander.innerHTML = "+";
+		replaceClass(this.reportContainer, "xn_test_collapsed", "xn_test_expanded");
+		this.expanded = false;
+	};
+
+	Suite.prototype.finish = function(timeTaken) {
+		var newClass = this.testFailed ? "xn_test_suite_failure" : "xn_test_suite_success";
+		var oldClass = this.testFailed ? "xn_test_suite_success" : "xn_test_suite_failure";
+		replaceClass(this.container, newClass, oldClass);
+
+		this.headingTextNode.nodeValue += " (" + timeTaken + "ms)";
+
+		if (this.hideSuccessful && !this.testFailed) {
+			this.collapse();
+		}
+		runNextSuite();
+	};
+
+	/**
+	 * Works recursively with external state (the next index)
+	 * so that we can handle async tests differently
+	 */
+	Suite.prototype.runNextTest = function() {
+		if (this._currentIndex == this.tests.length) {
+			// finished!
+			var timeTaken = new Date().getTime() - this.startTime.getTime();
+
+			this.finish(timeTaken);
+			return;
+		}
+
+		var suite = this;
+		var t = this.tests[this._currentIndex++];
+		currentTestIndex++;
+
+		if (isFunction(suite.setUp)) {
+			suite.setUp.apply(suite, [t]);
+		}
+		if (isFunction(t.setUp)) {
+			t.setUp.apply(t, [t]);
+		}
+
+		t._run();
+		
+		function afterTest() {
+			if (isFunction(suite.tearDown)) {
+				suite.tearDown.apply(suite, [t]);
+			}
+			if (isFunction(t.tearDown)) {
+				t.tearDown.apply(t, [t]);
+			}
+			suite.log("finished test [%s]", t.name);
+			updateProgressBar();
+			suite.updateProgressBar();
+			suite.runNextTest();
+		}
+		
+		if (t.isAsync) {
+			t.whenFinished = afterTest;
+		} else {
+			setTimeout(afterTest, 1);
+		}
+	};
+
+	Suite.prototype.reportSuccess = function() {
+	};
+
+	/* ---------------------------------------------------------------------- */
+	/**
+	 * Create a new test
+	 */
+	var Test = function(name, callback, suite, setUp, tearDown) {
+		this.name = name;
+		this.callback = callback;
+		this.suite = suite;
+		this.setUp = setUp;
+		this.tearDown = tearDown;
+		this.log = log;
+		this.error = error;
+		this.assertCount = 0;
+		this.logMessages = [];
+		this.logExpanded = false;
+	};
+
+	/**
+	 * Default success reporter, please override
+	 */
+	Test.prototype.reportSuccess = function(name, timeTaken) {
+		/* default success reporting handler */
+		this.reportHeading = document.createElement("dt");
+		var text = this.name + " passed in " + timeTaken + "ms";
+		
+		this.reportHeading.appendChild(document.createTextNode(text));
+
+		this.reportHeading.className = "success";
+		var dd = document.createElement("dd");
+		dd.className = "success";
+
+		this.suite.reportContainer.appendChild(this.reportHeading);
+		this.suite.reportContainer.appendChild(dd);
+		this.createLogReport();
+	};
+
+	/**
+	 * Cause the test to immediately fail
+	 */
+	Test.prototype.reportFailure = function(name, msg, ex) {
+		this.suite.testFailed = true;
+		this.suite.progressBar.className = "failure";
+		progressBar.className = "failure";
+		this.reportHeading = document.createElement("dt");
+		this.reportHeading.className = "failure";
+		var text = document.createTextNode(this.name);
+		this.reportHeading.appendChild(text);
+
+		var dd = document.createElement("dd");
+		dd.appendChild(document.createTextNode(msg));
+		dd.className = "failure";
+
+		this.suite.reportContainer.appendChild(this.reportHeading);
+		this.suite.reportContainer.appendChild(dd);
+		if (ex && ex.stack) {
+			var stackTraceContainer = this.suite.reportContainer.appendChild(document.createElement("code"));
+			stackTraceContainer.className = "xn_test_stacktrace";
+			stackTraceContainer.innerHTML = ex.stack.replace(/\r/g, "\n").replace(/\n{1,2}/g, "<br />");
+		}
+		this.createLogReport();
+	};
+	
+	Test.prototype.createLogReport = function() {
+		if (this.logMessages.length > 0) {
+			this.reportHeading.appendChild(document.createTextNode(" ("));
+			var logToggler = this.reportHeading.appendChild(document.createElement("a"));
+			logToggler.href = "#";
+			logToggler.innerHTML = "show log";
+			var test = this;
+			
+			logToggler.onclick = function() {
+				if (test.logExpanded) {
+					test.hideLogReport();
+					this.innerHTML = "show log";
+					test.logExpanded = false;
+				} else {
+					test.showLogReport();
+					this.innerHTML = "hide log";
+					test.logExpanded = true;
+				}
+				return false;
+			};
+
+			this.reportHeading.appendChild(document.createTextNode(")"));
+			
+			// Create log report
+			this.logReport = this.suite.reportContainer.appendChild(document.createElement("pre"));
+			this.logReport.style.display = "none";
+			this.logReport.className = "xn_test_log_report";
+			var logMessageDiv;
+			for (var i = 0, len = this.logMessages.length; i < len; i++) {
+				logMessageDiv = this.logReport.appendChild(document.createElement("div"));
+				logMessageDiv.appendChild(document.createTextNode(this.logMessages[i]));
+			}
+		}
+	};
+
+	Test.prototype.showLogReport = function() {
+		this.logReport.style.display = "inline-block";
+	};
+		
+	Test.prototype.hideLogReport = function() {
+		this.logReport.style.display = "none";
+	};
+
+	Test.prototype.async = function(timeout, callback) {
+		timeout = timeout || 250;
+		var self = this;
+		var timedOutFunc = function() {
+			if (!self.completed) {
+				var message = (typeof callback === "undefined") ?
+							"Asynchronous test timed out" : callback(self);
+				self.fail(message);
+			}
+		}
+		var timer = setTimeout(function () { timedOutFunc.apply(self, []); }, timeout)
+		this.isAsync = true;
+	};
+
+	/**
+	 * Run the test
+	 */
+	Test.prototype._run = function() {
+		this.log("starting test [%s]", this.name);
+		this.startTime = new Date();
+		currentTest = this;
+		try {
+			this.callback(this);
+			if (!this.completed && !this.isAsync) {
+				this.succeed();
+			}
+		} catch (e) {
+			this.log("test [%s] threw exception [%s]", this.name, e);
+			var s = (this.assertCount === 1) ? "" : "s";
+			this.fail("Exception thrown after " + this.assertCount + " successful assertion" + s + ": " + getExceptionStringRep(e), e);
+		}
+	};
+
+	/**
+	 * Cause the test to immediately succeed
+	 */
+	Test.prototype.succeed = function() {
+		if (this.completed) { return false; }
+		// this.log("test [%s] succeeded", this.name);
+		this.completed = true;
+		var timeTaken = new Date().getTime() - this.startTime.getTime();
+		testsPassedCount++;
+		this.reportSuccess(this.name, timeTaken);
+		if (this.whenFinished) {
+			this.whenFinished();
+		}
+	};
+
+	Test.prototype.fail = function(msg, ex)	{
+		if (typeof msg != "string") {
+			msg = getExceptionStringRep(msg);
+		}
+		if (this.completed) { return false; }
+		this.completed = true;
+		// this.log("test [%s] failed", this.name);
+		this.reportFailure(this.name, msg, ex);
+		if (this.whenFinished) {
+			this.whenFinished();
+		}
+	};
+	
+	Test.prototype.addLogMessage = function(logMessage) {
+		this.logMessages.push(logMessage);
+	};
+
+	/* assertions */
+	var displayStringForValue = function(obj) {
+		if (obj === null) {
+			return "null";
+		} else if (typeof obj === "undefined") {
+			return "undefined";
+		}
+		return obj.toString();
+	};
+
+	var assert = function(args, expectedArgsCount, testFunction, defaultComment) {
+		this.assertCount++;
+		var comment = defaultComment;
+		var i;
+		var success;
+		var values = [];
+		if (args.length == expectedArgsCount) {
+			for (i = 0; i < args.length; i++) {
+				values[i] = args[i];
+			}
+		} else if (args.length == expectedArgsCount + 1) {
+			comment = args[0];
+			for (i = 1; i < args.length; i++) {
+				values[i - 1] = args[i];
+			}
+		} else {
+			throw new Error("Invalid number of arguments passed to assert function");
+		}
+		success = testFunction(values);
+		if (!success) {
+			var regex = /\{([0-9]+)\}/;
+			while (regex.test(comment)) {
+				comment = comment.replace(regex, displayStringForValue(values[parseInt(RegExp.$1)]));
+			}
+			this.fail("Test failed on assertion " + this.assertCount + ": " + comment);
+		}
+	};
+
+	var testNull = function(values) {
+		return (values[0] === null);
+	};
+
+	Test.prototype.assertNull = function() {
+		assert.apply(this, [arguments, 1, testNull, "Expected to be null but was {0}"]);
+	}
+
+	var testNotNull = function(values) {
+		return (values[0] !== null);
+	};
+
+	Test.prototype.assertNotNull = function() {
+		assert.apply(this, [arguments, 1, testNotNull, "Expected not to be null but was {0}"]);
+	}
+
+	var testBoolean = function(values) {
+		return (Boolean(values[0]));
+	};
+
+	Test.prototype.assert = function() {
+		assert.apply(this, [arguments, 1, testBoolean, "Expected not to be equivalent to false"]);
+	};
+
+	var testTrue = function(values) {
+		return (values[0] === true);
+	};
+
+	Test.prototype.assertTrue = function() {
+		assert.apply(this, [arguments, 1, testTrue, "Expected to be true but was {0}"]);
+	};
+
+	Test.prototype.assert = function() {
+		assert.apply(this, [arguments, 1, testTrue, "Expected to be true but was {0}"]);
+	};
+
+	var testFalse = function(values) {
+		return (values[0] === false);
+	};
+
+	Test.prototype.assertFalse = function() {
+		assert.apply(this, [arguments, 1, testFalse, "Expected to be false but was {0}"]);
+	}
+
+	var testEquivalent = function(values) {
+		return (values[0] === values[1]);
+	};
+
+	Test.prototype.assertEquivalent = function() {
+		assert.apply(this, [arguments, 2, testEquivalent, "Expected to be equal but values were {0} and {1}"]);
+	}
+
+	var testNotEquivalent = function(values) {
+		return (values[0] !== values[1]);
+	};
+
+	Test.prototype.assertNotEquivalent = function() {
+		assert.apply(this, [arguments, 2, testNotEquivalent, "Expected to be not equal but values were {0} and {1}"]);
+	}
+
+	var testEquals = function(values) {
+		return (values[0] == values[1]);
+	};
+
+	Test.prototype.assertEquals = function() {
+		assert.apply(this, [arguments, 2, testEquals, "Expected to be equal but values were {0} and {1}"]);
+	}
+
+	var testNotEquals = function(values) {
+		return (values[0] != values[1]);
+	};
+
+	Test.prototype.assertNotEquals = function() {
+		assert.apply(this, [arguments, 2, testNotEquals, "Expected to be not equal but values were {0} and {1}"]);
+	}
+
+	var testRegexMatches = function(values) {
+		return (values[0].test(values[1]));
+	};
+
+	Test.prototype.assertRegexMatches = function() {
+		assert.apply(this, [arguments, 2, testRegexMatches, "Expected regex {0} to match value {1} but it didn't"]);
+	}
+
+	Test.prototype.assertError = function(f, errorType) {
+		try {
+			f();
+			this.fail("Expected error to be thrown");
+		} catch (e) {
+			if (errorType && (!(e instanceof errorType))) {
+				this.fail("Expected error of type " + errorType + " to be thrown but error thrown was " + e);
+			}
+		}
+	};
+
+	/**
+	 * Execute a synchronous test
+	 */
+	xn.test = function(name, callback) {
+		xn.test.suite("Anonymous", function(s) {
+			s.test(name, callback);
+		});
+	}
+
+	/**
+	 * Create a test suite with a given name
+	 */
+	xn.test.suite = function(name, callback, hideSuccessful) {
+		var s = new Suite(name, callback, hideSuccessful);
+	}
+})();
\ No newline at end of file
diff --git a/planetstack/core/static/main.js b/planetstack/core/static/main.js
new file mode 100644
index 0000000..486d65a
--- /dev/null
+++ b/planetstack/core/static/main.js
@@ -0,0 +1,153 @@
+$(document).ready(function() {
+
+	
+	function getServerData(url, label, value) {
+		var jqxhr = $.getJSON( url, function(data) {
+			if (value == 'nodesValue') {
+				var unit = '';
+				window.nodesCnt = data;
+			} else if (value == 'cpuValue'){
+				var unit = '%';
+				window.cpuCnt = data;
+			} else if (value == 'bandwidthValue'){
+				var unit = '';
+				window.bandData = data;
+			}
+			var legend = data.legend;
+			var data = data.data;
+			var dataLength = data.length - 1;
+			$('.'+label).text(legend).show();
+			$('.'+value).text(Math.round(data[dataLength][1])+unit).show();
+		})
+		
+	}
+	var selectedNodeTxt = $('.currentOriginalNode').text();
+	selectedNodeTxt = selectedNodeTxt.trim();
+	selectedNodeTxt = selectedNodeTxt.split(' ').join('');//selectedNodeTxt.replace(" ", "")
+	var parentNodeTxt = $('.selectedMainNav').text();
+	parentNodeTxt = parentNodeTxt.replace("/\n","");
+ 	parentNodeTxt = parentNodeTxt.replace("»","");
+	parentNodeTxt = parentNodeTxt.trim();
+	
+	baseNodeQuery = 'SELECT Minute(time) as Minute,COUNT(distinct %hostname) FROM [vicci.demoevents]';
+	baseCpuQuery = 'SELECT Minute(time) as Minute,AVG(i0) as Cpu FROM [vicci.demoevents]';
+	baseBwQuery = 'SELECT Minute(time) as Minute,AVG(i1) as Requests FROM [vicci.demoevents]';
+	groupByClause = ' GROUP BY Minute ORDER BY Minute';
+
+	if (selectedNodeTxt ) {
+		if (parentNodeTxt.length > 0 && parentNodeTxt.charAt(parentNodeTxt.length-1)=='s') {
+			parentNodeTxt = parentNodeTxt.substring(0, parentNodeTxt.length-1);
+		}
+		if (parentNodeTxt=='Slice') {
+			whereClause = " WHERE s3='"+selectedNodeTxt+"'";
+		} 
+		else if (parentNodeTxt=='Site') {
+			whereClause = " WHERE s2='"+selectedNodeTxt+"' OR %hostname CONTAINS '"+selectedNodeTxt+"'";
+		} 
+		else if (parentNodeTxt=='Node') {
+			whereClause = " WHERE %hostname='"+selectedNodeTxt+"'";
+			alert(whereClause);
+		} else {
+			console.log('Error: Unkown object type:'+parentNodeTxt);
+		}
+	} else {
+		whereClause = '';
+	}
+	finalNodeQuery = encodeURIComponent(baseNodeQuery + whereClause + groupByClause);
+	finalCpuQuery = encodeURIComponent(baseCpuQuery + whereClause + groupByClause);
+	finalBwQuery = encodeURIComponent(baseBwQuery + whereClause + groupByClause);
+	getServerData('http://cloud-scrutiny.appspot.com/command?action=send_query&legend=Node+Count&tqx=saber&q='+finalNodeQuery,'nodesLabel','nodesValue');
+	getServerData('http://cloud-scrutiny.appspot.com/command?action=send_query&legend=Load&tqx=saber&q='+finalCpuQuery,'cpuLabel','cpuValue');
+	getServerData('http://cloud-scrutiny.appspot.com/command?action=send_query&legend=Bandwidth&tqx=saber&q='+finalBwQuery,'bandwidthLabel','bandwidthValue');
+
+	$('.nodesLabel, .nodesValue').click(function() {
+		var jsonData = window.nodesCnt;
+		renderChart(jsonData);
+	});
+	$('.cpuLabel, .cpuValue').click(function() {
+		var jsonData = window.cpuCnt;
+		renderChart(jsonData);
+	});
+	$('.bandwidthLabel, .bandwidthValue').click(function() {
+		var jsonData = window.bandData;
+		renderChart(jsonData);
+	});
+
+	function renderChart(jsonData) {
+		$('#graph').empty();
+		$('#chartsModal').modal('show');
+		$('.modal-body').scrollTop(0)
+		var margin = {top: 0, right: 100, bottom: 100, left: 175},
+		width = 520 - margin.left - margin.right,
+		height = 300 - margin.top - margin.bottom;
+
+		var parseDate = d3.time.format("%Y-%m-%m-%H-%M").parse;
+
+		var x = d3.time.scale()
+		.range([0, width]);
+
+		var y = d3.scale.linear()
+		.range([height, 0]);
+
+		var xAxis = d3.svg.axis()
+		.scale(x)
+		.ticks(d3.time.minutes, 15)
+		.orient("bottom");
+
+		var yAxis = d3.svg.axis()
+		.scale(y)
+		.ticks(4)
+		.orient("left");
+
+		var line = d3.svg.line()
+		.x(function(d) { return x(d.date); })
+		.y(function(d) { return y(d.value); });
+
+		var svg = d3.select("#graph").append("svg")
+		.attr("width", width + margin.left + margin.right)
+		.attr("height", height + margin.top + margin.bottom)
+		.append("g")
+		.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
+
+		/*var data_path = "http://sabertooth.cs.princeton.edu/graphs/UpNodes";
+		d3.json(data_path, function(error, input) {*/
+			//jsonData = JSON.stringify(eval("(" + jsonData + ")"));
+			data = jsonData.data;//input['data'];
+			legend = jsonData.legend;//input['legend']
+			$('#chartHeading').text(legend);
+			data.forEach(function(d) {
+				d.date = new Date(d[0]*1000);
+				d.value = +d[1];
+				});
+					x.domain(d3.extent(data, function(d) { return d.date; }));
+
+					var e = d3.extent(data, function(d) { return d.value;});
+					e = [e[0]-1,e[1]+1];
+
+					y.domain(e);
+
+					svg.append("g")
+					.attr("class", "x axis")
+					.attr("transform", "translate(0," + height + ")")
+					.attr("x", 5)
+					.call(xAxis);
+
+					svg.append("g")
+					.attr("class", "y axis")
+					.call(yAxis)
+					.append("text")
+					.attr("transform", "rotate(-90)")
+					.attr("y", 6)
+					.attr("dy", ".71em")
+					.style("text-anchor", "end")
+					.text(legend)
+					.attr("class", "legend");
+
+					svg.append("path")
+					.datum(data)
+					.attr("class", "line")
+					.attr("d", line);
+				//});
+	}
+
+})
diff --git a/planetstack/core/static/planetstack.css b/planetstack/core/static/planetstack.css
index 873a9d9..d59adb7 100644
--- a/planetstack/core/static/planetstack.css
+++ b/planetstack/core/static/planetstack.css
@@ -488,15 +488,12 @@
     background-position: 0;*/
 }
 
-.icon-home ,.icon-deployment ,.icon-site ,.icon-slice ,.icon-user, .icon-reservation, .icon-app{
+.icon-home ,.icon-deployment ,.icon-site ,.icon-slice ,.icon-user, .icon-reservation{
 background-position: left center;
 width:22px;
 height:22px;	
 }
 
-.icon-app {
-background-image: url("opencloudApp.png");
-}
 .icon-home {
 background-image: url("Home.png");
 }
@@ -535,3 +532,161 @@
 .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;
+}
+
+
+
+
+
+/* Charts CSS */
+p.numeral
+{
+	font-size:32pt;
+	color:#ffffff;
+	opacity: 0.7;
+	font-family:Helvetica Neue;
+	font-weight:100;
+	text-align:center;
+	line-height:75%;
+}
+
+.helper-text
+{
+	border: 1px solid #fff;
+	padding: 7px;
+	border-radius: 18px;
+	font-size:13pt;
+	color:#ffffff;
+	opacity: 0.7;
+	font-family:Helvetica Neue;
+	font-weight:200;
+	text-align:center;
+	line-height:100%;
+}
+p.osobject
+{
+	font-size:12pt;
+	color:#ffffff;
+	opacity: 0.7;
+	font-family:Helvetica Neue;
+	font-weight:200;
+	text-align:center;
+	line-height:100%;
+}
+
+p.heading
+{
+	font-size:20pt;
+	color:#ffffff;
+	opacity: 0.7;
+	font-family:Helvetica Neue;
+	font-weight:200;
+	text-align:center;
+}
+
+/*p.heading
+{
+	font-size:32pt;
+	color:#ffffff;
+	opacity: 0.7;
+	font-family:Helvetica Neue;
+	font-weight:200;
+	text-align:center;
+}*/
+
+div.graph 
+{
+	height:340px;
+}
+
+div.numeral 
+{
+	height:120px;
+}
+
+div.heading 
+{
+	height:10px;
+}
+
+div.padding 
+{
+	height:20px;
+}
+
+div.chartContainer
+{
+	background-image:url('chartsBg.jpg');
+	width:527px;
+	height:400px;
+	border:1px;
+}
+
+/* D3 */
+
+.axis path,
+.axis line {
+  fill: none;
+  stroke: #ffffff;
+  opacity: 0.7;
+  shape-rendering: crispEdges;
+}
+
+
+.x.axis path {
+  display: none;
+}
+
+.x.axis text {
+  fill: white;
+  opacity: 0.5;
+}
+
+.y.axis text {
+  opacity: 0.5;
+  fill: white;
+}
+
+.y.axis text.legend {
+  opacity: 1.0;
+  fill: white;
+  font-size:8pt;
+}
+
+.line {
+  fill: none;
+  stroke: white;
+  stroke-width: 3px;
+  opacity: 0.6;
+}
+
+
+/* Charts CSS */
diff --git a/planetstack/deployment_auth.py b/planetstack/deployment_auth.py
new file mode 100644
index 0000000..f7383ea
--- /dev/null
+++ b/planetstack/deployment_auth.py
@@ -0,0 +1,25 @@
+## 
+# This file contains the auth credentials used to access openstack deployments 
+# we wish to manage. The 'default' credentials will be used for any deployments
+# not specifed here.
+#
+
+deployment_auth = {
+# Example
+#   'deployment_name': {
+#       'user': 'email@domain.com',
+#       'pasword': 'password',
+#       'tenant': 'tenant',    
+#       'url': 'http://localhost:5000/v2.0/',
+#       'token': 'ADMIN',
+#       'endpoint': 'http://localhost:35357/v2.0/'    
+#    }, 
+    
+    'default': {
+        'user': 'admin@domain.com',
+        'password': 'admin',
+        'tenant': 'admin', 
+        'url': 'http://localhost:5000/v2.0/'     
+    },
+
+}
diff --git a/planetstack/observer/deleters/site_deleter.py b/planetstack/observer/deleters/site_deleter.py
index bb29c94..a558eaf 100644
--- a/planetstack/observer/deleters/site_deleter.py
+++ b/planetstack/observer/deleters/site_deleter.py
@@ -1,5 +1,5 @@
 from core.models import Site
-from observer.delete import Deleter
+from observer.deleter import Deleter
 
 class SiteDeleter(Deleter):
     model='Site'
diff --git a/planetstack/observer/event_loop.py b/planetstack/observer/event_loop.py
index bdf5ce3..6b77236 100644
--- a/planetstack/observer/event_loop.py
+++ b/planetstack/observer/event_loop.py
@@ -18,303 +18,259 @@
 from planetstack.config import Config
 from observer.steps import *
 from syncstep import SyncStep
+from toposort import toposort
 
 debug_mode = False
 
 logger = Logger(level=logging.INFO)
 
 class StepNotReady(Exception):
-    pass
-
-def toposort(g, steps=None):
-    if (not steps):
-        keys = set(g.keys())
-        values = set({})
-        for v in g.values():
-            values=values | set(v)
-        
-        steps=list(keys|values)
-    reverse = {}
-
-    for k,v in g.items():
-        for rk in v:
-            try:
-                reverse[rk].append(k)
-            except:
-                reverse[rk]=k
-
-    sources = []
-    for k,v in g.items():
-        if not reverse.has_key(k):
-            sources.append(k)
-
-
-    for k,v in reverse.iteritems():
-        if (not v):
-            sources.append(k)
-
-    order = []
-    marked = []
-
-    while sources:
-        n = sources.pop()
-        try:
-            for m in g[n]:
-                if m not in marked:
-                    sources.append(m)
-                    marked.append(m)
-        except KeyError:
-            pass
-        if (n in steps):
-            order.append(n)
-
-    order.reverse()
-    order.extend(set(steps)-set(order))
-    return order
+	pass
 
 class NoOpDriver:
-    def __init__(self):
-         self.enabled = True
+	def __init__(self):
+		 self.enabled = True
 
 class PlanetStackObserver:
-    #sync_steps = [SyncNetworks,SyncNetworkSlivers,SyncSites,SyncSitePrivileges,SyncSlices,SyncSliceMemberships,SyncSlivers,SyncSliverIps,SyncExternalRoutes,SyncUsers,SyncRoles,SyncNodes,SyncImages,GarbageCollector]
-    sync_steps = []
+	#sync_steps = [SyncNetworks,SyncNetworkSlivers,SyncSites,SyncSitePrivileges,SyncSlices,SyncSliceMemberships,SyncSlivers,SyncSliverIps,SyncExternalRoutes,SyncUsers,SyncRoles,SyncNodes,SyncImages,GarbageCollector]
+	sync_steps = []
 
-    def __init__(self):
-        # The Condition object that gets signalled by Feefie events
-        self.step_lookup = {}
-        self.load_sync_step_modules()
-        self.load_sync_steps()
-        self.event_cond = threading.Condition()
+	def __init__(self):
+		# The Condition object that gets signalled by Feefie events
+		self.step_lookup = {}
+		self.load_sync_step_modules()
+		self.load_sync_steps()
+		self.event_cond = threading.Condition()
 
 
-        self.driver_kind = getattr(Config(), "observer_driver", "openstack")
-        if self.driver_kind=="openstack":
-            self.driver = OpenStackDriver()
-        else:
-            self.driver = NoOpDriver()
+		self.driver_kind = getattr(Config(), "observer_driver", "openstack")
+		if self.driver_kind=="openstack":
+			self.driver = OpenStackDriver()
+		else:
+			self.driver = NoOpDriver()
 
-    def wait_for_event(self, timeout):
-        self.event_cond.acquire()
-        self.event_cond.wait(timeout)
-        self.event_cond.release()
+	def wait_for_event(self, timeout):
+		self.event_cond.acquire()
+		self.event_cond.wait(timeout)
+		self.event_cond.release()
 
-    def wake_up(self):
-        logger.info('Wake up routine called. Event cond %r'%self.event_cond)
-        self.event_cond.acquire()
-        self.event_cond.notify()
-        self.event_cond.release()
+	def wake_up(self):
+		logger.info('Wake up routine called. Event cond %r'%self.event_cond)
+		self.event_cond.acquire()
+		self.event_cond.notify()
+		self.event_cond.release()
 
-    def load_sync_step_modules(self, step_dir=None):
-        if step_dir is None:
-            if hasattr(Config(), "observer_steps_dir"):
-                step_dir = Config().observer_steps_dir
-            else:
-                step_dir = "/opt/planetstack/observer/steps"
+	def load_sync_step_modules(self, step_dir=None):
+		if step_dir is None:
+			if hasattr(Config(), "observer_steps_dir"):
+				step_dir = Config().observer_steps_dir
+			else:
+				step_dir = "/opt/planetstack/observer/steps"
 
-        for fn in os.listdir(step_dir):
-            pathname = os.path.join(step_dir,fn)
-            if os.path.isfile(pathname) and fn.endswith(".py") and (fn!="__init__.py"):
-                module = imp.load_source(fn[:-3],pathname)
-                for classname in dir(module):
-                    c = getattr(module, classname, None)
+		for fn in os.listdir(step_dir):
+			pathname = os.path.join(step_dir,fn)
+			if os.path.isfile(pathname) and fn.endswith(".py") and (fn!="__init__.py"):
+				module = imp.load_source(fn[:-3],pathname)
+				for classname in dir(module):
+					c = getattr(module, classname, None)
 
-                    # make sure 'c' is a descendent of SyncStep and has a
-                    # provides field (this eliminates the abstract base classes
-                    # since they don't have a provides)
+					# make sure 'c' is a descendent of SyncStep and has a
+					# provides field (this eliminates the abstract base classes
+					# since they don't have a provides)
 
-                    if inspect.isclass(c) and issubclass(c, SyncStep) and hasattr(c,"provides") and (c not in self.sync_steps):
-                        self.sync_steps.append(c)
-        logger.info('loaded sync steps: %s' % ",".join([x.__name__ for x in self.sync_steps]))
-        # print 'loaded sync steps: %s' % ",".join([x.__name__ for x in self.sync_steps])
+					if inspect.isclass(c) and issubclass(c, SyncStep) and hasattr(c,"provides") and (c not in self.sync_steps):
+						self.sync_steps.append(c)
+		logger.info('loaded sync steps: %s' % ",".join([x.__name__ for x in self.sync_steps]))
+		# print 'loaded sync steps: %s' % ",".join([x.__name__ for x in self.sync_steps])
 
-    def load_sync_steps(self):
-        dep_path = Config().observer_dependency_graph
-        logger.info('Loading model dependency graph from %s' % dep_path)
-        try:
-            # This contains dependencies between records, not sync steps
-            self.model_dependency_graph = json.loads(open(dep_path).read())
-        except Exception,e:
-            raise e
+	def load_sync_steps(self):
+		dep_path = Config().observer_dependency_graph
+		logger.info('Loading model dependency graph from %s' % dep_path)
+		try:
+			# This contains dependencies between records, not sync steps
+			self.model_dependency_graph = json.loads(open(dep_path).read())
+		except Exception,e:
+			raise e
 
-        try:
-            backend_path = Config().observer_pl_dependency_graph
-            logger.info('Loading backend dependency graph from %s' % backend_path)
-            # This contains dependencies between backend records
-            self.backend_dependency_graph = json.loads(open(backend_path).read())
-        except Exception,e:
-            logger.info('Backend dependency graph not loaded')
-            # We can work without a backend graph
-            self.backend_dependency_graph = {}
+		try:
+			backend_path = Config().observer_pl_dependency_graph
+			logger.info('Loading backend dependency graph from %s' % backend_path)
+			# This contains dependencies between backend records
+			self.backend_dependency_graph = json.loads(open(backend_path).read())
+		except Exception,e:
+			logger.info('Backend dependency graph not loaded')
+			# We can work without a backend graph
+			self.backend_dependency_graph = {}
 
-        provides_dict = {}
-        for s in self.sync_steps:
-            self.step_lookup[s.__name__] = s 
-            for m in s.provides:
-                try:
-                    provides_dict[m.__name__].append(s.__name__)
-                except KeyError:
-                    provides_dict[m.__name__]=[s.__name__]
+		provides_dict = {}
+		for s in self.sync_steps:
+			self.step_lookup[s.__name__] = s 
+			for m in s.provides:
+				try:
+					provides_dict[m.__name__].append(s.__name__)
+				except KeyError:
+					provides_dict[m.__name__]=[s.__name__]
 
-                
-        step_graph = {}
-        for k,v in self.model_dependency_graph.iteritems():
-            try:
-                for source in provides_dict[k]:
-                    for m in v:
-                        try:
-                            for dest in provides_dict[m]:
-                                # no deps, pass
-                                try:
-                                    step_graph[source].append(dest)
-                                except:
-                                    step_graph[source]=[dest]
-                        except KeyError:
-                            pass
-                    
-            except KeyError:
-                pass
-                # no dependencies, pass
-        
-        #import pdb
-        #pdb.set_trace()
-        if (self.backend_dependency_graph):
-            backend_dict = {}
-            for s in self.sync_steps:
-                for m in s.serves:
-                    backend_dict[m]=s.__name__
-                    
-            for k,v in backend_dependency_graph.iteritems():
-                try:
-                    source = backend_dict[k]
-                    for m in v:
-                        try:
-                            dest = backend_dict[m]
-                        except KeyError:
-                            # no deps, pass
-                            pass
-                        step_graph[source]=dest
-                        
-                except KeyError:
-                    pass
-                    # no dependencies, pass
+				
+		step_graph = {}
+		for k,v in self.model_dependency_graph.iteritems():
+			try:
+				for source in provides_dict[k]:
+					for m in v:
+						try:
+							for dest in provides_dict[m]:
+								# no deps, pass
+								try:
+									if (dest not in step_graph[source]):
+										step_graph[source].append(dest)
+								except:
+									step_graph[source]=[dest]
+						except KeyError:
+							pass
+					
+			except KeyError:
+				pass
+				# no dependencies, pass
+		
+		#import pdb
+		#pdb.set_trace()
+		if (self.backend_dependency_graph):
+			backend_dict = {}
+			for s in self.sync_steps:
+				for m in s.serves:
+					backend_dict[m]=s.__name__
+					
+			for k,v in backend_dependency_graph.iteritems():
+				try:
+					source = backend_dict[k]
+					for m in v:
+						try:
+							dest = backend_dict[m]
+						except KeyError:
+							# no deps, pass
+							pass
+						step_graph[source]=dest
+						
+				except KeyError:
+					pass
+					# no dependencies, pass
 
-        dependency_graph = step_graph
+		dependency_graph = step_graph
 
-        self.ordered_steps = toposort(dependency_graph, map(lambda s:s.__name__,self.sync_steps))
-        print "Order of steps=",self.ordered_steps
-        self.load_run_times()
-        
+		self.ordered_steps = toposort(dependency_graph, map(lambda s:s.__name__,self.sync_steps))
+		print "Order of steps=",self.ordered_steps
+		self.load_run_times()
+		
 
-    def check_duration(self, step, duration):
-        try:
-            if (duration > step.deadline):
-                logger.info('Sync step %s missed deadline, took %.2f seconds'%(step.name,duration))
-        except AttributeError:
-            # S doesn't have a deadline
-            pass
+	def check_duration(self, step, duration):
+		try:
+			if (duration > step.deadline):
+				logger.info('Sync step %s missed deadline, took %.2f seconds'%(step.name,duration))
+		except AttributeError:
+			# S doesn't have a deadline
+			pass
 
-    def update_run_time(self, step):
-        self.last_run_times[step.__name__]=time.time()
+	def update_run_time(self, step):
+		self.last_run_times[step.__name__]=time.time()
 
-    def check_schedule(self, step):
-        time_since_last_run = time.time() - self.last_run_times.get(step.__name__, 0)
-        try:
-            if (time_since_last_run < step.requested_interval):
-                raise StepNotReady
-        except AttributeError:
-            logger.info('Step %s does not have requested_interval set'%step.__name__)
-            raise StepNotReady
-    
-    def load_run_times(self):
-        try:
-            jrun_times = open('/tmp/observer_run_times').read()
-            self.last_run_times = json.loads(jrun_times)
-        except:
-            self.last_run_times={}
-            for e in self.ordered_steps:
-                self.last_run_times[e]=0
+	def check_schedule(self, step):
+		time_since_last_run = time.time() - self.last_run_times.get(step.__name__, 0)
+		try:
+			if (time_since_last_run < step.requested_interval):
+				raise StepNotReady
+		except AttributeError:
+			logger.info('Step %s does not have requested_interval set'%step.__name__)
+			raise StepNotReady
+	
+	def load_run_times(self):
+		try:
+			jrun_times = open('/tmp/observer_run_times').read()
+			self.last_run_times = json.loads(jrun_times)
+		except:
+			self.last_run_times={}
+			for e in self.ordered_steps:
+				self.last_run_times[e]=0
 
 
-    def save_run_times(self):
-        run_times = json.dumps(self.last_run_times)
-        open('/tmp/observer_run_times','w').write(run_times)
+	def save_run_times(self):
+		run_times = json.dumps(self.last_run_times)
+		open('/tmp/observer_run_times','w').write(run_times)
 
-    def check_class_dependency(self, step, failed_steps):
-        step.dependenices = []
-        for obj in step.provides:
-            step.dependenices.extend(self.model_dependency_graph.get(obj.__name__, []))
-        for failed_step in failed_steps:
-            if (failed_step in step.dependencies):
-                raise StepNotReady
+	def check_class_dependency(self, step, failed_steps):
+		step.dependenices = []
+		for obj in step.provides:
+			step.dependenices.extend(self.model_dependency_graph.get(obj.__name__, []))
+		for failed_step in failed_steps:
+			if (failed_step in step.dependencies):
+				raise StepNotReady
 
-    def run(self):
-        if not self.driver.enabled:
-            return
-        if (self.driver_kind=="openstack") and (not self.driver.has_openstack):
-            return
+	def run(self):
+		if not self.driver.enabled:
+			return
+		if (self.driver_kind=="openstack") and (not self.driver.has_openstack):
+			return
 
-        while True:
-            try:
-                logger.info('Waiting for event')
-                tBeforeWait = time.time()
-                self.wait_for_event(timeout=30)
-                logger.info('Observer woke up')
+		while True:
+			try:
+				logger.info('Waiting for event')
+				tBeforeWait = time.time()
+				self.wait_for_event(timeout=30)
+				logger.info('Observer woke up')
 
-                # Set of whole steps that failed
-                failed_steps = []
+				# Set of whole steps that failed
+				failed_steps = []
 
-                # Set of individual objects within steps that failed
-                failed_step_objects = set()
+				# Set of individual objects within steps that failed
+				failed_step_objects = set()
 
-                for S in self.ordered_steps:
-                    step = self.step_lookup[S]
-                    start_time=time.time()
-                    
-                    sync_step = step(driver=self.driver)
-                    sync_step.__name__ = step.__name__
-                    sync_step.dependencies = []
-                    try:
-                        mlist = sync_step.provides
-                        
-                        for m in mlist:
-                            sync_step.dependencies.extend(self.model_dependency_graph[m.__name__])
-                    except KeyError:
-                        pass
-                    sync_step.debug_mode = debug_mode
+				for S in self.ordered_steps:
+					step = self.step_lookup[S]
+					start_time=time.time()
+					
+					sync_step = step(driver=self.driver)
+					sync_step.__name__ = step.__name__
+					sync_step.dependencies = []
+					try:
+						mlist = sync_step.provides
+						
+						for m in mlist:
+							sync_step.dependencies.extend(self.model_dependency_graph[m.__name__])
+					except KeyError:
+						pass
+					sync_step.debug_mode = debug_mode
 
-                    should_run = False
-                    try:
-                        # Various checks that decide whether
-                        # this step runs or not
-                        self.check_class_dependency(sync_step, failed_steps) # dont run Slices if Sites failed
-                        self.check_schedule(sync_step) # dont run sync_network_routes if time since last run < 1 hour
-                        should_run = True
-                    except StepNotReady:
-                        logging.info('Step not ready: %s'%sync_step.__name__)
-                        failed_steps.append(sync_step)
-                    except:
-                        failed_steps.append(sync_step)
+					should_run = False
+					try:
+						# Various checks that decide whether
+						# this step runs or not
+						self.check_class_dependency(sync_step, failed_steps) # dont run Slices if Sites failed
+						self.check_schedule(sync_step) # dont run sync_network_routes if time since last run < 1 hour
+						should_run = True
+					except StepNotReady:
+						logging.info('Step not ready: %s'%sync_step.__name__)
+						failed_steps.append(sync_step)
+					except:
+						failed_steps.append(sync_step)
 
-                    if (should_run):
-                        try:
-                            duration=time.time() - start_time
+					if (should_run):
+						try:
+							duration=time.time() - start_time
 
-                            logger.info('Executing step %s' % sync_step.__name__)
+							logger.info('Executing step %s' % sync_step.__name__)
 
-                            # ********* This is the actual sync step
-                            #import pdb
-                            #pdb.set_trace()
-                            failed_objects = sync_step(failed=list(failed_step_objects))
+							# ********* This is the actual sync step
+							#import pdb
+							#pdb.set_trace()
+							failed_objects = sync_step(failed=list(failed_step_objects))
 
 
-                            self.check_duration(sync_step, duration)
-                            if failed_objects:
-                                failed_step_objects.update(failed_objects)
-                            self.update_run_time(sync_step)
-                        except:
-                            failed_steps.append(S)
-                self.save_run_times()
-            except:
-                logger.log_exc("Exception in observer run loop")
-                traceback.print_exc()
+							self.check_duration(sync_step, duration)
+							if failed_objects:
+								failed_step_objects.update(failed_objects)
+							self.update_run_time(sync_step)
+						except:
+							failed_steps.append(S)
+				self.save_run_times()
+			except:
+				logger.log_exc("Exception in observer run loop")
+				traceback.print_exc()
diff --git a/planetstack/observer/steps/garbage_collector.py b/planetstack/observer/steps/garbage_collector.py
index a13fd22..34ecd77 100644
--- a/planetstack/observer/steps/garbage_collector.py
+++ b/planetstack/observer/steps/garbage_collector.py
@@ -6,6 +6,7 @@
 from planetstack.config import Config
 from util.logger import Logger, logging
 from observer.openstacksyncstep import OpenStackSyncStep
+from deployment_auth import deployment_auth
 from core.models import *
 
 logger = Logger(level=logging.INFO)
@@ -69,17 +70,20 @@
             slice_dict[slice.name] = slice
 
         # delete keystone tenants that don't have a site record
-        tenants = self.driver.shell.keystone.tenants.findall()
-        system_tenants = ['admin','service', 'invisible_to_admin']
-        for tenant in tenants:
-            if tenant.name in system_tenants: 
-                continue
-            if tenant.name not in site_dict and tenant.name not in slice_dict:
-                try:
-                    self.driver.delete_tenant(tenant.id)
-                    logger.info("deleted tenant: %s" % (tenant))
-                except:
-                    logger.log_exc("delete tenant failed: %s" % tenant)
+        for deployment in deployment_auth:
+            driver = self.driver.admin_driver(deployment=deployment)
+            tenants = driver.shell.keystone.tenants.findall()
+
+            system_tenants = ['admin','service', 'invisible_to_admin']
+            for tenant in tenants:
+                if tenant.name in system_tenants: 
+                    continue
+                if tenant.name not in site_dict and tenant.name not in slice_dict:
+                    try:
+                        driver.delete_tenant(tenant.id)
+                        logger.info("deleted tenant: %s" % (tenant))
+                    except:
+                        logger.log_exc("delete tenant failed: %s" % tenant)
 
 
     def gc_users(self):
@@ -96,16 +100,18 @@
 
         # delete keystone users that don't have a user record
         system_users = ['admin', 'nova', 'quantum', 'glance', 'cinder', 'swift', 'service', 'demo']
-        users = self.driver.shell.keystone.users.findall()
-        for user in users:
-            if user.name in system_users:
-                continue
-            if user.id not in user_dict:
-                try:
-                    self.driver.delete_user(user.id)
-                    logger.info("deleted user: %s" % user)
-                except:
-                    logger.log_exc("delete user failed: %s" % user)
+        for deployment in deployment_auth:
+            driver = self.driver.admin_driver(deployment=deployment)
+            users = driver.shell.keystone.users.findall()
+            for user in users:
+                if user.name in system_users:
+                    continue
+                if user.id not in user_dict:
+                    try:
+                        self.driver.delete_user(user.id)
+                        logger.info("deleted user: %s" % user)
+                    except:
+                        logger.log_exc("delete user failed: %s" % user)
                     
 
     def gc_user_tenant_roles(self):
@@ -126,39 +132,43 @@
         # 2. Never remove a user's role at a slice they've created.
         # Keep track of all roles that must be preserved.     
         users = User.objects.all()
-        preserved_roles = {}
-        for user in users:
-            tenant_ids = [s['tenant_id'] for s in user.slices.values()]
-            if user.site:
-                tenant_ids.append(user.site.tenant_id) 
-            preserved_roles[user.kuser_id] = tenant_ids
+        for deployment in deployment_auth:
+            driver = self.driver.admin_driver(deployment=deployment)
+            tenants = driver.shell.keystone.tenants.list() 
+            for user in users:
+                # skip admin roles
+                if user.kuser_id == self.driver.admin_user.id:
+                    continue
+     
+                ignore_tenant_ids = []
+                k_user = driver.shell.keystone.users.find(id=user.kuser_id)
+                ignore_tenant_ids = [s['tenant_id'] for s in user.slices.values()]
+                if user.site:
+                    ignore_tenant_ids.append(user.site.tenant_id) 
 
- 
-        # begin removing user tenant roles from keystone. This is stored in the 
-        # Metadata table.
-        for metadata in self.driver.shell.keystone_db.get_metadata():
-            # skip admin roles
-            if metadata.user_id == self.driver.admin_user.id:
-                continue
-            # skip preserved tenant ids
-            if metadata.user_id in preserved_roles and \
-               metadata.tenant_id in preserved_roles[metadata.user_id]: 
-                continue           
-            # get roles for user at this tenant
-            user_tenant_role_ids = user_tenant_roles.get((metadata.user_id, metadata.tenant_id), [])
+                # get user roles in keystone
+                for tenant in tenants:
+                    # skip preserved tenant ids
+                    if tenant.tenant_id in ignore_tenant_ids: 
+                        continue          
+                    # compare user tenant roles
+                    user_tenant_role_ids = user_tenant_roles.get((user.kuser_id, tenant.id), [])
 
-            if user_tenant_role_ids:
-                # The user has roles at the tenant. Check if roles need to 
-                # be updated.
-                user_keystone_role_ids = metadata.data.get('roles', [])
-                for role_id in user_keystone_role_ids:
-                    if role_id not in user_tenant_role_ids: 
-                        user_keystone_role_ids.pop(user_keystone_role_ids.index(role_id))
-            else:
-                # The user has no roles at this tenant. 
-                metadata.data['roles'] = [] 
-            #session.add(metadata)
-            logger.info("pruning metadata for %s at %s" % (metadata.user_id, metadata.tenant_id))
+                    if user_tenant_role_ids:
+                        # The user has roles at the tenant. Check if roles need to 
+                        # be updated.
+                        k_user_roles =  driver.shell.keystone.roles.roles_for_user(k_user, tenant)
+                        for k_user_role in k_user_roles:
+                            if k_user_role.role_id not in user_tenant_role_ids: 
+                                driver.shell.keyston.remove_user_role(k_user, k_user_role, tenant) 
+                                logger.info("removed user role %s for %s at %s" % \
+                                           (k_user_role, k_user.username, tenant.name))
+                    else:
+                        # remove all roles the user has at the tenant. 
+                        for k_user_role in k_user_roles:
+                            driver.shell.keyston.remove_user_role(k_user, k_user_role, tenant) 
+                            logger.info("removed user role %s for %s at %s" % \
+                                       (k_user_role, k_user.username, tenant.name))
  
     def gc_slivers(self):
         """
@@ -172,20 +182,17 @@
         for sliver in slivers:
             sliver_dict[sliver.instance_id] = sliver
 
-        # delete sliver that don't have a sliver record
-        ctx = self.driver.shell.nova_db.ctx 
-        instances = self.driver.shell.nova_db.instance_get_all(ctx)
-        for instance in instances:
-            if instance.uuid not in sliver_dict:
-                try:
-                    # lookup tenant and update context  
-                    tenant = self.driver.shell.keystone.tenants.find(id=instance.project_id)
-                    driver = self.driver.client_driver(tenant=tenant.name) 
-                    driver.destroy_instance(instance.uuid)
-                    logger.info("destroyed sliver: %s" % (instance))
-                except:
-                    logger.log_exc("destroy sliver failed: %s" % instance) 
-                
+        for tenant in self.driver.shell.keystone.tenants.list():
+            # delete sliver that don't have a sliver record
+            tenant_driver = self.driver.client_driver(tenant=tenant.name, deployment=sliver.node.deployment)
+            for instance in tenant_driver.nova.servers.list():
+                if instance.uuid not in sliver_dict:
+                    try:
+                        tenant_driver.destroy_instance(instance.uuid)
+                        logger.info("destroyed sliver: %s" % (instance))
+                    except:
+                        logger.log_exc("destroy sliver failed: %s" % instance)
+               
 
     def gc_sliver_ips(self):
         """
@@ -195,7 +202,8 @@
         slivers = Sliver.objects.filter(ip=None)
         for sliver in slivers:
             # update connection
-            driver = self.driver.client_driver(tenant=sliver.slice.name)
+            
+            driver = self.driver.client_driver(tenant=sliver.slice.name, deployment=sliver.node.deployment)
             servers = driver.shell.nova.servers.findall(id=sliver.instance_id)
             if not servers:
                 continue
@@ -217,10 +225,12 @@
             nodes_dict[node.name] = node
 
         # collect nova nodes:
-        compute_nodes = self.client.nova.hypervisors.list()
         compute_nodes_dict = {}
-        for compute_node in compute_nodes:
-            compute_nodes_dict[compute_node.hypervisor_hostname] = compute_node
+        for deployment in deployment_auth:
+            driver = self.driver.admin_driver(deployment=deployment) 
+            compute_nodes = driver.nova.hypervisors.list()
+            for compute_node in compute_nodes:
+                compute_nodes_dict[compute_node.hypervisor_hostname] = compute_node
 
         # remove old nodes
         old_node_names = set(nodes_dict.keys()).difference(compute_nodes_dict.keys())
@@ -234,10 +244,12 @@
             images_dict[image.name] = image
 
         # collect glance images
-        glance_images = self.driver.shell.glance.get_images()
         glance_images_dict = {}
-        for glance_image in glance_images:
-            glance_images_dict[glance_image['name']] = glance_image
+        for deployment in deployment_auth:
+            driver = self.driver.admin_driver(deployment=deployment)
+            glance_images = driver.shell.glance.get_images()
+            for glance_image in glance_images:
+                glance_images_dict[glance_image['name']] = glance_image
 
         # remove old images
         old_image_names = set(images_dict.keys()).difference(glance_images_dict.keys())
diff --git a/planetstack/observer/steps/sync_network_slivers.py b/planetstack/observer/steps/sync_network_slivers.py
index 09dc7ed..7e69330 100644
--- a/planetstack/observer/steps/sync_network_slivers.py
+++ b/planetstack/observer/steps/sync_network_slivers.py
@@ -30,7 +30,8 @@
         for sliver in slivers:
             slivers_by_instance_id[sliver.instance_id] = sliver
 
-        ports = self.driver.shell.quantum.list_ports()["ports"]
+        driver = self.driver.admin_driver(caller=sliver.creator, tenant=sliver.slice.name, deployment=sliver.node.deployment.name)
+        ports = driver.shell.quantum.list_ports()["ports"]
         for port in ports:
             if port["id"] in networkSlivers_by_port:
                 # we already have it
diff --git a/planetstack/observer/steps/sync_nodes.py b/planetstack/observer/steps/sync_nodes.py
index a1f0803..bef0ca0 100644
--- a/planetstack/observer/steps/sync_nodes.py
+++ b/planetstack/observer/steps/sync_nodes.py
@@ -14,28 +14,26 @@
     requested_interval=0
 
     def fetch_pending(self):
-        config = Config()
-        deployment = Deployment.objects.filter(name=config.plc_deployment)[0]
-        login_bases = ['princeton', 'stanford', 'gt', 'uw', 'mpisws']
-        sites = Site.objects.filter(login_base__in=login_bases)
-        
         # collect local nodes
+        sites = Site.objects.all()
         nodes = Node.objects.all()
         node_hostnames  = [node.name for node in nodes]
 
-        # collect nova nodes
-        # generate list of new nodes
-        new_nodes = []
-        compute_nodes = self.driver.shell.nova.hypervisors.list()
-        for compute_node in compute_nodes:
+        # fetch all nodes from each deployment 
+        deployments = Deployment.objects.all()
+        for deployment in deployments:
+            driver = self.driver.admin_driver(deployment=deployment.name)
+            compute_nodes = driver.shell.nova.hypervisors.list()
             if compute_node.hypervisor_hostname not in node_hostnames:
-                # pick a random site to add the node to for now
+                # XX TODO:figure out how to correctly identify a node's site.
+                # XX pick a random site to add the node to for now
                 site_index = random.randint(0, len(sites))
-                node = Node(name=compute_node.hypervisor_hostname, 
+                node = Node(name=compute_node.hypervisor_hostname,
                             site=sites[site_index], deployment=deployment)
-                new_nodes.append(node) 
-        
-        return new_nodes
+                new_nodes.append(node)
+
+        return new_nodes    
+                 
 
     def sync_record(self, node):
         node.save()
diff --git a/planetstack/observer/steps/sync_site_deployments.py b/planetstack/observer/steps/sync_site_deployments.py
new file mode 100644
index 0000000..a996c85
--- /dev/null
+++ b/planetstack/observer/steps/sync_site_deployments.py
@@ -0,0 +1,28 @@
+import os
+import base64
+from django.db.models import F, Q
+from planetstack.config import Config
+from observer.openstacksyncstep import OpenStackSyncStep
+from core.models.site import *
+
+class SyncSiteDeployments(OpenStackSyncStep):
+    requested_interval=0
+    provides=[Site, SiteDeployments]
+
+    def fetch_pending(self):
+        return SiteDeployments.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
+
+    def sync_record(self, site_deployment):
+        if not site_deployment.tenant_id:
+            driver = self.driver.admin_driver(deployment=site_deployment.deployment.name)
+            tenant = driver.create_tenant(tenant_name=site_deployment.site.login_base,
+                                               description=site_deployment.site.name,
+                                               enabled=site_deployment.site.enabled)
+            site_deployment.tenant_id = tenant.id
+            site_deployment.save()
+        elif site_deployment.site.id and site_deployment.tenant_id:
+            driver = self.driver.admin_driver(deployment=site_deployment.name)
+            driver.update_tenant(site_deployment.tenant_id,
+                                 description=site_deployment.site.name,
+                                 enabled=site_deployment.site.enabled)
+            
diff --git a/planetstack/observer/steps/sync_site_privileges.py b/planetstack/observer/steps/sync_site_privileges.py
index 8287d44..922f579 100644
--- a/planetstack/observer/steps/sync_site_privileges.py
+++ b/planetstack/observer/steps/sync_site_privileges.py
@@ -4,6 +4,7 @@
 from planetstack.config import Config
 from observer.openstacksyncstep import OpenStackSyncStep
 from core.models.site import *
+from core.models.user import UserDeployments    
 
 class SyncSitePrivileges(OpenStackSyncStep):
     requested_interval=0
@@ -17,3 +18,14 @@
             self.driver.add_user_role(site_priv.user.kuser_id,
                                       site_priv.site.tenant_id,
                                       site_priv.role.role) 
+
+        # sync site privileges at all site deployments
+        site_deployments = SiteDeployments.objects.filter(site=site_priv.site)
+        for site_deployment in site_deployments:
+            user_deployments = UserDeployments.objects.filter(deployment=site_deployment.deployment)
+            if user_deployments:
+                kuser_id  = user_deployments[0].kuser_id
+                driver = self.driver.admin_driver(deployment=site_deployment.name)
+                driver.add_user_role(kuser_id,
+                                     site_deployment.tenant_id,
+                                     slice_memb.role.role)
diff --git a/planetstack/observer/steps/sync_sites.py b/planetstack/observer/steps/sync_sites.py
index 2013c6d..e128e9a 100644
--- a/planetstack/observer/steps/sync_sites.py
+++ b/planetstack/observer/steps/sync_sites.py
@@ -13,22 +13,5 @@
         return Site.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
 
     def sync_record(self, site):
-        save_site = False
-        if not site.tenant_id:
-            tenant = self.driver.create_tenant(tenant_name=site.login_base,
-                                               description=site.name,
-                                               enabled=site.enabled)
-            site.tenant_id = tenant.id
-            save_site = True
-            # XXX - What's caller?
-            # self.driver.add_user_role(self.caller.kuser_id, tenant.id, 'admin')
-
-        # update the record
-        if site.id and site.tenant_id:
-            self.driver.update_tenant(site.tenant_id,
-                                      description=site.name,
-                                      enabled=site.enabled)
-
-        if (save_site):
-            site.save() # 
+        site.save()
 
diff --git a/planetstack/observer/steps/sync_slice_deployments.py b/planetstack/observer/steps/sync_slice_deployments.py
new file mode 100644
index 0000000..8c0374d
--- /dev/null
+++ b/planetstack/observer/steps/sync_slice_deployments.py
@@ -0,0 +1,111 @@
+import os
+import base64
+from collections import defaultdict
+from netaddr import IPAddress, IPNetwork
+from django.db.models import F, Q
+from planetstack.config import Config
+from observer.openstacksyncstep import OpenStackSyncStep
+from core.models.site import SiteDeployments
+from core.models.slice import Slice, SliceDeployments
+from core.models.user import UserDeployments
+from util.logger import Logger, logging
+
+logger = Logger(level=logging.INFO)
+
+class SyncSliceDeployments(OpenStackSyncStep):
+    provides=[Slice, SliceDeployments]
+    requested_interval=0
+
+    def fetch_pending(self):
+        # slice deployments are not visible to users. We must ensure
+        # slices are deployed at all deploymets available to their site.
+        site_deployments = SiteDeployment.objects.all()
+        site_deploy_lookup = defaultdict(list)
+        for site_deployment in site_deployments:
+            site_deploy_lookup[site_deployment.site].append(site_deployment.deployment)
+        
+        slice_deployments = SliceDeployment.objects.all()
+        slice_deploy_lookup = defaultdict(list)
+        for slice_deployment in slice_deployments:
+            slice_deploy_lookup[slice_deployment.slice].append(slice_deployment.deployment)
+        
+        for slice in Slice.objects.all():
+            expected_deployments = site_deploy_lookup[slice.site]
+            for expected_deployment in expected_deployments:
+                if slice not in slice_deploy_lookup or \
+                   expected_deployment not in slice_deploy_lookup[slice]:
+                    sd = SliceDeployments(slice=slice, deployment=expected_deployment)
+                    sd.save()
+
+        # now we can return all slice deployments that need to be enacted   
+        return SliceDeployments.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
+
+    def get_next_subnet(self, deployment=None):
+        # limit ourself to 10.0.x.x for now
+        valid_subnet = lambda net: net.startswith('10.0')
+        driver = self.driver.admin_driver(deployment=deployment)
+        subnets = driver.shell.quantum.list_subnets()['subnets']
+        ints = [int(IPNetwork(subnet['cidr']).ip) for subnet in subnets \
+                if valid_subnet(subnet['cidr'])]
+        ints.sort()
+        last_ip = IPAddress(ints[-1])
+        last_network = IPNetwork(str(last_ip) + "/24")
+        next_network = IPNetwork(str(IPAddress(last_network) + last_network.size) + "/24")
+        return next_network
+
+    def sync_record(self, slice_deployment):
+        logger.info("sync'ing slice deployment %s" % slice_deployment)
+        if not slice_deployment.tenant_id:
+            nova_fields = {'tenant_name': slice_deployment.slice.name,
+                   'description': slice_deployment.slice.description,
+                   'enabled': slice_deployment.slice.enabled}
+            driver = self.driver.admin_driver(deployment=slice_deployment.deployment.name)
+            tenant = driver.create_tenant(**nova_fields)
+            slice_deployment.tenant_id = tenant.id
+
+            # XXX give caller an admin role at the tenant they've created
+            deployment_users = UserDeployments.objects.filter(user=slice_deployment.slice.creator,
+                                                             deployment=slice_deployment.deployment)            
+            if not deployment_users or not deployment_users[0].kuser_id:
+                logger.info("slice createor %s has not accout at deployment %s" % (slice_deployment.slice.creator, slice_deployment.deployment.name)
+            else:
+                driver.add_user_role(slice_deployment.slice.creator.kuser_id, tenant.id, 'admin')
+
+                # refresh credentials using this tenant
+                client_driver = self.driver.client_driver(tenant=tenant.name, 
+                                                          deployment=slice_deployment.deployment.name)
+
+                # create network
+                network = client_driver.create_network(slice.name)
+                slice_deployment.network_id = network['id']
+
+                # create router
+                router = client_driver.create_router(slice.name)
+                slice_deployment.router_id = router['id']
+
+                # create subnet for slice's private network
+                next_subnet = self.get_next_subnet(deployment=slice_deployment.deployment.name)
+                cidr = str(next_subnet.cidr)
+                ip_version = next_subnet.version
+                start = str(next_subnet[2])
+                end = str(next_subnet[-2]) 
+                subnet = client_driver.create_subnet(name=slice.name,
+                                                   network_id = network['id'],
+                                                   cidr_ip = cidr,
+                                                   ip_version = ip_version,
+                                                   start = start,
+                                                   end = end)
+                slice_deployment.subnet_id = subnet['id']
+                # add subnet as interface to slice's router
+                client_driver.add_router_interface(router['id'], subnet['id'])
+                # add external route
+                client_driver.add_external_route(subnet)
+
+
+        if slice_deployment.id and slice_deployment.tenant_id:
+            driver = self.driver.admin_driver(deployment=slice_deployment.deployment.name)
+            driver.update_tenant(slice_deployment.tenant_id,
+                                 description=slice_deployment.slice.description,
+                                 enabled=slice_deployment.slice.enabled)   
+
+        slice_deployment.save()
diff --git a/planetstack/observer/steps/sync_slice_memberships.py b/planetstack/observer/steps/sync_slice_memberships.py
index ffc6eb8..6def794 100644
--- a/planetstack/observer/steps/sync_slice_memberships.py
+++ b/planetstack/observer/steps/sync_slice_memberships.py
@@ -4,6 +4,7 @@
 from planetstack.config import Config
 from observer.openstacksyncstep import OpenStackSyncStep
 from core.models.slice import *
+from core.models.user import UserDeployments
 
 class SyncSliceMemberships(OpenStackSyncStep):
     requested_interval=0
@@ -17,3 +18,14 @@
                 self.driver.add_user_role(slice_memb.user.kuser_id,
                                           slice_memb.slice.tenant_id,
                                           slice_memb.role.role)
+
+        # sync slice memberships at all slice deployments 
+        slice_deployments = SliceDeployments.objects.filter(slice=slice_memb.slice)
+        for slice_deployment in slice_deployments:
+            user_deployments = UserDeployments.objects.filter(deployment=slice_deployment.deployment)
+            if user_deployments:
+                kuser_id  = user_deployments[0].kuser_id
+                driver = self.driver.admin_driver(deployment=slice_deployment.name)
+                driver.add_user_role(kuser_id,
+                                     slice_deployment.tenant_id,
+                                     slice_memb.role.role)
diff --git a/planetstack/observer/steps/sync_slices.py b/planetstack/observer/steps/sync_slices.py
index f91c0fc..cc1220c 100644
--- a/planetstack/observer/steps/sync_slices.py
+++ b/planetstack/observer/steps/sync_slices.py
@@ -16,63 +16,5 @@
     def fetch_pending(self):
         return Slice.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
 
-    def get_next_subnet(self):
-        # limit ourself to 10.0.x.x for now
-        valid_subnet = lambda net: net.startswith('10.0')
-        subnets = self.driver.shell.quantum.list_subnets()['subnets']
-        ints = [int(IPNetwork(subnet['cidr']).ip) for subnet in subnets \
-                if valid_subnet(subnet['cidr'])]
-        ints.sort()
-        last_ip = IPAddress(ints[-1])
-        last_network = IPNetwork(str(last_ip) + "/24")
-        next_network = IPNetwork(str(IPAddress(last_network) + last_network.size) + "/24")
-        return next_network
-
     def sync_record(self, slice):
-        logger.info("sync'ing slice %s" % slice.name)
-        if not slice.tenant_id:
-            nova_fields = {'tenant_name': slice.name,
-                   'description': slice.description,
-                   'enabled': slice.enabled}
-            tenant = self.driver.create_tenant(**nova_fields)
-            slice.tenant_id = tenant.id
-
-            # XXX give caller an admin role at the tenant they've created
-            self.driver.add_user_role(slice.creator.kuser_id, tenant.id, 'admin')
-
-            # refresh credentials using this tenant
-            client_driver = self.driver.client_driver(tenant=tenant.name)
-
-            # create network
-            network = client_driver.create_network(slice.name)
-            slice.network_id = network['id']
-
-            # create router
-            router = client_driver.create_router(slice.name)
-            slice.router_id = router['id']
-
-            # create subnet for slice's private network
-            next_subnet = self.get_next_subnet()
-            cidr = str(next_subnet.cidr)
-            ip_version = next_subnet.version
-            start = str(next_subnet[2])
-            end = str(next_subnet[-2]) 
-            subnet = client_driver.create_subnet(name=slice.name,
-                                               network_id = network['id'],
-                                               cidr_ip = cidr,
-                                               ip_version = ip_version,
-                                               start = start,
-                                               end = end)
-            slice.subnet_id = subnet['id']
-            # add subnet as interface to slice's router
-            client_driver.add_router_interface(router['id'], subnet['id'])
-            # add external route
-            client_driver.add_external_route(subnet)
-
-
-        if slice.id and slice.tenant_id:
-            self.driver.update_tenant(slice.tenant_id,
-                                      description=slice.description,
-                                      enabled=slice.enabled)   
-
         slice.save()
diff --git a/planetstack/observer/steps/sync_sliver_ips.py b/planetstack/observer/steps/sync_sliver_ips.py
index 2d7f1f8..83e33eb 100644
--- a/planetstack/observer/steps/sync_sliver_ips.py
+++ b/planetstack/observer/steps/sync_sliver_ips.py
@@ -14,7 +14,8 @@
         return slivers
 
     def sync_record(self, sliver):
-        driver = self.driver.client_driver(tenant=sliver.slice.name)  
+        driver = self.driver.client_driver(tenant=sliver.slice.name, 
+                                           deployment=sliver.node.deployment.name)  
         servers = driver.shell.nova.servers.findall(id=sliver.instance_id)
         if not servers:
             return
diff --git a/planetstack/observer/steps/sync_slivers.py b/planetstack/observer/steps/sync_slivers.py
index a3f423c..03383d9 100644
--- a/planetstack/observer/steps/sync_slivers.py
+++ b/planetstack/observer/steps/sync_slivers.py
@@ -40,7 +40,7 @@
             slice_memberships = SlicePrivilege.objects.filter(slice=sliver.slice)
             pubkeys = [sm.user.public_key for sm in slice_memberships if sm.user.public_key]
             pubkeys.append(sliver.creator.public_key)
-            driver = self.driver.client_driver(caller=sliver.creator, tenant=sliver.slice.name)
+            driver = self.driver.client_driver(caller=sliver.creator, tenant=sliver.slice.name, deployment=sliver.node.deployment.name)
             instance = driver.spawn_instance(name=sliver.name,
                                 key_name = sliver.creator.keyname,
                                 image_id = sliver.image.image_id,
diff --git a/planetstack/observer/steps/sync_user_deployments.py b/planetstack/observer/steps/sync_user_deployments.py
new file mode 100644
index 0000000..ad1363d
--- /dev/null
+++ b/planetstack/observer/steps/sync_user_deployments.py
@@ -0,0 +1,84 @@
+import os
+import base64
+import hashlib
+from collections import defaultdict
+from django.db.models import F, Q
+from planetstack.config import Config
+from observer.openstacksyncstep import OpenStackSyncStep
+from core.models.site import SiteDeployments, Deployment
+from core.models.user import User, UserDeployments
+from util.logger import Logger, logging
+
+logger = Logger(level=logging.INFO)
+
+class SyncUserDeployments(OpenStackSyncStep):
+    provides=[User, UserDeployments]
+    requested_interval=0
+
+    def fetch_pending(self):
+        # user deployments are not visible to users. We must ensure
+        # user are deployed at all deploymets available to their sites.
+
+        deployments = Deployment.objects.all()
+        site_deployments = SiteDeployments.objects.all()
+        site_deploy_lookup = defaultdict(list)
+        for site_deployment in site_deployments:
+            site_deploy_lookup[site_deployment.site].append(site_deployment.deployment)
+        
+        user_deployments = UserDeployments.objects.all()
+        user_deploy_lookup = defaultdict(list)
+        for user_deployment in user_deployments:
+            user_deploy_lookup[user_deployment.user].append(user_deployment.deployment)
+        
+        for user in User.objects.all():
+            if user.is_admin:
+                # admins should have an account at all deployments
+                expected_deployments = deployments
+            else:
+                # normal users should have an account at their site's deployments
+                expected_deployments = site_deploy_lookup[user.site]
+            for expected_deployment in expected_deployments:
+                if expected_deployment not in user_deploy_lookup[user]:
+                    ud = UserDeployments(user=user, deployment=expected_deployment)
+                    ud.save()
+
+        # now we can return all slice deployments that need to be enacted   
+        return UserDeployments.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
+
+    def sync_record(self, user_deployment):
+        logger.info("sync'ing user %s at deployment %s" % (user_deployment.user, user_deployment.deployment.name))
+        name = user_deployment.user.email[:user_deployment.user.email.find('@')]
+        user_fields = {'name': user_deployment.user.email,
+                       'email': user_deployment.user.email,
+                       'password': hashlib.md5(user_deployment.user.password).hexdigest()[:6],
+                       'enabled': True}    
+        driver = self.driver.admin_driver(deployment=user_deployment.deployment.name)
+        if not user_deployment.kuser_id:
+            keystone_user = driver.create_user(**user_fields)
+            user_deployment.kuser_id = keystone_user.id
+        else:
+            driver.update_user(user_deployment.kuser_id, user_fields)
+
+        # setup user deployment site roles  
+        if user_deployment.user.site:
+            site_deployments = SiteDeployments.objects.filter(site=user_deployment.user.site,
+                                                              deployment=user_deployment.deployment)
+            if site_deployments:
+                # need the correct tenant id for site at the deployment
+                tenant_id = site_deployments[0].tenant_id  
+                driver.add_user_role(user_deployment.kuser_id, 
+                                     tenant_id, 'user')
+                if user_deployment.user.is_admin:
+                    driver.add_user_role(user_deployment.kuser_id, tenant_id, 'admin')
+                else:
+                    # may have admin role so attempt to remove it
+                    driver.delete_user_role(user_deployment.kuser_id, tenant_id, 'admin')
+
+        if user_deployment.user.public_key:
+            user_driver = driver.client_driver(caller=user, tenant=user.site.login_base, 
+                                                    deployment=user_deployment.deployment.name)
+            key_fields =  {'name': user_deployment.user.keyname,
+                           'public_key': user_deployment.user.public_key}
+            user_driver.create_keypair(**key_fields)
+
+        user_deployment.save()
diff --git a/planetstack/observer/steps/sync_users.py b/planetstack/observer/steps/sync_users.py
index 25f093e..4bd2826 100644
--- a/planetstack/observer/steps/sync_users.py
+++ b/planetstack/observer/steps/sync_users.py
@@ -14,29 +14,4 @@
         return User.objects.filter(Q(enacted__lt=F('updated')) | Q(enacted=None))
 
     def sync_record(self, user):
-        name = user.email[:user.email.find('@')]
-        user_fields = {'name': name,
-                       'email': user.email,
-                       'password': hashlib.md5(user.password).hexdigest()[:6],
-                       'enabled': True}
-        if not user.kuser_id:
-            keystone_user = self.driver.create_user(**user_fields)
-            user.kuser_id = keystone_user.id
-        else:
-            self.driver.update_user(user.kuser_id, user_fields)        
-
-        if user.site:
-            self.driver.add_user_role(user.kuser_id, user.site.tenant_id, 'user')
-            if user.is_admin:
-                self.driver.add_user_role(user.kuser_id, user.site.tenant_id, 'admin')
-            else:
-                # may have admin role so attempt to remove it
-                self.driver.delete_user_role(user.kuser_id, user.site.tenant_id, 'admin')
-
-        if user.public_key:
-            driver = self.driver.client_driver(caller=user, tenant=user.site.login_base) 
-            key_fields =  {'name': user.keyname,
-                           'public_key': user.public_key}
-            driver.create_keypair(**key_fields)
-
         user.save()
diff --git a/planetstack/observer/toposort.py b/planetstack/observer/toposort.py
old mode 100755
new mode 100644
index 959cea3..a2c9389
--- a/planetstack/observer/toposort.py
+++ b/planetstack/observer/toposort.py
@@ -5,58 +5,69 @@
 import commands
 import threading
 import json
+import pdb
 
 from datetime import datetime
 from collections import defaultdict
 
+# Topological sort
+# Notes:
+# - Uses a stack instead of recursion
+# - Forfeits optimization involving tracking currently visited nodes
 def toposort(g, steps=None):
+	# Get set of all nodes, including those without outgoing edges
+	keys = set(g.keys())
+	values = set({})
+	for v in g.values():
+		values=values | set(v)
+	
+	all_nodes=list(keys|values)
 	if (not steps):
-		keys = set(g.keys())
-		values = set({})
-		for v in g.values():
-			values=values | set(v)
-		
-		steps=list(keys|values)
+		steps = all_nodes
 
-	reverse = {}
-
-	for k,v in g.items():
-		for rk in v:
-			try:
-				reverse[rk].append(k)
-			except:
-				reverse[rk]=k
-
-	sources = []
-	for k,v in g.items():
-		if not reverse.has_key(k):
-			sources.append(k)
-
-	for k,v in reverse.iteritems():
-		if (not v):
-			sources.append(k)
-
+	# Final order
 	order = []
-	marked = []
 
-	while sources:
-		n = sources.pop(0)
-		try:
-			for m in g[n]:
-				if m not in marked:
-					sources.append(m)
-					marked.append(m)
-		except KeyError:
-			pass
-		if (n in steps):
-			order.append(n)
+	# DFS stack, not using recursion
+	stack = []
 
-	order.reverse()
+	# Unmarked set
+	unmarked = all_nodes
 
-	return order
+	# visiting = [] - skip, don't expect 1000s of nodes, |E|/|V| is small
 
-graph_file=open('model-deps').read()
-g = json.loads(graph_file)
-print toposort(g)
+	while unmarked:
+		stack.insert(0,unmarked[0]) # push first unmarked
+
+		while (stack):
+			n = stack[0]
+			add = True
+			try:
+				for m in g[n]:
+					if (m in unmarked):
+						if (m not in stack):
+							add = False
+							stack.insert(0,m)
+						else:
+							# Should not happen, if so there's a loop
+							print 'Loop at %s'%m
+			except KeyError:
+				pass
+			if (add):
+				if (n in steps):
+					order.append(n)
+				item = stack.pop(0)
+				unmarked.remove(item)
+
+	noorder = list(set(steps) - set(order))
+	return order + noorder
+
+def main():
+	graph_file=open('planetstack.deps').read()
+	g = json.loads(graph_file)
+	print toposort(g)
+
+if (__name__=='__main__'):
+	main()
 
 #print toposort({'a':'b','b':'c','c':'d','d':'c'},['d','c','b','a'])
diff --git a/planetstack/openstack/client.py b/planetstack/openstack/client.py
index 1a6386d..c6b6b16 100644
--- a/planetstack/openstack/client.py
+++ b/planetstack/openstack/client.py
@@ -13,6 +13,7 @@
     has_openstack = False
 
 from planetstack.config import Config
+from deployment_auth import deployment_auth
 
 def require_enabled(callable):
     def wrapper(*args, **kwds):
@@ -39,16 +40,22 @@
     return opts
 
 class Client:
-    def __init__(self, username=None, password=None, tenant=None, url=None, config=None, *args, **kwds):
-        if config:
-            config = Config(config)
+    def __init__(self, username=None, password=None, tenant=None, url=None, token=None, endpoint=None, deployment=None, *args, **kwds):
+        
+            
+        if not deployment or deployment not in deployment_auth:
+            auth = deployment_auth['default']
         else:
-            config = Config()
+            auth = deployment_auth[deployment]
+            
+            
         self.has_openstack = has_openstack
-        self.username = config.nova_admin_user
-        self.password = config.nova_admin_password
-        self.tenant = config.nova_admin_tenant
-        self.url = config.nova_url
+        self.username = auth['user']
+        self.password = auth['password']
+        self.tenant = auth['tenant']
+        self.url = auth['url']
+        self.endpoint = auth['endpoint']
+        self.token = auth['token']  
 
         if username:
             self.username = username
@@ -58,6 +65,10 @@
             self.tenant = tenant
         if url:
             self.url = url
+        if token:
+            self.token = token    
+        if endpoint:
+            self.endpoint = endpoint
 
         if '@' in self.username:
             self.username = self.username[:self.username.index('@')]
@@ -80,7 +91,10 @@
             self.client = keystone_client.Client(username=self.username,
                                                  password=self.password,
                                                  tenant_name=self.tenant,
-                                                 auth_url=self.url)
+                                                 auth_url=self.url,
+                                                 endpoint=self.endpoint,
+                                                 token=self.token
+                                                )
 
     @require_enabled
     def connect(self, *args, **kwds):
diff --git a/planetstack/openstack/driver.py b/planetstack/openstack/driver.py
index 8224c17..174cf85 100644
--- a/planetstack/openstack/driver.py
+++ b/planetstack/openstack/driver.py
@@ -12,37 +12,39 @@
 
 class OpenStackDriver:
 
-    def __init__(self, config = None, client=None): 
+    def __init__(self, config = None, client=None, deployment=None):
         if config:
             self.config = Config(config)
         else:
-            self.config = Config() 
+            self.config = Config()
 
-        self.admin_client = OpenStackClient()
+        self.admin_client = OpenStackClient(deployment=deployment)
         self.admin_user = self.admin_client.keystone.users.find(name=self.admin_client.keystone.username)
 
         if client:
             self.shell = client
         else:
-            self.shell = OpenStackClient()
+            self.shell = OpenStackClient(deployment=deployment)
 
         self.enabled = manager_enabled
         self.has_openstack = has_openstack
 
-    def client_driver(self, caller=None, tenant=None):
+    def client_driver(self, caller=None, tenant=None, deployment=None):
         if caller:
             auth = {'username': caller.email,
                     'password': hashlib.md5(caller.password).hexdigest()[:6],
                     'tenant': tenant}
-            client = OpenStackClient(**auth)
+            client = OpenStackClient(deployment=deployment, **auth)
         else:
-            client = OpenStackClient(tenant=tenant)
-        driver = OpenStackDriver(client=client)
+            client = OpenStackClient(tenant=tenant, deployment=deployment)
+
+        driver = OpenStackDriver(client=client, deployment=deployment)
         return driver
 
-    def admin_driver(self, tenant=None):
-        client = OpenStackClient(tenant=tenant)
-        driver = OpenStackDriver(client=client) 
+    def admin_driver(self, tenant=None, deployment=None):
+        client = OpenStackClient(tenant=tenant, deployment=deployment)
+        driver = OpenStackDriver(client=client, deployment=deployment)
+        return driver    
 
     def create_role(self, name):
         roles = self.shell.keystone.roles.findall(name=name)
diff --git a/planetstack/scripts/opencloud b/planetstack/scripts/opencloud
new file mode 100755
index 0000000..3005865
--- /dev/null
+++ b/planetstack/scripts/opencloud
@@ -0,0 +1,62 @@
+#!/bin/sh
+
+if [ -z "$1" ]; then
+    echo usage: $0 "[initdb | resetdb ]"
+    exit
+fi
+
+cd /opt/planetstack
+
+function initdb {
+    #Figure out if the script is running on Fedora 16 or 17
+    if grep 16 /etc/fedora-release;  then
+        sudo -u postgres initdb -D /var/lib/pgsql/data/
+        sudo -u postgres pg_ctl -D /var/lib/pgsql/data -l logfile start
+    else
+        #Try normal Fedora 17 commands
+        echo "Trying Fedora 17 commands" > /dev/stdout
+        /sbin/service postgresql initdb
+        /sbin/service postgresql start
+        /sbin/chkconfig postgresql on
+    fi
+}
+function createdb {
+    echo "Creating OpenCloud database..."
+    sudo -u postgres createdb planetstack 
+}
+function dropdb {
+    echo "Dropping OpenCloud database..."
+    sudo -u postgres dropdb planetstack
+}
+function syncdb {
+    echo "Syncing OpenCloud services..."
+    python /opt/planetstack/manage.py syncdb --noinput
+}
+function runserver {
+#    python manage.py runserver 128.95.1.128:8000
+    echo "Starting OpenCloud Service on $HOSTNAME:8000"
+    python manage.py runserver  $HOSTNAME:8000&
+}
+
+COMMAND=$1
+
+if [ "$COMMAND" = "initdb" ]; then
+    initdb
+    createdb
+    syncdb
+    runserver
+fi
+if [ "$COMMAND" = "resetdb" ]; then
+    dropdb
+    createdb
+    syncdb
+    runserver
+fi
+if [ "$COMMAND" = "syncdb" ]; then
+    syncdb
+    runserver
+fi
+if [ "$COMMAND" = "runserver" ]; then
+    runserver
+fi
+
diff --git a/planetstack/templates/admin/base.html b/planetstack/templates/admin/base.html
index b9ea01c..6842040 100644
--- a/planetstack/templates/admin/base.html
+++ b/planetstack/templates/admin/base.html
@@ -18,7 +18,6 @@
   {% block blockbots %}
     <meta name="robots" content="NONE,NOARCHIVE"/>{% endblock %}
   <link rel="shortcut icon" href="{% static 'favicon.png' %}">
-
 </head>
 {% load i18n %}
 
@@ -133,12 +132,20 @@
                     </li>
                 </ul>
               {% endblock %}
-               <label class="nodetextbox" >Active Nodes: </label>
-              <label class="nodelabel" >37</label>
-              <label class="nodetextbox">CPU Utilization: </label>
-              <label class="nodelabel" >12%</label>
-            <label class="nodetextbox">Bytes Transferred:</label>     
-              <label class="nodelabel" style="width:60px;">4321GB</label>
+		<div class="hide">{{ app_label|capfirst|escape }}</div>
+		<div class="hide selectedMainNav">{{ opts.verbose_name_plural|capfirst }}</div>
+		<div class="hide currentOriginalNode">{{ original|truncatewords:"18" }}</div>  
+                  
+
+               <label class="nodetextbox nodesLabel" style="display: none;" > </label>
+              <label class="nodelabel nodesValue" style="display: none;" ></label>
+		<span class="nodesCnt hide"></span>
+              <label class="nodetextbox cpuLabel" style="display: none;" ></label>
+              <label class="nodelabel cpuValue" style="display: none;" ></label>
+		<span class="cpuCnt hide"></span>
+            <label class="nodetextbox bandwidthLabel" style="display: none;" ></label>    
+              <label class="nodelabel bandwidthValue" style="width:60px;display: none;"></label>
+		<span class="bandUsage hide"></span>
             {% endif %}
 
             {% block messages %}
@@ -230,7 +237,52 @@
 
   <script src="{% static 'suit/bootstrap/js/bootstrap.min.js' %}"></script>
   <script src="{% static 'suit/js/suit.js' %}"></script>
+  <script src="{% static 'main.js' %}"></script>
   {% block extrajs %}{% endblock %}
+<script src="http://d3js.org/d3.v3.js"></script>
 
+	<div class="modal fade hide" id="chartsModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
+	  <div class="modal-dialog">
+	    <div class="modal-content">
+	      <!--<div class="modal-header">
+		<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
+		<h4 class="modal-title" id="myModalLabel">OpenCloud</h4>
+	      </div>-->
+	      <div class="modal-body">
+		<div class="chartContainer">
+			<div class="row">
+				<div class=" padding">
+				</div>
+			</div>
+
+			<div class="row">
+				<div class=" heading">
+					<p id="chartHeading" class="heading">OpenCloud</p>	
+				</div>
+			</div>
+			<div class="row">
+				<div class="padding"></div>
+				<div class="padding"></div>
+			</div>
+			<div class="row">
+				<div id="graph" class="graph">
+				</div>
+			</div>
+		</div>
+	      </div>
+	      <!--<div class="modal-footer">
+		<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+	      </div>-->
+	    </div><!-- /.modal-content -->
+	  </div><!-- /.modal-dialog -->
+	</div><!-- /.modal -->
+
+
+<script>
+
+
+
+
+</script>
 </body>
 </html>
diff --git a/planetstack/templates/admin/dashboard/welcome.html b/planetstack/templates/admin/dashboard/welcome.html
index 707ee96..8df5f10 100644
--- a/planetstack/templates/admin/dashboard/welcome.html
+++ b/planetstack/templates/admin/dashboard/welcome.html
@@ -22,4 +22,160 @@
 {% endif %}
 {% endfor %}
 </table>
+<script type="text/javascript" src="{% static 'log4javascript-1.4.6/log4javascript.js' %}"></script>
+<div id="HPCDashboard">
+    <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>
+</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 );
+
+    data[key]['marker'] = L.marker([data[key]['lat'], data[key]['long']], {icon: getIcon(data[key]['numNodes'], data[key]['numHPCSlivers']) });
+    data[key]['marker'].addTo(map).bindPopup(setPopupVals(key, data[key]));
+
+}
+var bounds = new L.LatLngBounds(arrayOfLatLngs);
+map.fitBounds(bounds);
+
+var popup = L.popup();
+
+
+function setPopupVals (site, siteData) {
+    var retVal = '<span class="SiteDetail"><b>' + site + '</b></span>' + 
+                   '</br><a href="' + siteData['siteUrl'] + '">' + siteData['siteUrl'] + '</a>' + 
+                   '</br><b>Available Nodes: </b>' + siteData['numNodes'] + 
+                   '</br><b>Active HPC Slivers: </b>' + siteData['numHPCSlivers'] + 
+                   '</br><span id="addSlivers">Add HPC Slivers</span>' + 
+                   '<span id="remSlivers">Remove HPC Slivers</span>' ; 
+
+   return retVal;
+}
+function getIcon(numNodes, numHPCSlivers, currentBW) {
+    var colorChoices = ["#007FFF", "#0000FF", "#7f00ff", "#FF00FF", "#FF007F", "#FF0000"];
+
+    var ratio = (numHPCSlivers/numNodes) * 100;
+    var numColors = colorChoices.length;
+    var colorBands = 100/numColors;
+
+    //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 = 5;
+    for (colorBand = 0; colorBand < numColors; colorBand ++) {
+        if (ratio < colorBands * colorBand+1) {
+            iconColor = colorBand
+            break;
+        }
+    }
+  
+    var icon = L.MakiMarkers.icon({icon: "star-stroked", color: colorChoices[iconColor] , size: "s"});
+    return icon;
+}
+
+function updateMaps() {
+    log.info("Attempting to update Maps");
+    $.ajax({
+    url : '/hpcdashboard',
+    dataType : 'json',
+    type : 'GET',
+    success: function(newData)
+    {
+        log.info("Successfully got data back...");
+        log.info(newData);
+        log.info("Still have old data too");
+        log.info(data);
+        updateMapData(newData);
+    }
+});
+    setTimeout(updateMaps, 45000)
+
+}
+
+function updateMapData(newData) {
+    for ( site in newData ) {
+        var isNewSite = false;
+        //check to see if the site is new or not
+        if (site in data) {
+            log.info("Site " + site + " already mapped");
+            //take ownership of marker
+            newData[site]['marker'] = data[site]['marker'];
+            delete data[site];
+            newData[site]['marker'].setIcon(getIcon(newData[site]['numNodes'], newData[site]['numHPCSlivers']));
+            // workaround, markers currently don't have a setPopup Content method -- so have to grab object directly
+            newData[site]['marker']._popup.setContent(setPopupVals(site, newData[site]));
+        }
+        else {
+            isNewSite = true;
+            log.info("New Site detected: " + site);
+            newData[site]['marker'] = L.marker([newData[site]['lat'], newData[site]['long']], 
+                                              {icon: getIcon(newData[site]['numNodes'], newData[site]['numHPCSlivers']) });
+            newData[site]['marker'].addTo(map).bindPopup(setPopupVals(site, newData[site])); //.openPopup();
+            log.info("Should have added the new site");
+
+        }
+    }
+
+    // Anything still in data needs to be removed since it is no longer a valid site
+    for (remSite in data) {
+        log.warn("Site: " + remSite + " is no longer valid, removing from map");
+        map.removeLayer(data[remSite]['marker']);
+    }
+    data = newData;
+}
+
+function onMapClick(e) {
+    popup
+    .setLatLng(e.latlng)
+    .setContent("You clicked the map at " + e.latlng.toString())
+    .openOn(map);
+}
+
+setTimeout(updateMaps, 5000)
+
+</script>
 {% endblock %}
diff --git a/setup.py b/setup.py
index a250b29..267f282 100644
--- a/setup.py
+++ b/setup.py
@@ -19,7 +19,7 @@
       description='PlanetStack',
       scripts=['planetstack/planetstack-backend.py'],
       data_files=[
-        ('/etc/planetstack/', ['planetstack/plstackapi_config']),
+        ('/etc/planetstack/', ['planetstack/plstackapi_config', 'planetstack/deployment_auth.py']),
         ('/lib/systemd/system/', ['planetstack/redhat/planetstack-backend.service']),
         ])