changeset 2:472a16863ecc

expanded nightly.jar
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Tue, 02 Dec 2008 20:38:20 +0900
parents 93e46514f20d
children bbeace809d92
files chrome/content/.buildrc chrome/content/brand/icon.png chrome/content/brand/logo.png chrome/content/browser.js chrome/content/browserOverlay.xul chrome/content/calendar.js chrome/content/calendarOverlay.xul chrome/content/configwarning.js chrome/content/configwarning.xul chrome/content/crashreports/crashreports.js chrome/content/crashreports/sidebar.js chrome/content/crashreports/sidebar.xul chrome/content/extensions/addons.xul chrome/content/extensions/extensions.js chrome/content/extensions/incompatible.css chrome/content/extensions/incompatible.js chrome/content/extensions/incompatible.xml chrome/content/extensions/incompatible.xul chrome/content/includes/tree-utils.js chrome/content/leaks/leaks.html chrome/content/leaks/leaks.js chrome/content/leaks/leaks.xul chrome/content/messenger.js chrome/content/messengerOverlay.xul chrome/content/nightly.js chrome/content/options/options.xul chrome/content/options/prefs.js chrome/content/options/subpane.xml chrome/content/options/title.js chrome/content/platform.js chrome/content/screenshot/providers.js chrome/content/screenshot/screenshot.js chrome/content/screenshot/screenshot.xul chrome/content/session/dialog.js chrome/content/session/session.js chrome/content/session/session.xul chrome/content/songbird.js chrome/content/songbirdOverlay.xul chrome/content/suite.js chrome/content/suiteOverlay.xul chrome/content/winPlatform.js chrome/locale/en-US/configwarning.dtd chrome/locale/en-US/incompatible.dtd chrome/locale/en-US/leaks.dtd chrome/locale/en-US/leaks.properties chrome/locale/en-US/nightly.dtd chrome/locale/en-US/nightly.properties chrome/locale/en-US/options.dtd chrome/locale/en-US/screenshot.dtd chrome/locale/en-US/screenshot.properties chrome/locale/en-US/variables.properties chrome/nightly.jar chrome/skin/browser.css chrome/skin/cbox-check.gif chrome/skin/configwarning.css chrome/skin/crashreports/crash.png chrome/skin/crashreports/sidebar.css chrome/skin/extensions/extensions.css chrome/skin/extensions/incompatible.css chrome/skin/idlarge.png chrome/skin/idsmall.png chrome/skin/leaks/leaks.css chrome/skin/options/options.css chrome/skin/screenshot/screenshot.css chrome/skin/session/session.css
diffstat 65 files changed, 4951 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/.buildrc	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,7 @@
+[dependencies]
+calendaroverlay.xul = /Users/dave/workspace/Nightly/src/chrome/content/calendarOverlay.xul,/Users/dave/workspace/Nightly/src/chrome/content/crashreports/crashreports.inc.xul
+songbirdoverlay.xul = /Users/dave/workspace/Nightly/src/chrome/content/songbirdOverlay.xul,/Users/dave/workspace/Nightly/src/chrome/content/screenshot/screenshot.inc.xul,/Users/dave/workspace/Nightly/src/chrome/content/crashreports/crashreports.inc.xul
+messengeroverlay.xul = /Users/dave/workspace/Nightly/src/chrome/content/messengerOverlay.xul,/Users/dave/workspace/Nightly/src/chrome/content/crashreports/crashreports.inc.xul
+suiteoverlay.xul = /Users/dave/workspace/Nightly/src/chrome/content/suiteOverlay.xul,/Users/dave/workspace/Nightly/src/chrome/content/crashreports/crashreports.inc.xul
+browseroverlay.xul = /Users/dave/workspace/Nightly/src/chrome/content/browserOverlay.xul,/Users/dave/workspace/Nightly/src/chrome/content/screenshot/screenshot.inc.xul,/Users/dave/workspace/Nightly/src/chrome/content/crashreports/crashreports.inc.xul
+
Binary file chrome/content/brand/icon.png has changed
Binary file chrome/content/brand/logo.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/browser.js	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,61 @@
+var nightlyApp = {
+
+storedTitle: document.documentElement.getAttribute("titlemodifier"),
+
+init: function()
+{
+  var brandbundle = document.getElementById("bundle_brand");
+  if (nightly.variables.name==null)
+  {
+    nightly.variables.name=brandbundle.getString("brandShortName");
+  }
+  nightly.variables.brandname=brandbundle.getString("brandFullName");
+  nightly.variables.defaulttitle=nightlyApp.storedTitle;
+  document.getElementById("content").addEventListener("DOMTitleChanged",nightlyApp.titleUpdated,false);
+},
+
+detectLeaks: function(event)
+{
+  this.openURL('chrome://nightly/content/leaks/leaks.xul', event);
+},
+
+openURL: function(url, event)
+{
+  openUILink(url, event, false, true);
+},
+
+titleUpdated: function()
+{
+  if (!gBrowser.mTabbedMode)
+  {
+    gBrowser.updateTitlebar();
+  }
+},
+
+updateTitlebar: function()
+{
+  window.setTimeout("gBrowser.updateTitlebar();", 50);
+},
+
+setCustomTitle: function(title)
+{
+  document.documentElement.setAttribute("titlemodifier",title);
+  document.documentElement.setAttribute("titlemenuseparator"," - ");
+  nightlyApp.updateTitlebar();
+},
+
+setBlankTitle: function()
+{
+  document.documentElement.setAttribute("titlemodifier","");
+  document.documentElement.setAttribute("titlemenuseparator","");
+  nightlyApp.updateTitlebar();
+},
+
+setStandardTitle: function()
+{
+  document.documentElement.setAttribute("titlemodifier",nightlyApp.storedTitle);
+  document.documentElement.setAttribute("titlemenuseparator"," - ");
+  nightlyApp.updateTitlebar();
+}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/browserOverlay.xul	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,81 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE window [
+<!ENTITY % nightlyDTD SYSTEM "chrome://nightly/locale/nightly.dtd">
+%nightlyDTD;
+<!ENTITY % leaksDTD SYSTEM "chrome://nightly/locale/leaks.dtd">
+%leaksDTD;
+]>
+
+<overlay id="NightlyBrowserOverlay"
+         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+       
+  <script type="application/x-javascript" src="nightly.js" />
+  <script type="application/x-javascript" src="browser.js" />
+  <script type="application/x-javascript" src="session/session.js" />
+  <script type="application/x-javascript" src="crashreports/crashreports.js" />
+  <script type="application/x-javascript" src="chrome://nightly/content/platform.js" />
+
+  <!-- Sidebar -->
+  <broadcasterset id="mainBroadcasterSet">
+    <broadcaster id="viewCrashReportsSidebar"
+          autoCheck="false" 
+          label="&nightly.crashreports.sidebar.title;"
+          type="checkbox"
+          group="sidebar"
+          sidebarurl="chrome://nightly/content/crashreports/sidebar.xul"
+          oncommand="toggleSidebar('viewCrashReportsSidebar');"/>
+  </broadcasterset>
+
+  <keyset id="mainKeyset">
+    <key key="s" modifiers="accel,shift" oncommand="nightly.getScreenshot();"/>
+  </keyset>
+
+  <toolbarpalette id="BrowserToolbarPalette">
+    <toolbarbutton id="nightly-tester-enter"
+            class="toolbarbutton-1"
+            label="&nightly.id.insert.label;"
+            tooltiptext="&nightly.id.insert.tooltip;"
+            oncommand="nightly.insertTemplate('buildid');"/>
+  </toolbarpalette>
+  
+  <popupset id="mainPopupSet">
+    <tooltip orient="vertical" id="nightly-crashreport-tooltip" onpopupshowing="return crashreports.popupTooltip(event)">
+      <label/>
+    </tooltip>
+    <popup id="nightly-crashreport-context">
+      <menuitem oncommand="crashreports.copy(event)" label="&nightly.crashreports.copyid;"/>
+    </popup>
+  </popupset>
+  
+  <menupopup id="goPopup">
+    <menuitem id="nightly-session-restore" label="&nightly.session.restore;" insertbefore="endUndoSeparator" oncommand="session.restore()"/>
+  </menupopup>
+  
+  <menupopup id="menu_ToolsPopup">
+    <menu id="nightly-menu" label="Nightly Tester Tools" insertafter="devToolsSeparator">
+      <menupopup onpopupshowing="nightly.menuPopup(event,this);">
+        <menuitem id="build-copy" label="&nightly.id.copy.label;" oncommand="nightly.copyTemplate('buildid');"/>
+        <menuitem id="build-insert" label="&nightly.id.insert.label;" oncommand="nightly.insertTemplate('buildid');"/>
+        <menuitem id="list-copy" label="&nightly.extensions.copy.label;" oncommand="nightly.copyExtensions();"/>
+        <menuitem id="list-insert" label="&nightly.extensions.insert.label;" oncommand="nightly.insertExtensions();"/>
+        <menuseparator/>
+        <menuitem label="&nightly.screenshot.full.label;" oncommand="nightly.getScreenshot();"/>
+        <menuseparator/>
+        <menuitem label="&nightly.openprofile.label;" oncommand="nightly.openProfileDir();"/>
+        <menuseparator id="nightly-crashreports-separator"/>
+        <menu id="nightly-crashreports-recent" label="&nightly.crashreports.recentlist;" oncommand="crashreports.viewIncident(event);" onclick="checkForMiddleClick(this, event);">
+          <menupopup id="nightly-crashreports-incidents">
+            <menuitem disabled="true" label="&nightly.leaks.loading.label;"/>
+          </menupopup>
+        </menu>
+        <menuitem id="nightly-crashreports-sidebar" observes="viewCrashReportsSidebar"/>
+        <menuseparator/>
+        <menuitem label="&nightly.leakreporter.label;" oncommand="nightlyApp.detectLeaks(event);" onclick="checkForMiddleClick(this, event);"/>
+        <menuseparator/>
+        <menuitem label="&nightly.options.label;" oncommand="nightly.launchOptions();"/>
+      </menupopup>
+    </menu>
+  </menupopup>
+  
+</overlay>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/calendar.js	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,54 @@
+var nightlyApp = {
+
+storedTitle: '',
+
+init: function()
+{
+  nightlyApp.storedTitle = document.title;
+  var brandbundle = document.getElementById("bundle_branding");
+  if (nightly.variables.name==null)
+  {
+    nightly.variables.name = brandbundle.getString("brandShortName");
+  }
+  nightly.variables.defaulttitle = nightlyApp.storedTitle;
+  nightly.variables.brandname = brandbundle.getString("brandFullName");
+},
+
+openURL: function(url, event)
+{
+  var uri = Components.classes["@mozilla.org/network/io-service;1"]
+                      .getService(Components.interfaces.nsIIOService)
+                      .newURI(url, null, null);
+
+  var protocolSvc = Components.classes["@mozilla.org/uriloader/external-protocol-service;1"]
+                              .getService(Components.interfaces.nsIExternalProtocolService);
+  protocolSvc.loadUrl(uri);
+},
+
+detectLeaks: function(event)
+{
+  var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
+                     .getService(Components.interfaces.nsIWindowMediator);
+  var win = wm.getMostRecentWindow("Nightly:LeakReporter");
+  if (win)
+    win.focus();
+  else
+    window.openDialog("chrome://nightly/content/leaks/leaks.xul", "_blank", "chrome,all,dialog=no");
+},
+
+setCustomTitle: function(title)
+{
+  document.title = title;
+},
+
+setBlankTitle: function()
+{
+  document.title = '';
+},
+
+setStandardTitle: function()
+{
+  document.title = nightlyApp.storedTitle;
+}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/calendarOverlay.xul	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,58 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE window [
+<!ENTITY % nightlyDTD SYSTEM "chrome://nightly/locale/nightly.dtd">
+%nightlyDTD;
+<!ENTITY % leaksDTD SYSTEM "chrome://nightly/locale/leaks.dtd">
+%leaksDTD;
+]>
+
+<overlay id="NightlyCalendarOverlay"
+         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+       
+  <script type="application/x-javascript" src="nightly.js" />
+  <script type="application/x-javascript" src="calendar.js" />
+  <script type="application/x-javascript" src="breakpad/breakpad.js" />
+  <script type="application/x-javascript" src="chrome://nightly/content/platform.js" />
+
+  <toolbarpalette id="calendarToolbarPalette">
+    <toolbarbutton id="nightly-tester-enter"
+            class="toolbarbutton-1"
+            label="&nightly.id.insert.label;"
+            tooltiptext="&nightly.id.insert.tooltip;"
+            oncommand="nightly.insertTemplate('buildid');"/>
+  </toolbarpalette>
+  
+  <window id="calendar-window">
+    <tooltip orient="vertical" id="nightly-crashreport-tooltip" onpopupshowing="return crashreports.popupTooltip(event)">
+      <label/>
+    </tooltip>
+    <popup id="nightly-crashreport-context">
+      <menuitem oncommand="crashreports.copy(event)" label="&nightly.crashreports.copyid;"/>
+    </popup>
+  </window>
+  
+  <menupopup id="toolsPopup">
+    <menu id="nightly-menu" label="Nightly Tester Tools" insertafter="addonsManager">
+      <menupopup onpopupshowing="nightly.menuPopup(event,this);">
+        <menuitem id="build-copy" label="&nightly.id.copy.label;" oncommand="nightly.copyTemplate('buildid');"/>
+        <menuitem id="build-insert" label="&nightly.id.insert.label;" oncommand="nightly.insertTemplate('buildid');"/>
+        <menuitem id="list-copy" label="&nightly.extensions.copy.label;" oncommand="nightly.copyExtensions();"/>
+        <menuitem id="list-insert" label="&nightly.extensions.insert.label;" oncommand="nightly.insertExtensions();"/>
+        <menuseparator/>
+        <menuitem label="&nightly.openprofile.label;" oncommand="nightly.openProfileDir();"/>
+        <menuseparator id="nightly-crashreports-separator"/>
+        <menu id="nightly-crashreports-recent" label="&nightly.crashreports.recentlist;" oncommand="crashreports.viewIncident(event);" onclick="checkForMiddleClick(this, event);">
+          <menupopup id="nightly-crashreports-incidents">
+            <menuitem disabled="true" label="&nightly.leaks.loading.label;"/>
+          </menupopup>
+        </menu>
+        <menuseparator/>
+        <menuitem label="&nightly.leakreporter.label;" oncommand="nightlyApp.detectLeaks(event);"/>
+        <menuseparator/>
+        <menuitem label="&nightly.options.label;" oncommand="nightly.launchOptions();"/>
+      </menupopup>
+    </menu>
+  </menupopup>
+  
+</overlay>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/configwarning.js	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,64 @@
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+var gOS = null;
+
+var observer = {
+  observe: function(subject, topic, data) {
+    window.focus();
+  }
+}
+
+function init() {
+  var bundle = document.getElementById("bundle");
+  setLabelForButton(document.documentElement.getButton("accept"), bundle.getString("Yes"));
+  setLabelForButton(document.documentElement.getButton("cancel"), bundle.getString("No"));
+
+  gOS = Cc["@mozilla.org/observer-service;1"].
+        getService(Ci.nsIObserverService);
+  gOS.addObserver(observer, "xul-window-visible", false);
+}
+
+function unload() {
+  gOS.removeObserver(observer, "xul-window-visible");
+  gOS = null;
+}
+
+function setLabelForButton(button, label)
+{
+  var accessKey = null;
+  if (/ *\(\&([^&])\)(:)?$/.test(label)) {
+    label = RegExp.leftContext + RegExp.$2;
+    accessKey = RegExp.$1;
+  } else if (/^(.*[^&])?\&(([^&]).*$)/.test(label)) {
+    label = RegExp.$1 + RegExp.$2;
+    accessKey = RegExp.$3;
+  }
+  // && is the magic sequence to embed an & in your label.
+  label = label.replace(/\&\&/g, "&");
+  button.label = label;
+  if (accessKey)
+    button.accessKey = accessKey;
+}
+
+function accept() {
+  var cs = Cc["@oxymoronical.com/nightly/addoncompatibility;1"].
+           createInstance(Ci.nttIAddonCompatibilityService);
+  var em = Cc["@mozilla.org/extensions/manager;1"].
+           getService(Ci.nsIExtensionManager);
+  var items = em.getItemList(Ci.nsIUpdateItem.TYPE_ADDON, {});
+  for (var i = 0; i < items.length; i++) {
+    var addon = cs.getAddonForID(items[i].id);
+    if (!addon.isValid())
+      continue;
+    if (!addon.needsOverride(false) && addon.needsOverride(true))
+      addon.overrideCompatibility(true);
+  }
+
+  var prefs = Cc["@mozilla.org/preferences-service;1"].
+              getService(Ci.nsIPrefBranch);
+  if (prefs.prefHasUserValue("extensions.checkCompatibility"))
+    prefs.clearUserPref("extensions.checkCompatibility");
+  if (prefs.prefHasUserValue("extensions.checkUpdateSecurity"))
+    prefs.clearUserPref("extensions.checkUpdateSecurity");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/configwarning.xul	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE dialog [
+<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
+%brandDTD;
+<!ENTITY % firstrunDTD SYSTEM "chrome://nightly/locale/configwarning.dtd">
+%firstrunDTD;
+]>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://nightly/skin/configwarning.css" type="text/css"?>
+
+<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        title="&dialog.title;" style="&dialog.style;" buttons="accept,cancel"
+        windowtype="NightlyTester:ConfigWarning"
+        onload="init()" onunload="unload()" ondialogaccept="accept()">
+
+  <script src="configwarning.js"/>
+
+  <stringbundle id="bundle" src="chrome://global/locale/commonDialogs.properties"/>
+
+  <hbox id="banner" align="start">
+    <image class="alert-icon"/>
+    <vbox flex="1">
+      <label id="title">&title;</label>
+      <description>&subtitle;</description>
+      <description>&question;</description>
+    </vbox>
+  </hbox>
+
+</dialog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/crashreports/crashreports.js	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,107 @@
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+var crashreports = {
+
+init: function(event)
+{
+  window.removeEventListener("load", crashreports.init, false);
+  if (Components.interfaces.nsICrashReporter)
+  {
+    var service = Components.classes["@blueprintit.co.uk/breakpad;1"]
+                            .getService(Components.interfaces.nttIBreakpadService);
+    
+    if (nightly.preferences.getBoolPref("crashreports.recentlist.display"))
+    {
+      service.loadDatabase();
+      service.addProgressListener(crashreports);
+    }
+    else
+    {
+      document.getElementById("nightly-crashreports-incidents").parentNode.hidden=true;
+    }
+  }
+  else
+  {
+    document.getElementById("nightly-crashreports-separator").hidden = true;
+    document.getElementById("nightly-crashreports-recent").hidden = true;
+    document.getElementById("nightly-crashreports-sidebar").hidden = true;
+  }
+},
+
+copy: function(event)
+{
+  var node = document.popupNode;
+  if (node.id.substring(0,12)=="breakpad-id-")
+  {
+    var id = node.id.substring(12);
+    var clipboard = Components.classes["@mozilla.org/widget/clipboardhelper;1"]
+                              .getService(Components.interfaces.nsIClipboardHelper);
+    clipboard.copyString(id);
+    closeMenus(node);
+  }
+},
+
+onDatabaseLoaded: function()
+{
+  var service = Components.classes["@blueprintit.co.uk/breakpad;1"]
+                          .getService(Components.interfaces.nttIBreakpadService);
+  
+  var incidents = null;
+  
+  incidents = service.getPreviousIncidents(10);
+  
+  var parent = document.getElementById("nightly-crashreports-incidents");
+  if ((incidents) && (incidents.length > 0))
+  {
+    while (parent.firstChild)
+      parent.removeChild(parent.firstChild);
+    
+    var en = incidents.enumerate();
+    while (en.hasMoreElements())
+    {
+      var incident = en.getNext().QueryInterface(Components.interfaces.nttIBreakpadIncident);
+      
+      var item = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "menuitem");
+      item.setAttribute("id", "breakpad-id-"+incident.id);
+      item.setAttribute("tooltip", "nightly-crashreport-tooltip");
+      item.setAttribute("context", "nightly-crashreport-context");
+      item.setAttribute("label", incident.id+" ("+(new Date(incident.date)).toLocaleDateString()+")");
+      parent.appendChild(item);
+    }
+  }
+  else
+  {
+    parent.parentNode.disabled=true;
+  }
+},
+
+popupTooltip: function(event)
+{
+  var node = document.tooltipNode;
+  if (node.id.substring(0,12)=="breakpad-id-")
+  {
+    var id = node.id.substring(12);
+    var service = Components.classes["@blueprintit.co.uk/breakpad;1"]
+                            .getService(Components.interfaces.nttIBreakpadService);
+    var incident = service.getIncident(id);
+    var label = document.getElementById("nightly-crashreport-tooltip").firstChild;
+    label.value=(new Date(incident.date)).toLocaleString();
+    return true;
+  }
+  return false;
+},
+
+viewIncident: function(event)
+{
+  if (event.target.id.substring(0,12)=="breakpad-id-")
+  {
+    var url = nightly.preferences.getCharPref("breakpad.searchurl");
+    var id = event.target.id.substring(15);
+    nightlyApp.openURL(url+id, event);
+  }
+},
+
+QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nttIBreakpadProgressListener])
+}
+
+window.addEventListener("load", crashreports.init, false);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/crashreports/sidebar.js	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,74 @@
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cr = Components.results;
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+const xulns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+var sidebar = {
+
+db: null,
+
+init: function()
+{
+  var service = Cc["@blueprintit.co.uk/breakpad;1"].
+                getService(Ci.nttIBreakpadService);
+  
+  service.loadDatabase();
+  service.addProgressListener(sidebar);
+},
+
+onDatabaseLoaded: function()
+{
+  var service = Cc["@blueprintit.co.uk/breakpad;1"].
+                getService(Ci.nttIBreakpadService);
+
+  var tree = document.getElementById("tree");
+  tree.view = service.getTreeView();
+  
+  document.getElementById("loading").hidden=true;
+  tree.hidden=false;
+},
+
+copy: function(event)
+{
+  var tree = document.getElementById("tree");
+  var id = tree.view.getCellText(tree.currentIndex, tree.columns.getNamedColumn("incidentID"));
+  var clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].
+                  getService(Ci.nsIClipboardHelper);
+  clipboard.copyString(id);
+},
+
+command: function(tree, event, row)
+{
+  var prefservice = Cc['@mozilla.org/preferences-service;1'].
+                    getService(Ci.nsIPrefBranch);
+  var url = prefservice.getCharPref("nightly.breakpad.searchurl");
+  var id = tree.view.getCellText(row, tree.columns.getNamedColumn("incidentID")).substring(3);
+  window.parent.openUILink(url+id, event, false, true);
+},
+
+selectedCommand: function(event)
+{
+  var tree = document.getElementById("tree");
+  sidebar.command(tree, event, tree.currentIndex);
+},
+
+clickCommand: function(event)
+{
+  var tree = document.getElementById("tree");
+  var row = {}, col = {};
+  tree.treeBoxObject.getCellAt(event.clientX, event.clientY, row, col, {});
+  sidebar.command(tree, event, row.value);
+},
+
+checkPopup: function(event)
+{
+  var tree = document.getElementById("tree");
+  var type = tree.view.getCellText(tree.currentIndex, tree.columns.getNamedColumn("type"));
+  return type=="incident";
+},
+
+QueryInterface: XPCOMUtils.generateQI([Ci.nttIBreakpadProgressListener])
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/crashreports/sidebar.xul	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE window [
+<!ENTITY % nightlyDTD SYSTEM "chrome://nightly/locale/nightly.dtd">
+%nightlyDTD;
+<!ENTITY % leaksDTD SYSTEM "chrome://nightly/locale/leaks.dtd">
+%leaksDTD;
+]>
+
+<?xml-stylesheet href="chrome://global/skin/global.css"?>
+<?xml-stylesheet href="chrome://nightly/skin/crashreports/sidebar.css"?>
+
+<page id="CrashReportsSidebar" onload="sidebar.init();"
+      xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  
+  <script src="sidebar.js"/>
+  
+  <popupset>
+    <popup id="crashReportContext" onpopupshowing="return sidebar.checkPopup(event)">
+      <menuitem oncommand="sidebar.copy(event)" label="&nightly.crashreports.copyid;"/>
+    </popup>
+  </popupset>
+  
+  <vbox id="loading" align="center" pack="center" flex="1">
+    <label style="font-size: 150%;" value="&nightly.leaks.loading.label;"/>
+  </vbox>
+  
+  <tree id="tree" hidden="true" flex="1" seltype="single" onkeypress="if (event.keyCode==13) sidebar.selectedCommand(event);">
+    <treecols>
+      <treecol id="incidentID" label="&nightly.crashreports.id;" primary="true" flex="1" persist="width"/>
+      <splitter class="tree-splitter"/>
+      <treecol id="incidentDate" label="&nightly.crashreports.date;" flex="2" hidden="true" persist="width hidden"/>
+    </treecols>
+    
+    <treechildren id="treeroot" context="crashReportContext"
+                  onclick="if (event.button==1) sidebar.clickCommand(event);"
+                  ondblclick="if (event.button==0) sidebar.clickCommand(event);"/>
+  </tree>
+
+</page>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/extensions/addons.xul	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE window SYSTEM "chrome://nightly/locale/nightly.dtd">
+
+<?xml-stylesheet href="chrome://nightly/skin/extensions/extensions.css" type="text/css"?>
+
+<overlay id="NightlyExtensionsOverlay"
+                        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <script type="application/x-javascript" src="extensions.js" />
+  
+  <stringbundleset id="extensionsSet">
+    <stringbundle id="nightlylocale" src="chrome://nightly/locale/nightly.properties"/>
+  </stringbundleset>
+
+  <vbox id="addonContextMenuPalette">
+    <menuitem id="menuitem_appenable" insertafter="menuitem_disable"
+        oncommand="extensionAppEnabler.appEnable();" label="&nightly.appenable.label;"/>
+  </vbox>
+  
+  <hbox id="commandBarBottom">
+    <button id="enableallButton" hidden="true" label="&nightly.enableall.label;"
+            oncommand="extensionAppEnabler.enableAll()"
+            tooltiptext="&nightly.enableall.tooltip;" insertbefore="restartAppButton"/>
+    <separator class="commandBarSeparator" insertbefore="restartAppButton"/>
+  </hbox>
+  
+</overlay>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/extensions/extensions.js	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,106 @@
+var extensionAppEnabler = {
+
+prefs: null,
+cs: null,
+
+init: function() {
+  var pos = gAddonContextMenus.indexOf("menuitem_enable");
+  gAddonContextMenus.splice(pos, 0, "menuitem_appenable");
+  this.cs = Components.classes["@oxymoronical.com/nightly/addoncompatibility;1"]
+                      .createInstance(Components.interfaces.nttIAddonCompatibilityService);
+},
+
+initView: function() {
+  var enableb = document.getElementById("enableallButton");
+  
+  if (!this.prefs.getBoolPref("showEnableAll")) {
+    enableb.hidden = true;
+    return;
+  }
+
+  var parent = document.getElementById("viewGroup");
+  var node = parent.firstChild;
+  while (node != null) {
+    if (node.selected) {
+      switch (node.id) {
+        case "extensions-view":
+        case "themes-view":
+        case "locales-view":
+          enableb.hidden = false;
+          break;
+        default:
+          enableb.hidden = true;
+      }
+      return;
+    }
+    node = node.nextSibling;
+  }
+
+  enableb.hidden = true;
+},
+
+load: function() {
+  var prefservice = Components.classes['@mozilla.org/preferences-service;1']
+                              .getService(Components.interfaces.nsIPrefService);
+  this.prefs = prefservice.getBranch("nightly.")
+                          .QueryInterface(Components.interfaces.nsIPrefBranchInternal);
+
+  var context = document.getElementById("addonContextMenu");
+  context.addEventListener("popupshowing", function() { extensionAppEnabler.popupShowing(); }, false);
+  
+  var radios = document.getElementById("viewGroup");
+  radios.addEventListener("select", function() { extensionAppEnabler.initView(); }, false);
+  this.initView();
+},
+
+popupShowing: function() {
+  var item = gExtensionsView.selectedItem;
+  var menu = document.getElementById("menuitem_appenable");
+  var menuclone = document.getElementById("menuitem_appenable_clone");
+  var addon = this.cs.getAddonForID(item.getAttribute("addonID"));
+  menu.hidden = !(addon.isValid() && addon.needsOverride(false));
+  if (menuclone)
+    menuclone.hidden = menu.hidden;    
+},
+
+appEnable: function() {
+  var ev = gExtensionsView;
+  var item = ev.selectedItem;
+  this.cs.confirmOverride([this.cs.getAddonForID(item.getAttribute("addonID"))], 1);
+  this.syncCompatibility();
+},
+
+enableAll: function() {
+  var addons = [];
+  var items = gExtensionsView.children;
+  for (var i = 0; i < items.length; i++) {
+    var addon = this.cs.getAddonForID(items[i].getAttribute("addonID"));
+    if (addon.isValid() && addon.needsOverride(false))
+      addons.push(addon);
+  }
+  if (addons.length > 0) {
+    this.cs.confirmOverride(addons, addons.length);
+    this.syncCompatibility();
+  }
+},
+
+syncCompatibility: function() {
+  var prefService = Components.classes['@mozilla.org/preferences-service;1']
+                              .getService(Components.interfaces.nsIPrefBranch);
+  try {
+    var checkCompatibility = prefService.getBoolPref("extensions.checkCompatibility");
+    prefService.setBoolPref("extensions.checkCompatibility", !checkCompatibility);
+    prefService.setBoolPref("extensions.checkCompatibility", checkCompatibility);
+ 	}
+ 	catch (e) {
+    prefService.setBoolPref("extensions.checkCompatibility", false);
+    prefService.setBoolPref("extensions.checkCompatibility", true);
+  }
+  updateOptionalViews();
+  updateGlobalCommands();
+}
+}
+
+extensionAppEnabler.init();
+
+window.addEventListener("load", function() { extensionAppEnabler.load(); }, false);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/extensions/incompatible.css	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,3 @@
+richlistitem {
+  -moz-binding: url(chrome://nightly/content/extensions/incompatible.xml#incompatible);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/extensions/incompatible.js	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,25 @@
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+var gItems;
+
+function Startup() {
+  gItems = window.arguments;
+  var list = document.getElementById("addonlist");
+  for (var i = 0; i < gItems.length; i++) {
+    gItems[i].QueryInterface(Ci.nsIUpdateItem)
+             .QueryInterface(Ci.nttIAddon);
+    var ri = document.createElement("richlistitem");
+    ri.setAttribute("name", gItems[i].name);
+    ri.setAttribute("version", gItems[i].version);
+    ri.setAttribute("icon", gItems[i].iconURL);
+    ri.setAttribute("secure", gItems[i].isUpdateSecure(false) ? "true" : "false");
+    ri.setAttribute("compatible", gItems[i].isCompatible(false) ? "true" : "false");
+    list.appendChild(ri);
+  }
+}
+
+function Accept() {
+  for (var i = 0; i < gItems.length; i++)
+    gItems[i].overrideCompatibility(false);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/extensions/incompatible.xml	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE bindings [
+<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
+%brandDTD;
+<!ENTITY % incompatibleDTD SYSTEM "chrome://nightly/locale/incompatible.dtd">
+%incompatibleDTD;
+]>
+
+<bindings xmlns="http://www.mozilla.org/xbl" xmlns:xbl="http://www.mozilla.org/xbl"
+          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <binding id="incompatible" name="incompatible">
+    <content>
+      <xul:hbox align="center">
+        <xul:image xbl:inherits="src=icon"/>
+        <xul:vbox flex="1">
+          <xul:hbox class="name-version">
+            <xul:label xbl:inherits="value=name"/>
+            <xul:label xbl:inherits="value=version"/>
+          </xul:hbox>
+          <xul:label class="warning incompatible" value="&incompatible.label;"/>
+          <xul:label class="warning insecure" value="&insecure.label;"/>
+        </xul:vbox>
+      </xul:hbox>
+    </content>
+  </binding>
+
+</bindings>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/extensions/incompatible.xul	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE window [
+<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
+%brandDTD;
+<!ENTITY % incompatibleDTD SYSTEM "chrome://nightly/locale/incompatible.dtd">
+%incompatibleDTD;
+]>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://nightly/content/extensions/incompatible.css" type="text/css"?>
+<?xml-stylesheet href="chrome://nightly/skin/extensions/incompatible.css" type="text/css"?>
+
+<dialog title="&window.title;" onload="Startup()" style="&window.style;"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        buttonlabelcancel="&window.cancel;" buttonlabelaccept="&window.accept;"
+        ondialogaccept="Accept()">
+
+  <script src="incompatible.js" type="application/x-javascript"/>
+
+  <hbox align="center">
+    <image class="alert-icon"/>
+    <description flex="1" id="warning">&warning.label;</description>
+  </hbox>
+
+  <richlistbox id="addonlist" flex="1">
+  </richlistbox>
+
+</dialog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/includes/tree-utils.js	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,1679 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is The JavaScript Debugger.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Robert Ginda, <rginda@netscape.com>, original author
+ *   Dave Townsend, <mossop@blueprintit.co.uk>, Added cell and row property support
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * BasicOView provides functionality of tree whose elements have no children.
+ * Usage:
+ * var myTree = new BasicOView()
+ * myTree.setColumnNames (["col 1", "col 2"]);
+ * myTree.data = [["row 1, col 1", "row 1, col 2"],
+ *                    ["row 2, col 1", "row 2, col 2"]];
+ * { override get*Properties, etc, as suits your purpose. }
+ *
+ * treeBoxObject.view = myTree;
+ * 
+ * You'll need to make the appropriate myTree.tree.invalidate calls
+ * when myTree.data changes.
+ */
+
+function BasicOView()
+{
+    this.tree = null;
+}
+
+/* functions *you* should call to initialize and maintain the tree state */
+
+/* scroll the line specified by |line| to the center of the tree */
+BasicOView.prototype.centerLine =
+function bov_ctrln (line)
+{
+    var first = this.tree.getFirstVisibleRow();
+    var last = this.tree.getLastVisibleRow();
+    this.scrollToRow(line - (last - first + 1) / 2);
+}
+
+/* call this to set the association between column names and data columns */
+BasicOView.prototype.setColumnNames =
+function bov_setcn (aryNames)
+{
+    this.columnNames = new Object();
+    for (var i = 0; i < aryNames.length; ++i)
+        this.columnNames[aryNames[i]] = i;
+}
+
+/*
+ * scroll the source so |line| is at either the top, center, or bottom
+ * of the view, depending on the value of |align|.
+ *
+ * line is the one based target line.
+ * if align is negative, the line will be scrolled to the top, if align is
+ * zero the line will be centered, and if align is greater than 0 the line
+ * will be scrolled to the bottom.  0 is the default.
+ */
+BasicOView.prototype.scrollTo =
+function bov_scrollto (line, align)
+{
+    if (!this.tree)
+        return;
+
+    var headerRows = 1;
+
+    var first = this.tree.getFirstVisibleRow();
+    var last  = this.tree.getLastVisibleRow();
+    var viz   = last - first + 1 - headerRows; /* total number of visible rows */
+
+    /* all rows are visible, nothing to scroll */
+    if (first == 0 && last >= this.rowCount)
+        return;
+
+    /* tree lines are 0 based, we accept one based lines, deal with it */
+    --line;
+
+    /* safety clamp */
+    if (line < 0)
+        line = 0;
+    if (line >= this.rowCount)
+        line = this.rowCount - 1;
+
+    if (align < 0)
+    {
+        if (line > this.rowCount - viz)    /* overscroll, can't put a row from */
+            line = this.rowCount - viz; /* last page at the top. */
+        this.tree.scrollToRow(line);
+    }
+    else if (align > 0)
+    {
+        if (line < viz) /* underscroll, can't put a row from the first page */
+            line = 0;   /* at the bottom. */
+        else
+            line = line - viz + headerRows;
+
+        this.tree.scrollToRow(line);
+    }
+    else
+    {
+        var half_viz = viz / 2;
+        /* lines past this line can't be centered without causing the tree
+         * to show more rows than we have. */
+        var lastCenterable = this.rowCount - half_viz;
+        if (line > half_viz)
+            line = lastCenterable;
+        /* lines before this can't be centered without causing the tree
+         * to attempt to display negative rows. */
+        else if (line < half_viz)
+            line = half_viz;
+        else
+        /* round the vizible rows down to a whole number, or we try to end up
+         * on a N + 0.5 row! */
+            half_viz = Math.floor(half_viz);
+
+        this.tree.scrollToRow(line - half_viz);
+    }
+}
+
+BasicOView.prototype.__defineGetter__("selectedIndex", bov_getsel);
+function bov_getsel()
+{
+    if (!this.tree || this.tree.view.selection.getRangeCount() < 1)
+        return -1;
+
+    var min = new Object();
+    this.tree.view.selection.getRangeAt(0, min, {});
+    return min.value;
+}
+
+BasicOView.prototype.__defineSetter__("selectedIndex", bov_setsel);
+function bov_setsel(i)
+{
+    if (i == -1)
+        this.tree.view.selection.clearSelection();
+    else
+        this.tree.view.selection.timedSelect (i, 500);
+    return i;
+}
+
+/*
+ * functions the tree will call to retrieve the list state (nsITreeView.)
+ */
+
+BasicOView.prototype.rowCount = 0;
+
+BasicOView.prototype.getCellProperties =
+function bov_cellprops (row, col, properties)
+{
+}
+
+BasicOView.prototype.getColumnProperties =
+function bov_colprops (col, properties)
+{
+}
+
+BasicOView.prototype.getRowProperties =
+function bov_rowprops (index, properties)
+{
+}
+
+BasicOView.prototype.isContainer =
+function bov_isctr (index)
+{
+    return false;
+}
+
+BasicOView.prototype.isContainerOpen =
+function bov_isctropen (index)
+{
+    return false;
+}
+
+BasicOView.prototype.isContainerEmpty =
+function bov_isctrempt (index)
+{
+    return false;
+}
+
+BasicOView.prototype.isSeparator =
+function bov_isseparator (index)
+{
+    return false;
+}
+
+BasicOView.prototype.isSorted =
+function bov_issorted (index)
+{
+    return false;
+}
+
+BasicOView.prototype.canDrop =
+function bov_drop (index, orientation)
+{
+    return false;
+}
+
+BasicOView.prototype.drop =
+function bov_drop (index, orientation)
+{
+    return false;
+}
+
+BasicOView.prototype.getParentIndex =
+function bov_getpi (index)
+{
+    if (index < 0)
+        return -1;
+
+    return 0;
+}
+
+BasicOView.prototype.hasNextSibling =
+function bov_hasnxtsib (rowIndex, afterIndex)
+{
+    return (afterIndex < (this.rowCount - 1));
+}
+
+BasicOView.prototype.getLevel =
+function bov_getlvl (index)
+{
+    return 0;
+}
+
+BasicOView.prototype.getImageSrc =
+function bov_getimgsrc (row, col)
+{
+}
+
+BasicOView.prototype.getProgressMode =
+function bov_getprgmode (row, col)
+{
+}
+
+BasicOView.prototype.getCellValue =
+function bov_getcellval (row, col)
+{
+}
+
+BasicOView.prototype.getCellText =
+function bov_getcelltxt (row, col)
+{
+    if (!this.columnNames)
+        return "";
+    
+    if (typeof col == "object")
+        col = col.id;
+
+    var ary = col.match (/:(.*)/);
+    if (ary)
+        col = ary[1];
+
+    var colName = this.columnNames[col];
+    
+    if (typeof colName == "undefined")
+        return "";
+    
+    return this.data[row][colName];
+}
+
+BasicOView.prototype.setTree =
+function bov_seto (tree)
+{
+    this.tree = tree;
+}
+
+BasicOView.prototype.toggleOpenState =
+function bov_toggleopen (index)
+{
+}
+
+BasicOView.prototype.cycleHeader =
+function bov_cyclehdr (col)
+{
+}
+
+BasicOView.prototype.selectionChanged =
+function bov_selchg ()
+{
+}
+
+BasicOView.prototype.cycleCell =
+function bov_cyclecell (row, col)
+{
+}
+
+BasicOView.prototype.isEditable =
+function bov_isedit (row, col)
+{
+    return false;
+}
+
+BasicOView.prototype.setCellValue =
+function bov_setct (row, col, value)
+{
+}
+
+BasicOView.prototype.setCellText =
+function bov_setct (row, col, value)
+{
+}
+
+BasicOView.prototype.onRouteFocus =
+function bov_rfocus (event)
+{
+    if ("onFocus" in this)
+        this.onFocus(event);
+}
+
+BasicOView.prototype.onRouteBlur =
+function bov_rblur (event)
+{
+    if ("onBlur" in this)
+        this.onBlur(event);
+}
+
+BasicOView.prototype.onRouteDblClick =
+function bov_rdblclick (event)
+{
+    if (!("onRowCommand" in this) || event.target.localName != "treechildren")
+        return;
+
+    var rowIndex = this.tree.view.selection.currentIndex;
+    if (rowIndex == -1 || rowIndex > this.rowCount)
+        return;
+    var rec = this.childData.locateChildByVisualRow(rowIndex);
+    if (!rec)
+    {
+        ASSERT (0, "bogus row index " + rowIndex);
+        return;
+    }
+
+    this.onRowCommand(rec, event);
+}
+
+BasicOView.prototype.onRouteKeyPress =
+function bov_rkeypress (event)
+{
+    var rec;
+    var rowIndex;
+    
+    if ("onRowCommand" in this && (event.keyCode == 13 || event.charCode == 32))
+    {
+        if (!this.selection)
+            return;
+        
+        rowIndex = this.tree.view.selection.currentIndex;
+        if (rowIndex == -1 || rowIndex > this.rowCount)
+            return;
+        rec = this.childData.locateChildByVisualRow(rowIndex);
+        if (!rec)
+        {
+            ASSERT (0, "bogus row index " + rowIndex);
+            return;
+        }
+
+        this.onRowCommand(rec, event);
+    }
+    else if ("onKeyPress" in this)
+    {
+        rowIndex = this.tree.view.selection.currentIndex;
+        if (rowIndex != -1 && rowIndex < this.rowCount)
+        {
+            rec = this.childData.locateChildByVisualRow(rowIndex);
+            if (!rec)
+            {
+                ASSERT (0, "bogus row index " + rowIndex);
+                return;
+            }
+        }
+        else
+        {
+            rec = null;
+        }
+        
+        this.onKeyPress(rec, event);
+    }
+}
+
+BasicOView.prototype.performAction =
+function bov_pact (action)
+{
+}
+
+BasicOView.prototype.performActionOnRow =
+function bov_pactrow (action)
+{
+}
+
+BasicOView.prototype.performActionOnCell =
+function bov_pactcell (action)
+{
+}
+
+/*
+ * record for the XULTreeView.  these things take care of keeping the
+ * XULTreeView properly informed of changes in value and child count.  you 
+ * shouldn't have to maintain tree state at all.
+ *
+ * |share| should be an otherwise empty object to store cache data.
+ * you should use the same object as the |share| for the XULTreeView that you
+ * indend to contain these records.
+ *
+ */
+function XULTreeViewRecord(share)
+{
+    this._share = share;
+    this.visualFootprint = 1;
+    this.isHidden = true; /* records are considered hidden until they are
+                           * inserted into a live tree */
+}
+
+XULTreeViewRecord.prototype.properties = "";
+
+XULTreeViewRecord.prototype.isContainerOpen = false;
+
+/*
+ * walk the parent tree to find our tree container.  return null if there is
+ * none
+ */
+XULTreeViewRecord.prototype.findContainerTree =
+function xtvr_gettree ()
+{
+    if (!("parentRecord" in this))
+        return null;
+    var parent = this.parentRecord;
+    
+    while (parent)
+    {
+        if ("_treeView" in parent)
+            return parent._treeView;
+        if ("parentRecord" in parent)
+            parent = parent.parentRecord;
+        else
+            parent = null;
+    }
+
+    return null;
+}
+
+XULTreeViewRecord.prototype.__defineGetter__("childIndex", xtvr_getChildIndex);
+function xtvr_getChildIndex ()
+{
+    //dd ("getChildIndex {");
+    
+    if (!("parentRecord" in this))
+    {
+        delete this._childIndex;
+        //dd ("} -1");
+        return -1;
+    }
+    
+    if ("_childIndex" in this)
+    {
+        if ("childData" in this && this._childIndex in this.childData &&
+            this.childData[this._childIndex] == this)
+        {
+            //dd ("} " + this._childIndex);
+            return this._childIndex;
+        }
+    }
+
+    var childData = this.parentRecord.childData;
+    var len = childData.length;
+    for (var i = 0; i < len; ++i)
+    {
+        if (childData[i] == this)
+        {
+            this._childIndex = i;
+            //dd ("} " + this._childIndex);
+            return i;
+        }
+    }
+    
+    delete this._childIndex;
+    //dd ("} -1");
+    return -1;
+}
+
+XULTreeViewRecord.prototype.__defineSetter__("childIndex", xtvr_setChildIndex);
+function xtvr_setChildIndex ()
+{
+    dd("xtvr: childIndex is read only, ignore attempt to write to it\n");
+    if (typeof getStackTrace == "function")
+        dd(getStackTrace());
+}
+
+/* count the number of parents, not including the root node */
+XULTreeViewRecord.prototype.__defineGetter__("level", xtvr_getLevel);
+function xtvr_getLevel ()
+{
+    if (!("parentRecord" in this))
+        return -1;
+    
+    var rv = 0;
+    var parentRecord = this.parentRecord;
+    while ("parentRecord" in parentRecord &&
+           (parentRecord = parentRecord.parentRecord)) ++rv;
+    return rv;
+}
+
+/*
+ * associates a property name on this record, with a column in the tree.  This
+ * method will set up a get/set pair for the property name you specify which
+ * will take care of updating the tree when the value changes.  DO NOT try
+ * to change your mind later.  Do not attach a different name to the same colID,
+ * and do not rename the colID.  You have been warned.
+ */
+XULTreeViewRecord.prototype.setColumnPropertyName =
+function xtvr_setcol (colID, propertyName)
+{
+    function xtvr_getValueShim ()
+    {
+        return this._colValues[colID];
+    }
+    function xtvr_setValueShim (newValue)
+    {
+        this._colValues[colID] = newValue;
+        return newValue;
+    }
+
+    if (!("_colValues" in this))
+        this._colValues = new Object();
+    if (!("_colProperties" in this))
+        this._colProperties = new Object();
+    
+    if (typeof propertyName == "function")
+    {
+        this._colValues.__defineGetter__(colID, propertyName);
+    }
+    else
+    {
+        this.__defineGetter__(propertyName, xtvr_getValueShim);
+        this.__defineSetter__(propertyName, xtvr_setValueShim);
+    }
+}
+
+XULTreeViewRecord.prototype.setColumnPropertyValue =
+function xtvr_setcolv (colID, value)
+{
+    this._colValues[colID] = value;
+}
+
+XULTreeViewRecord.prototype.setColumnProperties =
+function xtvr_setcolp (colID, value)
+{
+    this._colProperties[colID] = value;
+}
+
+/*
+ * set the default sort column and reSort.
+ */
+XULTreeViewRecord.prototype.setSortColumn =
+function xtvr_setcol (colID, dir)
+{
+    //dd ("setting sort column to " + colID);
+    this._share.sortColumn = colID;
+    this._share.sortDirection = (typeof dir == "undefined") ? 1 : dir;
+    this.reSort();
+}
+
+/*
+ * set the default sort direction.  1 is ascending, -1 is descending, 0 is no
+ * sort.  setting this to 0 will *not* recover the natural insertion order,
+ * it will only affect newly added items.
+ */
+XULTreeViewRecord.prototype.setSortDirection =
+function xtvr_setdir (dir)
+{
+    this._share.sortDirection = dir;
+}
+
+/*
+ * invalidate this row in the tree
+ */
+XULTreeViewRecord.prototype.invalidate =
+function xtvr_invalidate()
+{
+    var tree = this.findContainerTree();
+    if (tree)
+    {
+        var row = this.calculateVisualRow();
+        if (row != -1)
+            tree.tree.invalidateRow(row);
+    }
+}
+
+/*
+ * invalidate any data in the cache.
+ */
+XULTreeViewRecord.prototype.invalidateCache =
+function xtvr_killcache()
+{
+    this._share.rowCache = new Object();
+    this._share.lastComputedIndex = -1;
+    this._share.lastIndexOwner = null;
+}
+
+/*
+ * default comparator function for sorts.  if you want a custom sort, override
+ * this method.  We declare xtvr_sortcmp as a top level function, instead of
+ * a function expression so we can refer to it later.
+ */
+XULTreeViewRecord.prototype.sortCompare = xtvr_sortcmp;
+function xtvr_sortcmp (a, b)
+{
+    var sc = a._share.sortColumn;
+    var sd = a._share.sortDirection;    
+    
+    a = a[sc];
+    b = b[sc];
+
+    if (a < b)
+        return -1 * sd;
+    
+    if (a > b)
+        return 1 * sd;
+    
+    return 0;
+}
+
+/*
+ * this method will cause all child records to be reSorted.  any records
+ * with the default sortCompare method will be sorted by the colID passed to
+ * setSortColumn.
+ *
+ * the local parameter is used internally to control whether or not the 
+ * sorted rows are invalidated.  don't use it yourself.
+ */
+XULTreeViewRecord.prototype.reSort =
+function xtvr_resort (leafSort)
+{
+    if (!("childData" in this) || this.childData.length < 1 ||
+        (this.childData[0].sortCompare == xtvr_sortcmp &&
+         !("sortColumn" in this._share) || this._share.sortDirection == 0))
+    {
+        /* if we have no children, or we have the default sort compare and no
+         * sort flags, then just exit */
+        return;
+    }
+
+    this.childData.sort(this.childData[0].sortCompare);
+    
+    for (var i = 0; i < this.childData.length; ++i)
+    {
+        if ("isContainerOpen" in this.childData[i] &&
+            this.childData[i].isContainerOpen)
+            this.childData[i].reSort(true);
+        else
+            this.childData[i].sortIsInvalid = true;
+    }
+    
+    if (!leafSort)
+    {
+        this.invalidateCache();
+        var tree = this.findContainerTree();
+        if (tree && tree.tree)
+        {
+            var rowIndex = this.calculateVisualRow();
+            /*
+            dd ("invalidating " + rowIndex + " - " +
+                (rowIndex + this.visualFootprint - 1));
+            */
+            tree.tree.invalidateRange (rowIndex,
+                                       rowIndex + this.visualFootprint - 1);
+        }
+    }
+    delete this.sortIsInvalid;
+}
+    
+/*
+ * call this to indicate that this node may have children at one point.  make
+ * sure to call it before adding your first child.
+ */
+XULTreeViewRecord.prototype.reserveChildren =
+function xtvr_rkids (always)
+{
+    if (!("childData" in this))
+        this.childData = new Array();
+    if (!("isContainerOpen" in this))
+        this.isContainerOpen = false;
+    if (always)
+        this.alwaysHasChildren = true;
+    else
+        delete this.alwaysHasChildren;
+}
+
+/*
+ * add a child to the end of the child list for this record.  takes care of 
+ * updating the tree as well.
+ */
+XULTreeViewRecord.prototype.appendChild =
+function xtvr_appchild (child)
+{
+    if (!(child instanceof XULTreeViewRecord))
+        throw Components.results.NS_ERROR_INVALID_ARG;
+    
+    child.isHidden = false;
+    child.parentRecord = this;
+    this.childData.push(child);
+    
+    if ("isContainerOpen" in this && this.isContainerOpen)
+    {
+        //dd ("appendChild: " + xtv_formatRecord(child, ""));
+        if (this.calculateVisualRow() >= 0)
+        {
+            var tree = this.findContainerTree();
+            if (tree && tree.frozen)
+                this.needsReSort = true;
+            else
+                this.reSort(true);  /* reSort, don't invalidate.  we're going  
+                                     * to do that in the 
+                                     * onVisualFootprintChanged call. */
+        }
+        this.onVisualFootprintChanged(child.calculateVisualRow(),
+                                      child.visualFootprint);
+    }
+}
+
+/*
+ * add a list of children to the end of the child list for this record.
+ * faster than multiple appendChild() calls.
+ */
+XULTreeViewRecord.prototype.appendChildren =
+function xtvr_appchild (children)
+{
+    var idx = this.childData.length;
+    var delta = 0;
+    var len = children.length;
+    for (var i = 0; i <  len; ++i)
+    {
+        var child = children[i];
+        child.isHidden = false;
+        child.parentRecord = this;
+        this.childData.push(child);
+        delta += child.visualFootprint;
+    }
+    
+    if ("isContainerOpen" in this && this.isContainerOpen)
+    {
+        if (this.calculateVisualRow() >= 0)
+        {
+            this.reSort(true);  /* reSort, don't invalidate.  we're going to do
+                                 * that in the onVisualFootprintChanged call. */
+        }
+        this.onVisualFootprintChanged(this.childData[0].calculateVisualRow(),
+                                      delta);
+    }
+}
+
+/*
+ * remove a child from this record. updates the tree too.  DON'T call this with
+ * an index not actually contained by this record.
+ */
+XULTreeViewRecord.prototype.removeChildAtIndex =
+function xtvr_remchild (index)
+{
+    if (!ASSERT(this.childData.length, "removing from empty childData"))
+        return;
+    
+    var orphan = this.childData[index];
+    var fpDelta = -orphan.visualFootprint;
+    var changeStart = orphan.calculateVisualRow();
+    delete orphan.parentRecord;
+    arrayRemoveAt (this.childData, index);
+    
+    if (!orphan.isHidden && "isContainerOpen" in this && this.isContainerOpen)
+    {
+        this.onVisualFootprintChanged (changeStart, fpDelta);
+    }
+}
+
+/*
+ * hide this record and all descendants.
+ */
+XULTreeViewRecord.prototype.hide =
+function xtvr_hide ()
+{
+    if (this.isHidden)
+        return;
+
+    /* get the row before hiding */
+    var row = this.calculateVisualRow();
+    this.invalidateCache();
+    this.isHidden = true;
+    /* go right to the parent so we don't muck with our own visualFootprint
+     * record, we'll need it to be correct if we're ever unHidden. */
+    if ("parentRecord" in this)
+        this.parentRecord.onVisualFootprintChanged (row, -this.visualFootprint);
+}
+
+/*
+ * unhide this record and all descendants.
+ */
+XULTreeViewRecord.prototype.unHide =
+function xtvr_uhide ()
+{
+    if (!this.isHidden)
+        return;
+
+    this.isHidden = false;
+    this.invalidateCache();
+    var row = this.calculateVisualRow();
+    if (this.parentRecord)
+        this.parentRecord.onVisualFootprintChanged (row, this.visualFootprint);
+}
+
+/*
+ * open this record, exposing it's children.  DON'T call this method if the
+ * record has no children.
+ */
+XULTreeViewRecord.prototype.open =
+function xtvr_open ()
+{
+    if (this.isContainerOpen)
+        return;
+
+    if ("onPreOpen" in this)
+        this.onPreOpen();
+    
+    this.isContainerOpen = true;
+    var delta = 0;
+    for (var i = 0; i < this.childData.length; ++i)
+    {
+        if (!this.childData[i].isHidden)
+            delta += this.childData[i].visualFootprint;
+    }
+
+    /* this reSort should only happen if the sort column changed */
+    this.reSort(true);
+    this.visualFootprint += delta;
+    if ("parentRecord" in this)
+    {
+        this.parentRecord.onVisualFootprintChanged(this.calculateVisualRow(),
+                                                   0);
+        this.parentRecord.onVisualFootprintChanged(this.calculateVisualRow() +
+                                                   1, delta);
+    }
+}
+
+/*
+ * close this record, hiding it's children.  DON'T call this method if the record
+ * has no children, or if it is already closed.
+ */
+XULTreeViewRecord.prototype.close =
+function xtvr_close ()
+{
+    if (!this.isContainerOpen)
+        return;
+    
+    this.isContainerOpen = false;
+    var delta = 1 - this.visualFootprint;
+    this.visualFootprint += delta;
+    if ("parentRecord" in this)
+    {
+        this.parentRecord.onVisualFootprintChanged(this.calculateVisualRow(),
+                                                   0);
+        this.parentRecord.onVisualFootprintChanged(this.calculateVisualRow() +
+                                                   1, delta);
+    }
+
+    if ("onPostClose" in this)
+        this.onPostClose();
+}
+
+/*
+ * called when a node above this one grows or shrinks.  we need to adjust
+ * our own visualFootprint to match the change, and pass the message on.
+ */
+XULTreeViewRecord.prototype.onVisualFootprintChanged =
+function xtvr_vpchange (start, amount)
+{
+    /* if we're not hidden, but this notification came from a hidden node 
+     * (start == -1), ignore it, it doesn't affect us. */
+    if (start == -1 && !this.isHidden)
+    {
+        
+        //dd ("vfp change (" + amount + ") from hidden node ignored.");
+        return;
+    }
+    
+    this.visualFootprint += amount;
+
+    if ("parentRecord" in this)
+        this.parentRecord.onVisualFootprintChanged(start, amount);
+}
+
+/*
+ * calculate the "visual" row for this record.  If the record isn't actually
+ * visible return -1.
+ * eg.
+ * Name        Visual Row
+ * node1       0
+ *   node11    1
+ *   node12    2
+ * node2       3
+ *   node21    4
+ * node3       5
+ */
+XULTreeViewRecord.prototype.calculateVisualRow =
+function xtvr_calcrow ()
+{
+    /* if this is the second time in a row that someone asked us, fetch the last
+     * result from the cache. */
+    if (this._share.lastIndexOwner == this)
+        return this._share.lastComputedIndex;
+
+    var vrow;
+
+        /* if this is an uninserted or hidden node, or... */
+    if (!("parentRecord" in this) || (this.isHidden) ||
+        /* if parent isn't open, or... */
+        (!this.parentRecord.isContainerOpen) ||
+        /* parent isn't visible */
+        ((vrow = this.parentRecord.calculateVisualRow()) == -1))
+    {
+        /* then we're not visible, return -1 */
+        //dd ("cvr: returning -1");
+        return -1;
+    }
+
+    /* parent is the root node XXX parent is not visible */
+    if (vrow == null)
+        vrow = 0;
+    else
+    /* parent is not the root node, add one for the space they take up. */
+        ++vrow;
+
+    /* add in the footprint for all of the earlier siblings */
+    var ci = this.childIndex;
+    for (var i = 0; i < ci; ++i)
+    {
+        if (!this.parentRecord.childData[i].isHidden)
+            vrow += this.parentRecord.childData[i].visualFootprint;
+    }
+
+    /* save this calculation to the cache. */
+    this._share.lastIndexOwner = this;
+    this._share.lastComputedIndex = vrow;
+
+    return vrow;
+}
+
+/*
+ * locates the child record for the visible row |targetRow|.  DO NOT call this
+ * with a targetRow less than this record's visual row, or greater than this
+ * record's visual row + the number of visible children it has.
+ */
+XULTreeViewRecord.prototype.locateChildByVisualRow =
+function xtvr_find (targetRow, myRow)
+{
+    if (targetRow in this._share.rowCache)
+        return this._share.rowCache[targetRow];
+
+    /* if this is true, we *are* the index */
+    if (targetRow == myRow)
+        return (this._share.rowCache[targetRow] = this);
+
+    /* otherwise, we've got to search the kids */
+    var childStart = myRow; /* childStart represents the starting visual row
+                             * for the child we're examining. */
+    for (var i = 0; i < this.childData.length; ++i)
+    {
+        var child = this.childData[i];
+        /* ignore hidden children */
+        if (child.isHidden)
+            continue;
+        /* if this kid is the targetRow, we're done */
+        if (childStart == targetRow)
+            return (this._share.rowCache[targetRow] = child);
+        /* if this kid contains the index, ask *it* to find the record */
+        else if (targetRow <= childStart + child.visualFootprint) {
+            /* this *has* to succeed */
+            var rv = child.locateChildByVisualRow(targetRow, childStart + 1);
+            //XXXASSERT (rv, "Can't find a row that *has* to be there.");
+            /* don't cache this, the previous call to locateChildByVisualRow
+             * just did. */
+            return rv;
+        }
+
+        /* otherwise, get ready to ask the next kid */
+        childStart += child.visualFootprint;
+    }
+
+    return null;
+}   
+
+/* XTLabelRecords can be used to drop a label into an arbitrary place in an
+ * arbitrary tree.  normally, specializations of XULTreeViewRecord are tied to
+ * a specific tree because of implementation details.  XTLabelRecords are
+ * specially designed (err, hacked) to work around these details.  this makes
+ * them slower, but more generic.
+ *
+ * we set up a getter for _share that defers to the parent object.  this lets
+ * XTLabelRecords work in any tree.
+ */
+function XTLabelRecord (columnName, label, blankCols)
+{
+    this.setColumnPropertyName (columnName, "label");
+    this.label = label;
+    this.property = null;
+    
+    if (typeof blankCols == "object")
+    {
+        for (var i in blankCols)
+            this._colValues[blankCols[i]] = "";
+    }
+}
+
+XTLabelRecord.prototype = new XULTreeViewRecord (null);
+
+XTLabelRecord.prototype.__defineGetter__("_share", tolr_getshare);
+function tolr_getshare()
+{
+    if ("parentRecord" in this)
+        return this.parentRecord._share;
+
+    ASSERT (0, "XTLabelRecord cannot be the root of a visible tree.");
+    return null;
+}
+
+/* XTRootRecord is used internally by XULTreeView, you probably don't need to 
+ * make any of these */ 
+function XTRootRecord (tree, share)
+{
+    this._share = share;
+    this._treeView = tree;
+    this.visualFootprint = 0;
+    this.isHidden = false;
+    this.reserveChildren();
+    this.isContainerOpen = true;
+}
+
+/* no cache passed in here, we set it in the XTRootRecord contructor instead. */
+XTRootRecord.prototype = new XULTreeViewRecord (null);
+
+XTRootRecord.prototype.open =
+XTRootRecord.prototype.close =
+function torr_notimplemented()
+{
+    /* don't do this on a root node */
+}
+
+XTRootRecord.prototype.calculateVisualRow =
+function torr_calcrow ()
+{
+    return null;
+}
+
+XTRootRecord.prototype.reSort =
+function torr_resort ()
+{
+    if ("_treeView" in this && this._treeView.frozen)
+    {
+        this._treeView.needsReSort = true;
+        return;
+    }
+    
+    if (!("childData" in this) || this.childData.length < 1 ||
+        (this.childData[0].sortCompare == xtvr_sortcmp &&
+         !("sortColumn" in this._share) || this._share.sortDirection == 0))
+    {
+        /* if we have no children, or we have the default sort compare but we're
+         * missing a sort flag, then just exit */
+        return;
+    }
+    
+    this.childData.sort(this.childData[0].sortCompare);
+    
+    for (var i = 0; i < this.childData.length; ++i)
+    {
+        if ("isContainerOpen" in this.childData[i] &&
+            this.childData[i].isContainerOpen)
+            this.childData[i].reSort(true);
+        else
+            this.childData[i].sortIsInvalid = true;
+    }
+    
+    if ("_treeView" in this && this._treeView.tree)
+    {
+        /*
+        dd ("root node: invalidating 0 - " + this.visualFootprint +
+            " for sort");
+        */
+        this.invalidateCache();
+        this._treeView.tree.invalidateRange (0, this.visualFootprint);
+    }
+}
+
+XTRootRecord.prototype.locateChildByVisualRow =
+function torr_find (targetRow)
+{
+    if (targetRow in this._share.rowCache)
+        return this._share.rowCache[targetRow];
+
+    var childStart = -1; /* childStart represents the starting visual row
+                          * for the child we're examining. */
+    for (var i = 0; i < this.childData.length; ++i)
+    {
+        var child = this.childData[i];
+        /* ignore hidden children */
+        if (child.isHidden)
+            continue;
+        /* if this kid is the targetRow, we're done */
+        if (childStart == targetRow)
+            return (this._share.rowCache[targetRow] = child);
+        /* if this kid contains the index, ask *it* to find the record */
+        else if (targetRow <= childStart + child.visualFootprint) {
+            /* this *has* to succeed */
+            var rv = child.locateChildByVisualRow(targetRow, childStart + 1);
+            //XXXASSERT (rv, "Can't find a row that *has* to be there.");
+            /* don't cache this, the previous call to locateChildByVisualRow
+             * just did. */
+            return rv;
+        }
+
+        /* otherwise, get ready to ask the next kid */
+        childStart += child.visualFootprint;
+    }
+
+    return null;
+}
+
+XTRootRecord.prototype.onVisualFootprintChanged =
+function torr_vfpchange (start, amount)
+{
+    if (!this._treeView.frozen)
+    {
+        this.invalidateCache();
+        this.visualFootprint += amount;
+        if ("_treeView" in this && "tree" in this._treeView && 
+            this._treeView.tree)
+        {
+            if (amount != 0)
+                this._treeView.tree.rowCountChanged (start, amount);
+            else
+                this._treeView.tree.invalidateRow (start);
+        }
+    }
+    else
+    {
+        if ("changeAmount"  in this._treeView)
+            this._treeView.changeAmount += amount;
+        else
+            this._treeView.changeAmount = amount;
+        if ("changeStart" in this._treeView)
+            this._treeView.changeStart = 
+                Math.min (start, this._treeView.changeStart);
+        else
+            this._treeView.changeStart = start;
+    }
+}
+
+/*
+ * XULTreeView provides functionality of tree whose elements have multiple
+ * levels of children.
+ */
+
+function XULTreeView(share)
+{
+    if (!share)
+        share = new Object();
+    this.childData = new XTRootRecord(this, share);
+    this.childData.invalidateCache();
+    this.tree = null;
+    this.share = share;
+    this.frozen = 0;
+}
+
+/* functions *you* should call to initialize and maintain the tree state */
+
+/*
+ * Changes to the tree contents will not cause the tree to be invalidated
+ * until thaw() is called.  All changes will be pooled into a single invalidate
+ * call.
+ *
+ * Freeze/thaws are nestable, the tree will not update until the number of
+ * thaw() calls matches the number of freeze() calls.
+ */
+XULTreeView.prototype.freeze =
+function xtv_freeze ()
+{
+    if (++this.frozen == 1)
+    {
+        this.changeStart = 0;
+        this.changeAmount = 0;
+    }
+    //dd ("freeze " + this.frozen);
+}
+
+/*
+ * Reflect any changes to the tree content since the last freeze.
+ */
+XULTreeView.prototype.thaw =
+function xtv_thaw ()
+{
+    if (this.frozen == 0)
+    {
+        ASSERT (0, "not frozen");
+        return;
+    }
+    
+    if (--this.frozen == 0 && "changeStart" in this)
+    {
+        this.childData.onVisualFootprintChanged(this.changeStart,
+                                                this.changeAmount);
+    }
+    
+    if ("needsReSort" in this) {
+        this.childData.reSort();
+        delete this.needsReSort;
+    }
+    
+    
+    delete this.changeStart;
+    delete this.changeAmount;
+}
+
+XULTreeView.prototype.saveBranchState =
+function xtv_savebranch (target, source, recurse)
+{
+    var len = source.length;
+    for (var i = 0; i < len; ++i)
+    {
+        if (source[i].isContainerOpen)
+        {
+            target[i] = new Object();
+            target[i].name = source[i]._colValues["col-0"];
+            if (recurse)
+                this.saveBranchState (target[i], source[i].childData, true);
+        }
+    }
+}
+
+XULTreeView.prototype.restoreBranchState =
+function xtv_restorebranch (target, source, recurse)
+{
+    for (var i in source)
+    {
+        if (typeof source[i] == "object")
+        {
+            var name = source[i].name;
+            var len = target.length;
+            for (var j = 0; j < len; ++j)
+            {
+                if (target[j]._colValues["col-0"] == name &&
+                    "childData" in target[j])
+                {
+                    //dd ("opening " + name);
+                    target[j].open();
+                    if (recurse)
+                    {
+                        this.restoreBranchState (target[j].childData,
+                                                 source[i], true);
+                    }
+                    break;
+                }
+            }
+        }
+    }
+}
+
+/* scroll the line specified by |line| to the center of the tree */
+XULTreeView.prototype.centerLine =
+function xtv_ctrln (line)
+{
+    var first = this.tree.getFirstVisibleRow();
+    var last = this.tree.getLastVisibleRow();
+    this.scrollToRow(line - (last - first + 1) / 2);
+}
+
+/*
+ * functions the tree will call to retrieve the list state (nsITreeView.)
+ */
+
+XULTreeView.prototype.__defineGetter__("rowCount", xtv_getRowCount);
+function xtv_getRowCount ()
+{
+    if (!this.childData)
+      return 0;
+
+    return this.childData.visualFootprint;
+}
+
+XULTreeView.prototype.isContainer =
+function xtv_isctr (index)
+{
+    var row = this.childData.locateChildByVisualRow (index);
+
+    return Boolean(row && ("alwaysHasChildren" in row || "childData" in row));
+}
+
+XULTreeView.prototype.__defineGetter__("selectedIndex", xtv_getsel);
+function xtv_getsel()
+{
+    if (!this.tree || this.tree.view.selection.getRangeCount() < 1)
+        return -1;
+
+    var min = new Object();
+    this.tree.view.selection.getRangeAt(0, min, {});
+    return min.value;
+}
+
+XULTreeView.prototype.__defineSetter__("selectedIndex", xtv_setsel);
+function xtv_setsel(i)
+{
+    this.tree.view.selection.clearSelection();
+    if (i != -1)
+        this.tree.view.selection.timedSelect (i, 500);
+    return i;
+}
+
+XULTreeView.prototype.scrollTo = BasicOView.prototype.scrollTo;
+
+XULTreeView.prototype.isContainerOpen =
+function xtv_isctropen (index)
+{
+    var row = this.childData.locateChildByVisualRow (index);
+    return row && row.isContainerOpen;
+}
+
+XULTreeView.prototype.toggleOpenState =
+function xtv_toggleopen (index)
+{
+    var row = this.childData.locateChildByVisualRow (index);
+    //ASSERT(row, "bogus row");
+    if (row)
+    {
+        if (row.isContainerOpen)
+            row.close();
+        else
+            row.open();
+    }
+}
+
+XULTreeView.prototype.isContainerEmpty =
+function xtv_isctrempt (index)
+{
+    var row = this.childData.locateChildByVisualRow (index);
+    if ("alwaysHasChildren" in row)
+        return false;
+
+    if (!row || !("childData" in row))
+        return true;
+
+    return !row.childData.length;
+}
+
+XULTreeView.prototype.isSeparator =
+function xtv_isseparator (index)
+{
+    return false;
+}
+
+XULTreeView.prototype.getParentIndex =
+function xtv_getpi (index)
+{
+    if (index < 0)
+        return -1;
+    
+    var row = this.childData.locateChildByVisualRow (index);
+    
+    var rv = row.parentRecord.calculateVisualRow();
+    //dd ("getParentIndex: row " + index + " returning " + rv);
+    return (rv != null) ? rv : -1;
+}
+
+XULTreeView.prototype.hasNextSibling =
+function xtv_hasnxtsib (rowIndex, afterIndex)
+{
+    var row = this.childData.locateChildByVisualRow (rowIndex);
+    return row.childIndex < row.parentRecord.childData.length - 1;
+}
+
+XULTreeView.prototype.getLevel =
+function xtv_getlvl (index)
+{
+    var row = this.childData.locateChildByVisualRow (index);
+    if (!row)
+        return 0;
+    
+    return row.level;
+}
+
+XULTreeView.prototype.getImageSrc =
+function xtv_getimgsrc (index, col)
+{
+}
+
+XULTreeView.prototype.getProgressMode =
+function xtv_getprgmode (index, col)
+{
+}
+
+XULTreeView.prototype.getCellValue =
+function xtv_getcellval (index, col)
+{
+}
+
+XULTreeView.prototype.getCellText =
+function xtv_getcelltxt (index, col)
+{
+    var row = this.childData.locateChildByVisualRow (index);
+    //ASSERT(row, "bogus row " + index);
+
+    if (typeof col == "object")
+        col = col.id;
+
+    var ary = col.match (/:(.*)/);
+    if (ary)
+        col = ary[1];
+
+    if (row && row._colValues && col in row._colValues)
+        return row._colValues[col];
+    else
+        return "";
+}
+
+XULTreeView.prototype.getCellProperties =
+function xtv_cellprops (row, col, properties)
+{
+    var row = this.childData.locateChildByVisualRow (row);
+
+    if (typeof col == "object")
+        col = col.id;
+
+    var ary = col.match (/:(.*)/);
+    if (ary)
+        col = ary[1];
+
+    if (row && row._colProperties && col in row._colProperties)
+        xtv_atomizeText(row._colProperties[col], properties);
+}
+
+XULTreeView.prototype.getColumnProperties =
+function xtv_colprops (col, properties)
+{}
+
+XULTreeView.prototype.getRowProperties =
+function xtv_rowprops (index, properties)
+{
+    var row = this.childData.locateChildByVisualRow (index);
+    
+    xtv_atomizeText(row.properties, properties);
+}
+
+XULTreeView.prototype.isSorted =
+function xtv_issorted (index)
+{
+    return false;
+}
+
+XULTreeView.prototype.canDrop =
+function xtv_drop (index, orientation)
+{
+    var row = this.childData.locateChildByVisualRow (index);
+    //ASSERT(row, "bogus row " + index);
+    return (row && ("canDrop" in row) && row.canDrop(orientation));
+}
+
+XULTreeView.prototype.drop =
+function xtv_drop (index, orientation)
+{
+    var row = this.childData.locateChildByVisualRow (index);
+    //ASSERT(row, "bogus row " + index);
+    return (row && ("drop" in row) && row.drop(orientation));
+}
+
+XULTreeView.prototype.setTree =
+function xtv_seto (tree)
+{
+    this.childData.invalidateCache();
+    this.tree = tree;
+}
+
+XULTreeView.prototype.cycleHeader =
+function xtv_cyclehdr (col)
+{
+}
+
+XULTreeView.prototype.selectionChanged =
+function xtv_selchg ()
+{
+}
+
+XULTreeView.prototype.cycleCell =
+function xtv_cyclecell (row, col)
+{
+}
+
+XULTreeView.prototype.isEditable =
+function xtv_isedit (row, col)
+{
+    return false;
+}
+
+XULTreeView.prototype.setCellValue =
+function xtv_setct (row, col, value)
+{
+}
+
+XULTreeView.prototype.setCellText =
+function xtv_setct (row, col, value)
+{
+}
+
+XULTreeView.prototype.performAction =
+function xtv_pact (action)
+{
+}
+
+XULTreeView.prototype.performActionOnRow =
+function xtv_pactrow (action)
+{
+}
+
+XULTreeView.prototype.performActionOnCell =
+function xtv_pactcell (action)
+{
+}
+
+XULTreeView.prototype.onRouteFocus =
+function xtv_rfocus (event)
+{
+    if ("onFocus" in this)
+        this.onFocus(event);
+}
+
+XULTreeView.prototype.onRouteBlur =
+function xtv_rblur (event)
+{
+    if ("onBlur" in this)
+        this.onBlur(event);
+}
+
+XULTreeView.prototype.onRouteDblClick =
+function xtv_rdblclick (event)
+{
+    if (!("onRowCommand" in this) || event.target.localName != "treechildren")
+        return;
+
+    var rowIndex = this.tree.view.selection.currentIndex;
+    if (rowIndex == -1 || rowIndex > this.rowCount)
+        return;
+    var rec = this.childData.locateChildByVisualRow(rowIndex);
+    if (!rec)
+    {
+        ASSERT (0, "bogus row index " + rowIndex);
+        return;
+    }
+
+    this.onRowCommand(rec, event);
+}
+
+XULTreeView.prototype.onRouteKeyPress =
+function xtv_rkeypress (event)
+{
+    var rec;
+    var rowIndex;
+    
+    if ("onRowCommand" in this && (event.keyCode == 13 || event.charCode == 32))
+    {
+        if (!this.selection)
+            return;
+        
+        rowIndex = this.tree.view.selection.currentIndex;
+        if (rowIndex == -1 || rowIndex > this.rowCount)
+            return;
+        rec = this.childData.locateChildByVisualRow(rowIndex);
+        if (!rec)
+        {
+            ASSERT (0, "bogus row index " + rowIndex);
+            return;
+        }
+
+        this.onRowCommand(rec, event);
+    }
+    else if ("onKeyPress" in this)
+    {
+        rowIndex = this.tree.view.selection.currentIndex;
+        if (rowIndex != -1 && rowIndex < this.rowCount)
+        {
+            rec = this.childData.locateChildByVisualRow(rowIndex);
+            if (!rec)
+            {
+                ASSERT (0, "bogus row index " + rowIndex);
+                return;
+            }
+        }
+        else
+        {
+            rec = null;
+        }
+        
+        this.onKeyPress(rec, event);
+    }
+}
+
+/******************************************************************************/
+
+function xtv_atomizeText (text, array)
+{
+  var atomservice = Components.classes["@mozilla.org/atom-service;1"]
+                              .getService(Components.interfaces.nsIAtomService);
+                              
+  var parts = text.split(" ");
+  for (var i = 0; i<parts.length; i++)
+  {
+    var atom = atomservice.getAtom(parts[i]);
+    array.AppendElement(atom);
+  }
+}
+
+function xtv_formatRecord (rec, indent)
+{
+    var str = "";
+    
+    for (var i in rec._colValues)
+            str += rec._colValues[i] + ", ";
+    
+    str += "[";
+    
+    str += rec.calculateVisualRow() + ", ";
+    str += rec.childIndex + ", ";
+    str += rec.level + ", ";
+    str += rec.visualFootprint + ", ";
+    str += rec.isHidden + "]";
+    
+    return (indent + str);
+}
+    
+function xtv_formatBranch (rec, indent, recurse)
+{
+    var str = "";
+    for (var i = 0; i < rec.childData.length; ++i)
+    {
+        str += xtv_formatRecord (rec.childData[i], indent) + "\n";
+        if (recurse)
+        {
+            if ("childData" in rec.childData[i])
+                str += xtv_formatBranch(rec.childData[i], indent + "  ",
+                                        --recurse);
+        }
+    }
+
+    return str;
+}
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/leaks/leaks.html	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,22 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<style>
+p {
+  font-family: monospace;
+  margin: 0;
+}
+
+.leaked {
+  color: red;
+}
+
+.ignored {
+  color: grey;
+}
+</style>
+<style id="filters">
+</style>
+</head>
+<body>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/leaks/leaks.js	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,585 @@
+var handlers = {
+  "DOMWINDOW": {
+    count: 0,
+    leaked: 0,
+    windows: {},
+    handle_line: function(addr,verb,rest,para) {
+      if (verb == "created") {
+        if (rest.substring(1,6)!="outer")
+          throw "outer expected";
+        var out = rest.substring(7);
+        this.windows[addr] = { outer: out, paras: [], uris: [] };
+        ++this.count;
+        ++this.leaked;
+        if (para)
+          this.windows[addr].paras.push(para);
+      } else if (verb == "destroyed") {
+        delete this.windows[addr];
+        --this.leaked;
+      } else if (verb == "SetNewDocument") {
+        var uri = rest.substring(1);
+        this.windows[addr].uris[uri] = true;
+        if (para)
+          this.windows[addr].paras.push(para);
+      }
+    },
+    mark_leaks: function(addr)
+    {
+      for (var i=0; i<this.windows[addr].paras.length; i++) {
+        this.windows[addr].paras[i].className+=" leaked";
+      }
+    },
+    clear: function()
+    {
+      this.count=0;
+      this.leaked=0;
+      this.windows={};
+    }
+  },
+  "DOCUMENT": {
+    count: 0,
+    leaked: 0,
+    docs: {},
+    handle_line: function(addr,verb,rest,para) {
+      if (verb == "created") {
+        this.docs[addr] = { paras: [], uris: [] };
+        ++this.count;
+        ++this.leaked;
+        if (para)
+          this.docs[addr].paras.push(para);
+      } else if (verb == "destroyed") {
+        delete this.docs[addr];
+        --this.leaked;
+      } else if (verb == "ResetToURI" ||
+                 verb == "StartDocumentLoad") {
+        var uri = rest.substring(1);
+        this.docs[addr].uris[uri] = true;
+        if (para)
+          this.docs[addr].paras.push(para);
+      }
+    },
+    mark_leaks: function(addr)
+    {
+      for (var i=0; i<this.docs[addr].paras.length; i++) {
+        var para = this.docs[addr].paras[i].className+=" leaked";
+      }
+    },
+    clear: function()
+    {
+      this.count=0;
+      this.leaked=0;
+      this.docs={};
+    }
+  },
+  "DOCSHELL": {
+    count: 0,
+    leaked: 0,
+    shells: {},
+    handle_line: function(addr,verb,rest,para) {
+      if (verb == "created") {
+        this.shells[addr] = { paras: [], uris: [] };
+        ++this.count;
+        ++this.leaked;
+        if (para)
+          this.shells[addr].paras.push(para);
+      } else if (verb == "destroyed") {
+        delete this.shells[addr];
+        --this.leaked;
+      } else if (verb == "InternalLoad" ||
+                 verb == "SetCurrentURI") {
+        var uri = rest.substring(1);
+        this.shells[addr].uris[uri] = true;
+        if (para)
+          this.shells[addr].paras.push(para);
+      }
+    },
+    mark_leaks: function(addr)
+    {
+      for (var i=0; i<this.shells[addr].paras.length; i++) {
+        var para = this.shells[addr].paras[i].className+=" leaked";
+      }
+    },
+    clear: function()
+    {
+      this.count=0;
+      this.leaked=0;
+      this.shells={};
+    }
+  },
+  clear: function()
+  {
+    this["DOMWINDOW"].clear();
+    this["DOCUMENT"].clear();
+    this["DOCSHELL"].clear();
+  }
+};
+
+function doParse(storelog)
+{
+  handlers.clear();
+  
+  var fulllog = document.getElementById("logframe").contentDocument.body;
+  var datelbl = document.getElementById("date");
+  var date = new Date(nsprlog.lastModifiedTime);
+  datelbl.value=bundle.getFormattedString("nightly.leaks.sessiondate.label", [date.toLocaleString()]);
+
+  var is = Components.classes["@mozilla.org/network/file-input-stream;1"]
+                     .createInstance(Components.interfaces.nsIFileInputStream);
+  const PR_RDONLY = 0x01;
+  is.init(nsprlog, PR_RDONLY, 0, 0);
+  if (!(is instanceof Components.interfaces.nsILineInputStream))
+    return;
+  var line = { value: "" };
+  var lines=0;
+  var para = null;
+  do
+  {
+    lines++;
+    var more = is.readLine(line); // yuck, returns false for last valid line
+
+    var className="";
+    if (storelog)
+    {
+      para = fulllog.ownerDocument.createElementNS("http://www.w3.org/1999/xhtml","p");
+      fulllog.appendChild(para);
+      para.appendChild(fulllog.ownerDocument.createTextNode(line.value));
+      className="logline";
+    }
+    
+    // strip off initial "-", thread id, and thread pointer; separate
+    // first word and rest
+    var matches = line.value.match(/^\-?[0-9]*\[[0-9a-f]*\]: (\S*) ([0-9a-f]*) (\S*)(.*)$/);
+    if (matches) {
+      var handler = matches[1];
+      var address = matches[2];
+      var verb = matches[3];
+      className+=" "+handler+" "+address;
+      var data = matches[4];
+      if (typeof(handlers[handler]) != "undefined") {
+        handlers[handler].handle_line(address,verb,data,para);
+      }
+      else
+      {
+        
+        className+=" ignored";
+      }
+    }
+    else
+    {
+      className+=" ignored";
+    }
+    if (storelog)
+      para.className=className;
+  } while (more);
+  
+  var details = document.getElementById("details");
+  var leaked=false;
+  
+  var lbl = document.getElementById("windowLeaks");
+  var handler = handlers["DOMWINDOW"];
+  lbl.value=bundle.getFormattedString("nightly.leaks.windowleaks.label", [handler.leaked, handler.count]);
+  if (handler.leaked>0)
+  {
+    lbl.className="leaked";
+    leaked=true;
+  }
+  else
+  {
+    lbl.className="";
+  }
+  for (var addr in handler.windows)
+  {
+    handler.mark_leaks(addr);
+    var winobj = handler.windows[addr];
+    lbl = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul","label");
+    details.appendChild(lbl);
+    if (winobj.outer=="0")
+    {
+      lbl.value=bundle.getFormattedString("nightly.leaks.innerleak.text", [addr, winobj.outer, addr]);
+    }
+    else
+    {
+      lbl.value=bundle.getFormattedString("nightly.leaks.outerleak.text", [addr, addr]);
+    }
+    for (var uri in winobj.uris)
+    {
+      lbl = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul","label");
+      details.appendChild(lbl);
+      lbl.value=bundle.getFormattedString("nightly.leaks.urileak.text", [uri]);
+      lbl.className="uri";
+    }
+  }
+
+  lbl = document.getElementById("documentLeaks");
+  handler = handlers["DOCUMENT"];
+  lbl.value=bundle.getFormattedString("nightly.leaks.documentleaks.label", [handler.leaked, handler.count]);
+  if (handler.leaked>0)
+  {
+    lbl.className="leaked";
+    leaked=true;
+  }
+  else
+  {
+    lbl.className="";
+  }
+  for (var addr in handler.docs)
+  {
+    handler.mark_leaks(addr);
+    var doc = handler.docs[addr];
+    lbl = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul","label");
+    details.appendChild(lbl);
+    lbl.value=bundle.getFormattedString("nightly.leaks.documentleak.text", [addr]);
+    for (var uri in doc.uris)
+    {
+      lbl = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul","label");
+      details.appendChild(lbl);
+      lbl.value=bundle.getFormattedString("nightly.leaks.urileak.text", [uri]);
+      lbl.className="uri";
+    }
+  }
+
+  lbl = document.getElementById("docshellLeaks");
+  handler = handlers["DOCSHELL"];
+  lbl.value=bundle.getFormattedString("nightly.leaks.docshellleaks.label", [handler.leaked, handler.count]);
+  if (handler.leaked>0)
+  {
+    lbl.className="leaked";
+    leaked=true;
+  }
+  else
+  {
+    lbl.className="";
+  }
+  for (var addr in handler.shells)
+  {
+    handler.mark_leaks(addr);
+    var doc = handler.shells[addr];
+    lbl = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul","label");
+    details.appendChild(lbl);
+    lbl.value=bundle.getFormattedString("nightly.leaks.docshellleak.text", [addr]);
+    for (var uri in doc.uris)
+    {
+      lbl = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul","label");
+      details.appendChild(lbl);
+      lbl.value=bundle.getFormattedString("nightly.leaks.urileak.text", [uri]);
+      lbl.className="uri";
+    }
+  }
+  
+  document.getElementById("detailsbox").collapsed=!leaked;
+}
+// --------------------------------------------------------------------
+
+var nsprlog = null;
+var preferences = null;
+
+var summaryText = "";
+var detailsText = "";
+var logValid = false;
+var bundle = null;
+
+function frameLoaded(event)
+{
+  var chk = document.getElementById("showlog");
+
+  var frame = document.getElementById("logframe");
+  if (frame.getAttribute("src")=="")
+    return;
+
+  changeFilter();
+  
+  var details = document.getElementById("details");
+  while (details.firstChild)
+  {
+    details.removeChild(details.firstChild);
+  }
+
+  doParse(chk.checked);
+  
+  logValid=chk.checked;
+  
+  document.getElementById("summary").collapsed=false;
+  document.getElementById("btnSave").disabled=false;
+  document.getElementById("btnCopy").disabled=false;
+  document.getElementById("nsprlog").disabled=false;
+  document.getElementById("filebrowse").disabled=false;
+  document.getElementById("showlog").disabled=false;
+  document.getElementById("tabbox").collapsed=false;
+}
+
+function parseLog()
+{
+  document.getElementById("nsprlog").disabled=true;
+  document.getElementById("filebrowse").disabled=true;
+  document.getElementById("showlog").disabled=false;
+  document.getElementById("tabbox").collapsed=true;
+  var frame = document.getElementById("logframe");
+  frame.setAttribute("src", "")
+  window.setTimeout(function() { frame.setAttribute("src", "leaks.html") }, 100);
+}
+
+function init(event)
+{
+  window.removeEventListener("load", init, false);
+  
+  bundle = document.getElementById("bundle");
+  
+  var prefservice = Components.classes['@mozilla.org/preferences-service;1']
+              .getService(Components.interfaces.nsIPrefService);
+  preferences = prefservice.getBranch("nightly.leaks.");
+  
+  var buildid = document.getElementById("buildid");
+  var appinfo = Components.classes['@mozilla.org/xre/app-info;1'].getService(Components.interfaces.nsIXULAppInfo);
+  buildid.value=navigator.userAgent+" ID:"+appinfo.appBuildID;
+
+  var frame = document.getElementById("logframe");
+  frame.addEventListener("load", frameLoaded, true);
+
+  var chk = document.getElementById("showlog");
+  chk.checked = preferences.getBoolPref("showleaklog");
+  document.getElementById("tabbox").firstChild.style.display=(chk.checked ? null : 'none');
+  
+  chk = document.getElementById("filterDocshell");
+  chk.checked = preferences.getBoolPref("filterDocshell");
+
+  chk = document.getElementById("filterWindow");
+  chk.checked = preferences.getBoolPref("filterWindow");
+
+  chk = document.getElementById("filterDocument");
+  chk.checked = preferences.getBoolPref("filterDocument");
+    
+  chk = document.getElementById("filterLeaked");
+  chk.checked = preferences.getBoolPref("filterLeaked");
+    
+  chk = document.getElementById("filterCollected");
+  chk.checked = preferences.getBoolPref("filterCollected");
+    
+  chk = document.getElementById("filterIgnored");
+  chk.checked = preferences.getBoolPref("filterIgnored");
+
+  try
+  {
+    nsprlog = preferences.getComplexValue("nsprlog", Components.interfaces.nsILocalFile);
+  }
+  catch (e) { }
+
+  if (nsprlog && nsprlog.exists())
+  {
+    var logtext = document.getElementById("nsprlog");
+    logtext.value=nsprlog.path;
+    parseLog();
+  }
+}
+
+function flipLog()
+{
+  var chk = document.getElementById("showlog");
+  preferences.setBoolPref("showleaklog", chk.checked);
+  document.getElementById("tabbox").firstChild.style.display=(chk.checked ? null : 'none');
+  
+  if (!chk.checked)
+  {
+    document.getElementById("tabbox").selectedIndex=0;
+  }
+
+  if (chk.checked && !logValid && nsprlog && nsprlog.exists())
+  {
+    parseLog();
+  }
+}
+
+function changeFilter()
+{
+  var style = document.getElementById("logframe").contentDocument.getElementById("filters");
+  var filter = "";
+
+  var chk = document.getElementById("filterDocshell");
+  if (!chk.checked)
+    filter+=".logline.DOCSHELL { display: none }\n";
+  preferences.setBoolPref("filterDocshell", chk.checked);
+
+  chk = document.getElementById("filterWindow");
+  if (!chk.checked)
+    filter+=".logline.DOMWINDOW { display: none }\n";
+  preferences.setBoolPref("filterWindow", chk.checked);
+
+  chk = document.getElementById("filterDocument");
+  if (!chk.checked)
+    filter+=".logline.DOCUMENT { display: none }\n";
+  preferences.setBoolPref("filterDocument", chk.checked);
+    
+  chk = document.getElementById("filterLeaked");
+  if (!chk.checked)
+    filter+=".leaked { display: none }\n";
+  preferences.setBoolPref("filterLeaked", chk.checked);
+    
+  chk = document.getElementById("filterCollected");
+  if (!chk.checked)
+    filter+=".logline:not(.leaked) { display: none }\n";
+  preferences.setBoolPref("filterCollected", chk.checked);
+    
+  chk = document.getElementById("filterIgnored");
+  if (!chk.checked)
+    filter+=".logline.ignored { display: none }\n";
+  preferences.setBoolPref("filterIgnored", chk.checked);
+  
+  style.innerHTML=filter;
+}
+
+function pad(value)
+{
+  if (value<10)
+    return "0"+value;
+  return ""+value;
+}
+
+function getTextOverview()
+{
+  var text=bundle.getString("nightly.leaks.summary.label")+nightlyplatform.eol+nightlyplatform.eol;
+  var appinfo = Components.classes['@mozilla.org/xre/app-info;1'].getService(Components.interfaces.nsIXULAppInfo);
+  text+=navigator.userAgent+" ID:"+appinfo.appBuildID+nightlyplatform.eol+nightlyplatform.eol;
+  var date = new Date(nsprlog.lastModifiedTime);
+  text+=bundle.getFormattedString("nightly.leaks.sessiondate.label", [date.toLocaleString()])+nightlyplatform.eol+nightlyplatform.eol;
+  
+  var leaked = false;
+  var handler = handlers["DOMWINDOW"];
+  if (handler.leaked>0)
+    leaked=true;
+  text+=bundle.getFormattedString("nightly.leaks.windowleaks.label", [handler.leaked, handler.count])+nightlyplatform.eol;
+  handler = handlers["DOCUMENT"];
+  if (handler.leaked>0)
+    leaked=true;
+  text+=bundle.getFormattedString("nightly.leaks.documentleaks.label", [handler.leaked, handler.count])+nightlyplatform.eol;
+  handler = handlers["DOCSHELL"];
+  if (handler.leaked>0)
+    leaked=true;
+  text+=bundle.getFormattedString("nightly.leaks.docshellleaks.label", [handler.leaked, handler.count])+nightlyplatform.eol;
+  
+  if (leaked)
+  {
+    text+=nightlyplatform.eol+bundle.getString("nightly.leaks.details.label")+nightlyplatform.eol+nightlyplatform.eol;
+    handler = handlers["DOMWINDOW"];
+    for (var addr in handler.windows)
+    {
+      var winobj = handler.windows[addr];
+      if (winobj.outer=="0")
+      {
+        text+=bundle.getFormattedString("nightly.leaks.innerleak.text", [addr, winobj.outer, addr])+nightlyplatform.eol;
+      }
+      else
+      {
+        text+=bundle.getFormattedString("nightly.leaks.outerleak.text", [addr, addr])+nightlyplatform.eol;
+      }
+      for (var uri in winobj.uris)
+      {
+        text+=" ... "+bundle.getFormattedString("nightly.leaks.urileak.text", [uri])+nightlyplatform.eol;
+      }
+    }
+
+    handler = handlers["DOCUMENT"];
+    for (var addr in handler.docs)
+    {
+      var doc = handler.docs[addr];
+      text += bundle.getFormattedString("nightly.leaks.documentleak.text", [addr])+nightlyplatform.eol;
+      for (var uri in doc.uris)
+      {
+        text+=" ... "+bundle.getFormattedString("nightly.leaks.urileak.text", [uri])+nightlyplatform.eol;
+      }
+    }
+
+    handler = handlers["DOCSHELL"];
+    for (var addr in handler.shells)
+    {
+      var doc = handler.shells[addr];
+      text += bundle.getFormattedString("nightly.leaks.docshellleak.text", [addr])+nightlyplatform.eol;
+      for (var uri in doc.uris)
+      {
+        text+=" ... "+bundle.getFormattedString("nightly.leaks.urileak.text", [uri])+nightlyplatform.eol;
+      }
+    }
+  }
+  return text;
+}
+
+function save()
+{
+  var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(Components.interfaces.nsIFilePicker);
+  fp.init(window, bundle.getString("nightly.leaks.filepicker.title"), fp.modeSave);
+  fp.appendFilter(bundle.getString("nightly.leaks.filepicker.filterlog"), "*.log");
+  fp.appendFilter(bundle.getString("nightly.leaks.filepicker.filterall"), "*.*");
+  fp.displayDirectory=nsprlog.parent;
+
+  var date = new Date(nsprlog.lastModifiedTime);
+  fp.defaultString=date.getFullYear()+pad(date.getMonth()+1)+pad(date.getDate())+"-"+pad(date.getHours())+pad(date.getMinutes())+"_leaklog.log";
+
+  var result = fp.show();
+  if (result==fp.returnOK || result==fp.returnReplace)
+  {
+    var target=fp.file;
+    preferences.setComplexValue("leaksave", Components.interfaces.nsILocalFile, target);
+
+    var text = getTextOverview();
+    
+    // file is nsIFile, data is a string
+    var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
+                             .createInstance(Components.interfaces.nsIFileOutputStream);
+    
+    // use 0x02 | 0x10 to open file for appending.
+    foStream.init(target, 0x02 | 0x08 | 0x20, 0664, 0); // write, create, truncate
+    var os = Components.classes["@mozilla.org/intl/converter-output-stream;1"]
+                       .createInstance(Components.interfaces.nsIConverterOutputStream);
+
+    os.init(foStream, "UTF-8", 0, 0x0000);
+    os.writeString(text);
+    os.close();
+    foStream.close();
+  }
+}
+
+function clipboardCopy()
+{
+  var clipboard = Components.classes["@mozilla.org/widget/clipboardhelper;1"].
+                                         getService(Components.interfaces.nsIClipboardHelper);
+  clipboard.copyString(getTextOverview());
+}
+
+function textEnter()
+{
+  var logtext = document.getElementById("nsprlog");
+  var target = Components.classes["@mozilla.org/file/local;1"]
+                         .createInstance(Components.interfaces.nsILocalFile);
+  target.initWithPath(logtext.value);
+  if (target.exists())
+  {
+    nsprlog=target;
+    preferences.setComplexValue("nsprlog", Components.interfaces.nsILocalFile, nsprlog);
+    parseLog();
+  }
+  else
+  {
+    var prompt = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
+                           .getService(Components.interfaces.nsIPromptService);
+    prompt.alert(window, "File Not Found", logtext.value+" does not exist.");
+  }
+}
+
+function selectLog()
+{
+  var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(Components.interfaces.nsIFilePicker);
+  fp.init(window, bundle.getString("nightly.leaks.filepicker.title"), fp.modeOpen);
+  fp.appendFilter(bundle.getString("nightly.leaks.filepicker.filterlog"), "*.log");
+  fp.appendFilter(bundle.getString("nightly.leaks.filepicker.filterall"), "*.*");
+  if (nsprlog)
+    fp.displayDirectory=nsprlog.parent;
+    
+  if (fp.show() == fp.returnOK)
+  {
+    nsprlog=fp.file;
+    preferences.setComplexValue("nsprlog", Components.interfaces.nsILocalFile, nsprlog);
+    var logtext = document.getElementById("nsprlog");
+    logtext.value=nsprlog.path;
+    parseLog();
+  }
+}
+
+window.addEventListener("load", init, false);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/leaks/leaks.xul	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,89 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE window SYSTEM "chrome://nightly/locale/leaks.dtd">
+
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+<?xml-stylesheet href="chrome://nightly/skin/leaks/leaks.css" type="text/css"?>
+
+<window id="LeakReporter" type="Nightly:LeakReporter"
+            title="&nightly.leaks.title;" style="padding: 10px; width: 80em; height: 60em"
+            persist="width height screenX screenY"
+            xmlns:xhtml="http://www.w3.org/1999/xhtml"
+            xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<xhtml:style>
+.leaked {
+  color: red;
+}
+
+.uri {
+  padding-left: 2em;
+}
+</xhtml:style>
+
+  <script type="application/x-javascript" src="leaks.js"/>
+  <script type="application/x-javascript" src="chrome://nightly/content/platform.js" />
+  
+  <stringbundleset>
+    <stringbundle id="bundle" src="chrome://nightly/locale/leaks.properties"/>
+  </stringbundleset>
+  
+  <vbox style="padding-bottom: 1em">
+    <hbox align="center">
+      <label value="&nightly.leaks.logfile.label;"/>
+      <textbox id="nsprlog" onchange="textEnter()" flex="1"/>
+      <button id="filebrowse" oncommand="selectLog()" label="&nightly.leaks.browse.label;"/>
+    </hbox>
+    
+    <checkbox id="showlog" oncommand="flipLog()" label="&nightly.leaks.displayfull.label;"/>
+  </vbox>
+
+  <stack flex="1">
+    <vbox align="center" pack="center">
+      <label style="font-size: 200%;" value="&nightly.leaks.loading.label;"/>
+    </vbox>
+    <tabbox id="tabbox" flex="1">
+      <tabs>
+        <tab label="&nightly.leaks.overview.label;"/>
+        <tab label="&nightly.leaks.fulllog.label;"/>
+      </tabs>
+      <tabpanels flex="1">
+        <tabpanel orient="vertical">
+          <hbox pack="start">
+            <button id="btnCopy" disabled="true" oncommand="clipboardCopy()" label="&nightly.leaks.copy.label;"/>
+            <button id="btnSave" disabled="true" oncommand="save()" label="&nightly.leaks.save.label;"/>
+          </hbox>
+          <vbox id="summary" collapsed="true">
+            <label style="font-size: 200%;" value="&nightly.leaks.summary.label;"/>
+            <separator/>
+            <label id="buildid"/>
+            <hbox><label id="date"/></hbox>
+            <separator/>
+            <label id="windowLeaks"/>
+            <label id="documentLeaks"/>
+            <label id="docshellLeaks"/>
+          </vbox>
+          <separator/>
+          <vbox id="detailsbox" flex="1" collapsed="true">
+            <label style="font-size: 200%;" value="&nightly.leaks.details.label;"/>
+            <separator/>
+            <vbox flex="1" id="details" style="overflow: auto"/>
+          </vbox>
+        </tabpanel>
+        <tabpanel orient="vertical">
+          <hbox pack="start" align="center">
+            <label value="&nightly.leaks.display.label;"/>
+            <checkbox checked="true" oncommand="changeFilter()" id="filterDocshell" label="&nightly.leaks.docshellfilter.label;"/>
+            <checkbox checked="true" oncommand="changeFilter()" id="filterWindow" label="&nightly.leaks.windowfilter.label;"/>
+            <checkbox checked="true" oncommand="changeFilter()" id="filterDocument" label="&nightly.leaks.documentfilter.label;"/>
+            <checkbox checked="true" oncommand="changeFilter()" id="filterLeaked" label="&nightly.leaks.leakedfilter.label;"/>
+            <checkbox checked="true" oncommand="changeFilter()" id="filterCollected" label="&nightly.leaks.collectedfilter.label;"/>
+            <checkbox checked="true" oncommand="changeFilter()" id="filterIgnored" label="&nightly.leaks.unknownfilter.label;"/>
+          </hbox>
+          <iframe id="logframe" style="border: 1px solid threedshadow" flex="1"/>
+        </tabpanel>
+      </tabpanels>
+    </tabbox>
+  </stack>
+
+</window>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/messenger.js	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,98 @@
+var nightlyApp = {
+
+savedSetTitleFromFolder: window.setTitleFromFolder,
+customTitle: '',
+
+init: function()
+{
+  var brandbundle = document.getElementById("bundle_brand");
+  if (nightly.variables.name==null)
+  {
+    nightly.variables.name=brandbundle.getString("brandShortName");
+  }
+  nightly.variables.defaulttitle=brandbundle.getString("brandShortName");
+  nightly.variables.brandname=brandbundle.getString("brandFullName");
+},
+
+openURL: function(url, event)
+{
+  var uri = Components.classes["@mozilla.org/network/io-service;1"]
+                      .getService(Components.interfaces.nsIIOService)
+                      .newURI(url, null, null);
+
+  var protocolSvc = Components.classes["@mozilla.org/uriloader/external-protocol-service;1"]
+                              .getService(Components.interfaces.nsIExternalProtocolService);
+  protocolSvc.loadUrl(uri);
+},
+
+detectLeaks: function(event)
+{
+  var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
+                     .getService(Components.interfaces.nsIWindowMediator);
+  var win = wm.getMostRecentWindow("Nightly:LeakReporter");
+  if (win)
+    win.focus();
+  else
+    window.openDialog("chrome://nightly/content/leaks/leaks.xul", "_blank", "chrome,all,dialog=no");
+},
+
+customSetTitleFromFolder: function(msgfolder, subject)
+{
+  var brandbundle = document.getElementById("bundle_brand");
+  var end = " - "+brandbundle.getString("brandShortName");
+  nightlyApp.savedSetTitleFromFolder(msgfolder,subject);
+
+  var title;
+  if ((document.title)&&(document.title.length>0))
+  {
+    title = document.title;
+  }
+  else
+  {
+    title = window.title;
+  }
+
+  if (title.substring(title.length-end.length)==end)
+  {
+    title=title.substring(0,title.length-end.length);
+    if (nightlyApp.customTitle && nightlyApp.customTitle.length>0)
+      title=title+' - '+nightlyApp.customTitle;
+  }
+
+  if ((document.title)&&(document.title.length>0))
+  {
+    document.title=title;
+  }
+  else
+  {
+    window.title=title;
+  }
+},
+
+updateTitle: function()
+{
+  if (gDBView)
+    window.setTitleFromFolder(gDBView.msgFolder,null);
+},
+
+setCustomTitle: function(title)
+{
+  nightlyApp.customTitle=title;
+  window.setTitleFromFolder=nightlyApp.customSetTitleFromFolder;
+  nightlyApp.updateTitle();
+},
+
+setBlankTitle: function()
+{
+  nightlyApp.customTitle='';
+  window.setTitleFromFolder=nightlyApp.customSetTitleFromFolder;
+  nightlyApp.updateTitle();
+},
+
+setStandardTitle: function()
+{
+  window.setTitleFromFolder=nightlyApp.savedSetTitleFromFolder;
+  nightlyApp.updateTitle();
+}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/messengerOverlay.xul	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,58 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE window [
+<!ENTITY % nightlyDTD SYSTEM "chrome://nightly/locale/nightly.dtd">
+%nightlyDTD;
+<!ENTITY % leaksDTD SYSTEM "chrome://nightly/locale/leaks.dtd">
+%leaksDTD;
+]>
+
+<overlay id="NightlyMessengerOverlay"
+         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+       
+  <script type="application/x-javascript" src="nightly.js" />
+  <script type="application/x-javascript" src="messenger.js" />
+  <script type="application/x-javascript" src="breakpad/breakpad.js" />
+  <script type="application/x-javascript" src="chrome://nightly/content/platform.js" />
+
+  <toolbarpalette id="MailToolbarPalette">
+    <toolbarbutton id="nightly-tester-enter"
+            class="toolbarbutton-1"
+            label="&nightly.id.insert.label;"
+            tooltiptext="&nightly.id.insert.tooltip;"
+            oncommand="nightly.insertTemplate('buildid');"/>
+  </toolbarpalette>
+
+  <popupset id="mainPopupSet">
+    <tooltip orient="vertical" id="nightly-crashreport-tooltip" onpopupshowing="return crashreports.popupTooltip(event)">
+      <label/>
+    </tooltip>
+    <popup id="nightly-crashreport-context">
+      <menuitem oncommand="crashreports.copy(event)" label="&nightly.crashreports.copyid;"/>
+    </popup>
+  </popupset>
+  
+  <menupopup id="taskPopup">
+    <menu id="nightly-menu" label="Nightly Tester Tools" insertafter="devToolsSeparator">
+      <menupopup onpopupshowing="nightly.menuPopup(event,this);">
+        <menuitem id="build-copy" label="&nightly.id.copy.label;" oncommand="nightly.copyTemplate('buildid');"/>
+        <menuitem id="build-insert" label="&nightly.id.insert.label;" oncommand="nightly.insertTemplate('buildid');"/>
+        <menuitem id="list-copy" label="&nightly.extensions.copy.label;" oncommand="nightly.copyExtensions();"/>
+        <menuitem id="list-insert" label="&nightly.extensions.insert.label;" oncommand="nightly.insertExtensions();"/>
+        <menuseparator/>
+        <menuitem label="&nightly.openprofile.label;" oncommand="nightly.openProfileDir();"/>
+        <menuseparator id="nightly-crashreports-separator"/>
+        <menu id="nightly-crashreports-recent" label="&nightly.crashreports.recentlist;" oncommand="crashreports.viewIncident(event);" onclick="checkForMiddleClick(this, event);">
+          <menupopup id="nightly-crashreports-incidents">
+            <menuitem disabled="true" label="&nightly.leaks.loading.label;"/>
+          </menupopup>
+        </menu>
+        <menuseparator/>
+        <menuitem label="&nightly.leakreporter.label;" oncommand="nightlyApp.detectLeaks(event);"/>
+        <menuseparator/>
+        <menuitem label="&nightly.options.label;" oncommand="nightly.launchOptions();"/>
+      </menupopup>
+    </menu>
+  </menupopup>
+  
+</overlay>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/nightly.js	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,369 @@
+var nightly = {
+
+variables: {
+  _appInfo: null,
+  get appInfo() {
+    if (!this._appInfo) {
+      this._appInfo = Components.classes["@mozilla.org/xre/app-info;1"]
+                                .getService(Components.interfaces.nsIXULAppInfo)
+                                .QueryInterface(Components.interfaces.nsIXULRuntime);
+    }
+    return this._appInfo;
+  },
+
+  get appid() this.appInfo.ID,
+  get vendor() this.appInfo.vendor,
+  get name() this.appInfo.name,
+  get version() this.appInfo.version,
+  get appbuildid() this.appInfo.appBuildID,
+  get platformbuildid() this.appInfo.platformBuildID,
+  get platformversion() this.appInfo.platformVersion,
+  get geckobuildid() this.appInfo.platformBuildID,
+  get geckoversion() this.appInfo.platformVersion,
+  brandname: null,
+  get useragent() navigator.userAgent,
+  get locale() {
+    var registry = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
+                             .getService(Components.interfaces.nsIXULChromeRegistry);
+    return registry.getSelectedLocale("global");
+  },
+  get os() this.appInfo.OS,
+  get processor() this.appInfo.XPCOMABI.split("-")[0],
+  get compiler() this.appInfo.XPCOMABI.split("-")[1],
+  defaulttitle: null,
+  profile: null,
+  toolkit: "cairo",
+  flags: ""
+},
+
+templates: {
+},
+
+preferences: null,
+
+showAlert: function(id, args) {
+   var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"]
+                      .getService(Components.interfaces.nsIStringBundleService);
+  var bundle = sbs.createBundle("chrome://nightly/locale/nightly.properties");
+  var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
+                                .getService(Components.interfaces.nsIPromptService);
+  var text=bundle.formatStringFromName(id, args, args.length);
+  promptService.alert(null, "Nightly Tester Tools", text);
+},
+
+init: function() {
+  window.removeEventListener("load", nightly.init, false);
+  var prefs = Components.classes["@mozilla.org/preferences-service;1"]
+                        .getService(Components.interfaces.nsIPrefService);
+  nightly.preferences = prefs.getBranch("nightly.")
+                             .QueryInterface(Components.interfaces.nsIPrefBranchInternal);
+  nightly.preferences.addObserver("", nightly, false);
+
+  var profd = Components.classes["@mozilla.org/file/directory_service;1"]
+                        .getService(Components.interfaces.nsIProperties)
+                        .get("ProfD", Components.interfaces.nsILocalFile);
+  var profservice = Components.classes["@mozilla.org/toolkit/profile-service;1"]
+                              .getService(Components.interfaces.nsIToolkitProfileService);
+  var profiles = profservice.profiles;
+  while (profiles.hasMoreElements()) {
+    var profile = profiles.getNext().QueryInterface(Components.interfaces.nsIToolkitProfile);
+    if (profile.rootDir.path == profd.path) {
+      nightly.variables.profile = profile.name;
+      break;
+    }
+  }
+
+  if (!nightly.variables.profile)
+    nightly.variables.profile = profd.leafName;
+
+  nightlyApp.init();
+  nightly.prefChange("idtitle");
+
+  var lastVersion = 0;
+  try {
+    lastVersion = nightly.preferences.getCharPref("lastVersion");
+    if (lastVersion != "2.0.2") {
+    }
+  }
+  catch (e) {
+    var checkCompatibility = true;
+    var checkUpdateSecurity = true;
+    if (prefs.prefHasUserValue("extensions.checkCompatibility"))
+      checkCompatibility = prefs.getBoolPref("extensions.checkCompatibility");
+    if (prefs.prefHasUserValue("extensions.checkUpdateSecurity"))
+      checkUpdateSecurity = prefs.getBoolPref("extensions.checkUpdateSecurity");
+    if (!checkCompatibility || !checkUpdateSecurity) {
+      var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
+                         .getService(Components.interfaces.nsIWindowMediator);
+      var win = wm.getMostRecentWindow("NightlyTester:ConfigWarning");
+      if (win) {
+        win.focus();
+        return;
+      }
+    
+      window.openDialog("chrome://nightly/content/configwarning.xul", "",
+                        "dialog=no,titlebar,centerscreen,resizable=no");
+    }
+  }
+  nightly.preferences.setCharPref("lastVersion", "2.0.2");
+},
+
+unload: function(pref) {
+  window.removeEventListener("unload",nightly.unload,false);
+  nightly.preferences.removeObserver("",nightly);
+},
+
+prefChange: function(pref) {
+  if ((pref == "idtitle") || (pref == "templates.title")) {
+    if (nightly.preferences.getBoolPref("idtitle")) {
+      var title = nightly.getTemplate("title");
+      if (title && title.length>0)
+        nightlyApp.setCustomTitle(nightly.generateText(title));
+      else
+        nightlyApp.setBlankTitle();
+    }
+    else {
+      nightlyApp.setStandardTitle();
+    }
+  }
+},
+
+observe: function(prefBranch, subject, pref) {
+  nightly.prefChange(pref);
+},
+
+getStoredItem: function(type, name) {
+  name = name.toLowerCase();
+  var varvalue = null;
+  try {
+    return nightly.preferences.getCharPref(type+"."+name);
+  }
+  catch (e) {}
+  return nightly[type][name];
+},
+
+getVariable: function(name) {
+  return nightly.getStoredItem("variables",name);
+},
+
+getTemplate: function(name) {
+  return nightly.getStoredItem("templates",name);
+},
+
+generateText: function(template) {
+  var start = 0;
+  var pos = template.indexOf("${",start);
+  while (pos >= 0) {
+    if ((pos == 0) || (template.charAt(pos - 1) != "$")) {
+      var endpos = template.indexOf("}", pos + 2);
+      if (endpos >= 0) {
+        var varname = template.substring(pos+2,endpos);
+        var varvalue = nightly.getVariable(varname);
+        if (varvalue !== null) {
+          template = template.substring(0, pos) + varvalue +
+                     template.substring(endpos + 1, template.length);
+          start = pos + varvalue.length;
+        }
+        else {
+          start = pos + 2;
+        }
+      }
+      else {
+        start = pos + 2;
+      }
+    }
+    else {
+      start = pos + 2;
+    }
+    pos = template.indexOf("${", start);
+  }
+  return template;
+},
+
+copyText: function(text) {
+  var clipboard = Components.classes["@mozilla.org/widget/clipboardhelper;1"].
+                                         getService(Components.interfaces.nsIClipboardHelper);
+  clipboard.copyString(text);
+},
+
+copyTemplate: function(template) {
+  nightly.copyText(nightly.generateText(nightly.getTemplate(template)));
+},
+
+menuPopup: function(event, menupopup) {
+  if (menupopup == event.target) {
+    var attext = false;
+    
+    var element = document.commandDispatcher.focusedElement;
+    if (element) {
+      var type = element.localName.toLowerCase();
+      attext = ((type == "input") || (type == "textarea"))
+    }
+      
+    var node=menupopup.firstChild;
+    while (node && node.localName!='menuseparator') {
+      if (node.id.substring(node.id.length - 7) == "-insert")
+        node.hidden = !attext;
+      if (node.id.substring(node.id.length - 5) == "-copy")
+        node.hidden = attext;
+      node=node.nextSibling;
+    }
+  }
+},
+
+insertTemplate: function(template) {
+  var element = document.commandDispatcher.focusedElement;
+  if (element) {
+    var type = element.localName.toLowerCase();
+    if ((type == "input") || (type == "textarea")) {
+      var text = nightly.generateText(nightly.getTemplate(template));
+      var newpos = element.selectionStart+text.length;
+      var value = element.value;
+      element.value = value.substring(0, element.selectionStart) + text +
+                      value.substring(element.selectionEnd);
+      element.selectionStart = newpos;
+      element.selectionEnd = newpos;
+      return;
+    }
+  }
+  nightly.showAlert("nightly.notextbox.message", []);
+},
+
+insensitiveSort: function(a, b) {
+  a = a.toLowerCase();
+  b = b.toLowerCase();
+  if (a < b)
+    return -1
+  if (a > b)
+    return 1
+  // a must be equal to b
+  return 0
+},
+
+getExtensionList: function() {
+  var em = Components.classes["@mozilla.org/extensions/manager;1"]
+                     .getService(Components.interfaces.nsIExtensionManager);
+                     
+  var items = em.getItemList(Components.interfaces.nsIUpdateItem.TYPE_EXTENSION, {});
+
+  if (items.length == 0) {
+    nightly.showAlert("nightly.noextensions.message", []);
+    return null;
+  }
+
+  var rdfS = Components.classes["@mozilla.org/rdf/rdf-service;1"]
+                       .getService(Components.interfaces.nsIRDFService);
+  var ds = em.datasource;
+  var disabledResource = rdfS.GetResource("http://www.mozilla.org/2004/em-rdf#disabled");
+  var isDisabledResource = rdfS.GetResource("http://www.mozilla.org/2004/em-rdf#isDisabled");
+  var text = [];
+  for (var i = 0; i < items.length; i++) {
+    text[i] = items[i].name + " " + items[i].version;
+    var source = rdfS.GetResource("urn:mozilla:item:" + items[i].id);
+    var disabled = ds.GetTarget(source, disabledResource, true);
+    if (!disabled)
+      disabled = ds.GetTarget(source, isDisabledResource, true);
+    try {
+      disabled=disabled.QueryInterface(Components.interfaces.nsIRDFLiteral);
+      if (disabled.Value=="true")
+        text[i]+=" [DISABLED]";
+    }
+    catch (e) { }
+  }
+  text.sort(nightly.insensitiveSort);
+  return text.join("\n");
+},
+
+insertExtensions: function() {
+  var element = document.commandDispatcher.focusedElement;
+  if (element) {
+    var type = element.localName.toLowerCase();
+    if ((type == "input") || (type == "textarea")) {
+      var text = nightly.getExtensionList();
+      var newpos = element.selectionStart + text.length;
+      var value = element.value;
+      element.value = value.substring(0, element.selectionStart) + text +
+                      value.substring(element.selectionEnd);
+      element.selectionStart = newpos;
+      element.selectionEnd = newpos;
+      return;
+    }
+  }
+  nightly.showAlert("nightly.notextbox.message",[]);
+},
+
+copyExtensions: function() {
+  var text = nightly.getExtensionList();
+  if (text)
+    nightly.copyText(text);
+},
+
+openProfileDir: function() {
+  var stream = Components.classes["@mozilla.org/network/file-input-stream;1"]
+                         .createInstance(Components.interfaces.nsIFileInputStream);
+  var directoryService = Components.classes["@mozilla.org/file/directory_service;1"]
+                                   .getService(Components.interfaces.nsIProperties);
+
+  var profile = directoryService.get("ProfD",Components.interfaces.nsILocalFile);
+  try {
+    profile.reveal();
+  }
+  catch (ex) {
+    var uri = Components.classes["@mozilla.org/network/io-service;1"]
+                        .getService(Components.interfaces.nsIIOService)
+                        .newFileURI(profile);
+    var protocolSvc = Components.classes["@mozilla.org/uriloader/external-protocol-service;1"]
+                                .getService(Components.interfaces.nsIExternalProtocolService);
+    protocolSvc.loadUrl(uri);
+  }
+},
+
+launch: function(file, args) {
+  var process = Components.classes["@mozilla.org/process/util;1"]
+                    .createInstance(Components.interfaces.nsIProcess);
+  process.init(file);
+  if (args)
+    process.run(false, args, args.length);
+  else
+    process.run(false, null, 0);
+},
+
+alertType: function(type) {
+  var directoryService = Components.classes["@mozilla.org/file/directory_service;1"]
+                           .getService(Components.interfaces.nsIProperties);
+
+  var dir = directoryService.get(type, Components.interfaces.nsIFile);
+  window.alert(dir.path);
+},
+
+getScreenshot: function() {
+  window.openDialog("chrome://nightly/content/screenshot/screenshot.xul", "_blank", "chrome,all,dialog=no");
+},
+
+launchOptions: function() {
+  var wm = Components.classes['@mozilla.org/appshell/window-mediator;1']
+                     .getService(Components.interfaces.nsIWindowMediator);
+
+  var win = wm.getMostRecentWindow("NightlyTester:Options");
+  if (win) {
+    win.focus();
+    return;
+  }
+
+  var features;
+  try {
+    var prefservice = Components.classes["@mozilla.org/preferences-service;1"]
+                                .getService(Components.interfaces.nsIPrefBranch);
+    var instantApply = prefservice.getBoolPref("browser.preferences.instantApply");
+    features = "chrome,titlebar,toolbar,centerscreen" + (instantApply ? ",dialog=no" : ",modal");
+  }
+  catch (e) {
+    features = "chrome,titlebar,toolbar,centerscreen,modal";
+  }
+  openDialog("chrome://nightly/content/options/options.xul", "", features);
+}
+
+}
+
+window.addEventListener("load", nightly.init, false);
+window.addEventListener("unload", nightly.unload, false);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/options/options.xul	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,51 @@
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
+<?xml-stylesheet href="chrome://nightly/skin/options/options.css" type="text/css"?>
+
+<!DOCTYPE window SYSTEM "chrome://nightly/locale/options.dtd">
+
+<prefwindow id="NightlyTesterOptions" windowtype="NightlyTester:Options"
+            title="&nightly.options.title;"
+            xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <script type="application/x-javascript" src="prefs.js"/>
+
+  <prefpane id="paneTitle" label="&nightly.options.title;">
+
+    <preferences>
+      <preference id="idtitle" type="bool" name="nightly.idtitle" onchange="paneTitle.toggled();"/>
+      <preference id="title" type="string" name="nightly.templates.title"/>
+    </preferences>
+
+    <script type="application/x-javascript" src="title.js"/>
+
+    <stringbundle id="variablesBundle" src="chrome://nightly/locale/variables.properties"/>
+
+    <description style="padding-bottom: 5px">&nightly.paneTitlebar.description;</description>
+
+    <checkbox preference="idtitle" style="padding-bottom: 5px" id="enableTitleBar" label="&nightly.customtitle.label;"/>
+
+    <hbox style="padding-bottom: 5px" align="center">
+      <label value="&nightly.customtemplate.label;" control="customTitle"/>
+      <textbox preference="title" id="customTitle" flex="1"/>
+    </hbox>
+
+    <description style="padding-bottom: 5px">&nightly.variables.description;</description>
+
+    <listbox id="varList" flex="1">
+      <listhead>
+        <listheader label="&nightly.variable.label;"/>
+        <listheader label="&nightly.variabledesc.label;"/>
+        <listheader label="&nightly.variablevalue.label;"/>
+      </listhead>
+      <listcols>
+        <listcol style="width: 9em"/>
+        <listcol flex="1"/>
+        <listcol style="width: 15em"/>
+      </listcols>
+    </listbox>
+
+  </prefpane>
+
+</prefwindow>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/options/prefs.js	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,22 @@
+var prefs = {
+
+nightly: null,
+
+init: function()
+{
+  var mediator = Components.classes['@mozilla.org/appshell/window-mediator;1']
+              .getService(Components.interfaces.nsIWindowMediator);
+              
+  var window = mediator.getMostRecentWindow("navigator:browser");
+  if (!window)
+    window=mediator.getMostRecentWindow("mail:3pane");
+  if (!window)
+    window=mediator.getMostRecentWindow("calendarMainWindow");
+  if (!window)
+    window=mediator.getMostRecentWindow("Songbird:Main");
+  if (window)
+    prefs.nightly=window.nightly;
+}
+}
+
+window.addEventListener("load",prefs.init,false);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/options/subpane.xml	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,107 @@
+<?xml version="1.0"?>
+
+<bindings id="SubPaneBindings" xmlns="http://www.mozilla.org/xbl" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <binding id="subpane" name="subpane">
+
+    <content preference-editable="true" orient="vertical">
+    </content>
+
+    <implementation>
+    
+      <property name="action">
+        <getter>
+          return this.getAttribute("action");
+        </getter>
+      </property>
+      
+      <property name="_attribute">
+        <getter>
+          if (this.action == "hide")
+          {
+            return "hidden";
+          }
+          else if (this.action == "disable")
+          {
+            return "disabled";
+          }
+          return "";
+        </getter>
+      </property>
+      
+      <property name="_invert">
+        <getter>
+        <![CDATA[
+          var invert = false;
+          
+          if (this.action == "hide")
+          {
+            invert=true;
+          }
+          else if (this.action == "disable")
+          {
+            invert=true;
+          }
+          
+          if (this.hasAttribute("invert") && this.getAttribute("invert") == "true")
+            invert=!invert;
+            
+          return invert;
+        ]]>
+        </getter>
+      </property>
+      
+      <field name="_value"/>
+      <property name="value">
+        <setter>
+          if (val == this._value)
+            return val;
+
+          this._value = val;
+          this._updateElements(val);
+          
+          return val;
+        </setter>
+        <getter>
+          return this._value;
+        </getter>
+      </property>
+      
+      <method name="_setElementState">
+        <parameter name="element"/>
+        <parameter name="state"/>
+        <body>
+          var attribute = this._attribute;
+          state = this._invert ? !state : state;
+
+          if (attribute in element) 
+            element[attribute] = state;
+          else
+            element.setAttribute(attribute, state);
+        </body>
+      </method>
+      
+      <method name="_updateElements">
+        <parameter name="state"/>
+        <body>
+          if (this.action=="hide")
+          {
+            this.hidden = this._invert ? !state : state;
+          }
+          else
+          {
+            var element = this.firstChild;
+            while (element)
+            {
+              this._setElementState(element,state);
+              element = element.nextSibling;
+            }
+          }
+        </body>
+      </method>
+      
+    </implementation>
+    
+  </binding>
+
+</bindings>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/options/title.js	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,62 @@
+var paneTitle = {
+
+bundle: null,
+
+init: function()
+{
+  paneTitle.toggled();
+
+  paneTitle.bundle=document.getElementById("variablesBundle");
+  
+  paneTitle.addVariable("DefaultTitle");
+  paneTitle.addVariable("AppID");
+  paneTitle.addVariable("Vendor");
+  paneTitle.addVariable("Name");
+  paneTitle.addVariable("Version");
+  paneTitle.addVariable("AppBuildID");
+  paneTitle.addVariable("PlatformBuildID");
+  paneTitle.addVariable("PlatformVersion");
+  paneTitle.addVariable("GeckoVersion");
+  paneTitle.addVariable("BrandName");
+  paneTitle.addVariable("UserAgent");
+  paneTitle.addVariable("Locale");
+  paneTitle.addVariable("OS");
+  paneTitle.addVariable("Processor");
+  paneTitle.addVariable("Compiler");
+  paneTitle.addVariable("Toolkit");
+  paneTitle.addVariable("Profile");
+},
+
+addVariable: function(name)
+{
+  var list = document.getElementById("varList");
+  var item = document.createElement("listitem");
+  item.appendChild(document.createElement("listcell")).setAttribute('label',"${"+name+"}");
+  var text = null;
+  try
+  {
+    var text = paneTitle.bundle.getString("variable."+name+".description");
+  } catch (e) { }
+  if (text==null)
+  {
+    text="";
+  }
+  item.appendChild(document.createElement("listcell")).setAttribute('label',text);
+  var value = prefs.nightly.getVariable(name);
+  if (value==null)
+  {
+    value="Undefined";
+  }
+  item.appendChild(document.createElement("listcell")).setAttribute('label',value);
+  list.appendChild(item);
+},
+
+toggled: function()
+{
+  var checkbox = document.getElementById("enableTitleBar");
+  var text = document.getElementById("customTitle");
+  text.disabled=!checkbox.checked;
+}
+}
+
+window.addEventListener("load",paneTitle.init,false);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/platform.js	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,4 @@
+var nightlyplatform = {
+  eol: "\n"
+}
+ 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/screenshot/providers.js	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,79 @@
+var Providers = {
+  _providers: [],
+  _selected: null,
+  
+  addProvider: function(provider)
+  {
+    this._providers.push(provider);
+    if (this._selected == null)
+      this._selected = provider;
+  },
+  
+  selectProvider: function(provider)
+  {
+    this._selected = provider;
+  },
+  
+  getSelectedProvider: function()
+  {
+    return this._selected;
+  },
+  
+  getProviders: function()
+  {
+    return this._providers;
+  }
+}
+
+var ImageShack = {
+  addFormFields: function(formdata)
+  {
+    formdata.addControl("uploadtype", "on");
+    formdata.addControl("url", "paste image url here");
+    formdata.addControl("MAX_FILE_SIZE", "3145728");
+    formdata.addControl("refer", "");
+    formdata.addControl("brand", "");
+    formdata.addControl("optsize", "320x320");
+  },
+  
+  getFileFormField: function()
+  {
+    return "fileupload";
+  },
+  
+  getReferer: function()
+  {
+    return "http://www.imageshack.us/";
+  },
+  
+  getSubmissionURL: function()
+  {
+    return "http://www.imageshack.us/";
+  }
+}
+
+var AllYouCanUpload = {
+  addFormFields: function(formdata)
+  {
+    formdata.addControl("images[0].submittedPhotoSize", "100%");
+    formdata.addControl("imagesCount", "1");
+  },
+  
+  getFileFormField: function()
+  {
+    return "images[0].fileName";
+  },
+  
+  getReferer: function()
+  {
+    return "http://allyoucanupload.webshots.com/";
+  },
+  
+  getSubmissionURL: function()
+  {
+    return "http://allyoucanupload.webshots.com/uploadcomplete";
+  }
+}
+
+Providers.addProvider(ImageShack);
+//Providers.addProvider(AllYouCanUpload);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/screenshot/screenshot.js	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,292 @@
+const Ci = Components.interfaces;
+const Cc = Components.classes;
+
+var shotWindow = window.opener;
+
+var timer = 0;
+
+var canvas = null;
+var bundle = null;
+
+var windows = [];
+
+function init(event)
+{
+  canvas = document.getElementById("canvas");
+  drawScreenshot();
+  //canvas.parentNode.addEventListener("mousedown", startAreaSelect, true);
+  
+  buildWinPopup()
+    
+  var winlist = document.getElementById("winlist");
+  winlist.addEventListener("ValueChange", winChange, false);
+  
+  var winpopup = document.getElementById("winpopup");
+  winpopup.addEventListener("popupshowing", buildWinPopup, false);
+  
+  bundle = document.getElementById("bundle");
+
+  try
+  {
+    var win = getTopWin();
+    var webnav = win.content.QueryInterface(Ci.nsIInterfaceRequestor)
+                            .getInterface(Ci.nsIWebNavigation);
+    if (webnav.loadURI)
+      document.getElementById("imgsubmit").hidden = false;
+  }
+  catch (e)
+  {
+  }
+}
+
+function getTopWin()
+{
+  var windowManager = Cc['@mozilla.org/appshell/window-mediator;1']
+                        .getService(Ci.nsIWindowMediator);
+  return windowManager.getMostRecentWindow("navigator:browser");
+}
+
+function timedCapture()
+{
+  if (timer==0)
+  {
+    timer = 5;
+    var button = document.getElementById("timerbtn");
+    button.checked = true;
+    window.setTimeout(captureTimer, 1000);
+  }
+}
+
+function captureTimer()
+{
+  var button = document.getElementById("timerbtn");
+  timer--;
+  if (timer==0)
+  {
+    drawScreenshot();
+    button.setAttribute("label", bundle.getFormattedString("screenshot.timer.label", [5]));
+    button.checked = false;
+  }
+  else
+  {
+    button.setAttribute("label", bundle.getFormattedString("screenshot.timer.label", [timer]));
+    window.setTimeout(captureTimer, 1000);
+  }
+}
+
+function submitScreenshot()
+{
+  var fileService = ImageShack;
+  
+  var data = canvas.toDataURL("image/png");
+  var pos = data.indexOf(";",5);
+  var contenttype = data.substring(5,pos);
+  var npos = data.indexOf(",",pos+1);
+  var encoding = data.substring(pos+1,npos);
+  data = data.substring(npos+1);
+  
+  var fd = Cc["@blueprintit.co.uk/multipartformdata;1"]
+             .createInstance(Ci.nttIMultipartFormData);
+  fileService.addFormFields(fd);
+  fd.addFileData(fileService.getFileFormField(), "screenshot.png", contenttype, encoding, data);
+  
+  var ioService = Cc["@mozilla.org/network/io-service;1"]
+                    .getService(Ci.nsIIOService);
+  
+  var referer = ioService.newURI(fileService.getReferer(), "UTF8", null);
+  
+  var win = getTopWin();
+  var webnav = win.content.QueryInterface(Ci.nsIInterfaceRequestor)
+                          .getInterface(Ci.nsIWebNavigation);
+  webnav.loadURI(fileService.getSubmissionURL(), Ci.nsIWebNavigation.LOAD_FLAGS_NONE
+                , referer, fd.getPostDataStream(), fd.getHeaderStream());
+}
+
+function saveScreenshot()
+{
+  var fp = Cc["@mozilla.org/filepicker;1"]
+             .createInstance(Ci.nsIFilePicker);
+  fp.init(window, bundle.getString("screenshot.filepicker.title"), fp.modeSave);
+  fp.appendFilter(bundle.getString("screenshot.filepicker.filterPNG"), "*.png");
+  fp.appendFilter(bundle.getString("screenshot.filepicker.filterJPG"), "*.jpg");
+  fp.filterIndex = 0;
+  fp.defaultString="screenshot";
+
+  var result = fp.show();
+  if (result==fp.returnOK || result==fp.returnReplace)
+  {
+    var file = fp.file;
+    var mimetype = "image/png";
+    var options = "";
+    var extension = "png";
+    if (fp.filterIndex == 1)
+    {
+      extension = "jpg";
+      mimetype = "image/jpeg";
+      options = "quality=80";
+    }
+
+    if (file.leafName.indexOf(".") < 0)
+      file.leafName += "." + extension;
+    
+    var ioService = Cc["@mozilla.org/network/io-service;1"]
+                      .getService(Ci.nsIIOService);
+    
+    var source = ioService.newURI(canvas.toDataURL(mimetype, options), "UTF8", null);
+    var target = ioService.newFileURI(file)
+    
+    var persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
+                    .createInstance(Ci.nsIWebBrowserPersist);
+  
+    persist.persistFlags = Ci.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
+    persist.persistFlags |= Ci.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
+  
+    var tr = Cc["@mozilla.org/transfer;1"]
+               .createInstance(Ci.nsITransfer);
+  
+    tr.init(source, target, "", null, null, null, persist);
+    persist.progressListener = tr;
+    persist.saveURI(source, null, null, null, null, file);
+  }
+}
+
+function copyScreenshot()
+{
+  var image = document.getElementById("previewImage");
+  var docshell = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                       .getInterface(Ci.nsIWebNavigation)
+                       .QueryInterface(Ci.nsIDocShell);
+  var edit = docshell.contentViewer.QueryInterface(Ci.nsIContentViewerEdit);
+  document.popupNode = image;
+  edit.copyImage(Ci.nsIContentViewerEdit.COPY_IMAGE_DATA);
+}
+
+function buildWinPopup(event)
+{
+  var winlist = document.getElementById("winlist");
+  var winpopup = document.getElementById("winpopup");
+  
+  windows = [];
+  while (winpopup.firstChild)
+    winpopup.removeChild(winpopup.firstChild);
+
+  var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
+            .getService(Ci.nsIWindowMediator);
+  var wins = wm.getEnumerator(null);
+  var pos = 0;
+  while (wins.hasMoreElements())
+  {
+    var win = wins.getNext().QueryInterface(Ci.nsIDOMWindow);
+    if (win != window)
+    {
+      windows[pos] = win;
+      var item = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "menuitem");
+      if (win.document.title)
+        item.setAttribute("label", win.document.title);
+      else
+        item.setAttribute("label", win.document.location.href);
+      item.setAttribute("value", pos);
+      winpopup.appendChild(item);
+      
+      if (!event && win==shotWindow)
+        winlist.value=pos;
+        
+      pos++;
+    }
+  }
+}
+
+function winChange(event)
+{
+  var winlist = document.getElementById("winlist");
+  shotWindow = windows[winlist.value];
+  drawScreenshot();
+}
+
+function drawScreenshot()
+{
+  var width = shotWindow.innerWidth;
+  var height = shotWindow.innerHeight;
+  canvas.width = width;
+  canvas.height = height;
+  canvas.style.width = width + "px";
+  canvas.style.minWidth = width + "px";
+  canvas.style.maxWidth = width + "px";
+  canvas.style.height = height + "px";
+  canvas.style.minHeight = height + "px";
+  canvas.style.maxHeight = height + "px";
+
+  var ctx = canvas.getContext("2d");
+  
+  var winbo = shotWindow.document.getBoxObjectFor(shotWindow.document.documentElement);
+  var winx = winbo.screenX;
+  var winy = winbo.screenY;
+
+  // This draws the main window
+  try
+  {
+    ctx.drawWindow(shotWindow, shotWindow.scrollX, shotWindow.scrollY,
+                               shotWindow.innerWidth, shotWindow.innerHeight,
+                               "rgba(255,255,255,255)");
+  }
+  catch (e)
+  {
+  }
+
+  // Must also draw inner windows as inner-content from chrome are not included
+  var docshell = shotWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                           .getInterface(Ci.nsIWebNavigation)
+                           .QueryInterface(Ci.nsIDocShell);
+  var shells = docshell.getDocShellEnumerator(Ci.nsIDocShellTreeItem.typeAll, Ci.nsIDocShell.ENUMERATE_FORWARDS);
+  while (shells.hasMoreElements())
+  {
+    var shell = shells.getNext().QueryInterface(Ci.nsIDocShell);
+    try
+    {
+      if (shell == docshell)
+        continue;
+  
+      shell.QueryInterface(Ci.nsIBaseWindow);
+      if (!shell.visibility)
+        continue;
+  
+      var shellwin = shell.QueryInterface(Ci.nsIInterfaceRequestor)
+                          .getInterface(Ci.nsIDOMWindow);
+      var shellbo = shellwin.document.getBoxObjectFor(shellwin.document.documentElement);
+      
+      ctx.save();
+      try
+      {
+        ctx.translate(shellbo.screenX - winx + shellwin.scrollX,
+                      shellbo.screenY - winy + shellwin.scrollY);
+        ctx.drawWindow(shellwin, shellwin.scrollX, shellwin.scrollY,
+                                 shellwin.innerWidth, shellwin.innerHeight,
+                                 "rgba(255,255,255,255)");
+      }
+      catch (e)
+      {
+      }
+      ctx.restore();
+    }
+    catch (e)
+    {
+    }
+  }
+
+  var url = canvas.toDataURL();
+  var oldImage = document.getElementById("previewImage");
+  if (oldImage)
+    oldImage.parentNode.removeChild(oldImage);
+
+  var image = document.createElementNS("http://www.w3.org/1999/xhtml", "img");
+  image.id = "previewImage";
+  document.getElementById("container").appendChild(image);
+
+  image.style.width = width + "px";
+  image.style.height = height + "px";
+  image.width = width;
+  image.height = height;
+  image.src = url;
+}
+
+window.addEventListener("load", init, false);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/screenshot/screenshot.xul	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE window SYSTEM "chrome://nightly/locale/screenshot.dtd">
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://nightly/skin/screenshot/screenshot.css" type="text/css"?>
+
+<window title="&screenshot.window.title;" id="NightlyScreenshot"
+        persist="width height screenX screenY sizemode"
+        xmlns:xhtml="http://www.w3.org/1999/xhtml"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <script src="screenshot.js" type="application/x-javascript"/>
+  <script src="providers.js" type="application/x-javascript"/>
+  
+  <stringbundleset>
+    <stringbundle id="bundle" src="chrome://nightly/locale/screenshot.properties"/>
+  </stringbundleset>
+  
+  <toolbox>
+    <toolbar>
+      <toolbarbutton label="&screenshot.save.label;" oncommand="saveScreenshot()"/>
+      <toolbarbutton label="&screenshot.copy.label;" oncommand="copyScreenshot()"/>
+      <toolbarbutton id="imgsubmit" hidden="true" label="&screenshot.submit.label;" oncommand="submitScreenshot(); window.close();"/>
+      <toolbaritem align="center">
+        <label control="winlist" value="&screenshot.window.label;"/>
+        <menulist id="winlist">
+          <menupopup id="winpopup">
+          </menupopup>
+        </menulist>
+      </toolbaritem>
+      <toolbarbutton label="&screenshot.redraw.label;" oncommand="drawScreenshot();"/>
+      <toolbarbutton id="timerbtn" label="&screenshot.timer.label;" oncommand="timedCapture();"/>
+    </toolbar>
+  </toolbox>
+  
+  <scrollbox flex="1" style="overflow: auto" align="start" pack="start" id="container">
+    <xhtml:img id="previewImage"/>
+  </scrollbox>
+
+  <vbox height="0" style="overflow: hidden">
+    <xhtml:canvas id="canvas" style="visibility: hidden"/>
+  </vbox>
+
+</window>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/session/dialog.js	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,77 @@
+const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+var gArgs = null;
+
+function acceptRestore()
+{
+  for (var w in gArgs.state.windows)
+  {
+    var win = gArgs.state.windows[w];
+    for (var t = win.tabs.length-1; t>=0; t--)
+    {
+      var tab = win.tabs[t];
+      if (tab._control.getAttribute("value") !== "true")
+      {
+        win.tabs.splice(t, 1);
+        if (t < win.selected)
+          win.selected--;
+      }
+      else
+        delete tab["_control"];
+    }
+  }
+  gArgs.result = true;
+}
+
+function addTab(parent, tab)
+{
+  var item = document.createElementNS(XULNS, "treeitem");
+  item.setAttribute("container", "false");
+  parent.appendChild(item);
+  var row = document.createElementNS(XULNS, "treerow");
+  item.appendChild(row);
+  var cell = document.createElementNS(XULNS, "treecell");
+  if (tab.entries[tab.index-1].title)
+    cell.setAttribute("label", tab.entries[tab.index-1].title);
+  else
+    cell.setAttribute("label", "(Untitled)");
+  cell.setAttribute("editable", "false");
+  row.appendChild(cell);
+  cell = document.createElementNS(XULNS, "treecell");
+  cell.setAttribute("value", "true");
+  row.appendChild(cell);
+  tab._control = cell;
+}
+
+function addWindow(parent, win)
+{
+  var item = document.createElementNS(XULNS, "treeitem");
+  item.setAttribute("container", "true");
+  item.setAttribute("open", "true");
+  parent.appendChild(item);
+  var row = document.createElementNS(XULNS, "treerow");
+  item.appendChild(row);
+  var cell = document.createElementNS(XULNS, "treecell");
+  cell.setAttribute("label", "Window");
+  cell.setAttribute("editable", "false");
+  row.appendChild(cell);
+  cell = document.createElementNS(XULNS, "treecell");
+  cell.setAttribute("editable", "false");
+  row.appendChild(cell);
+  var children = document.createElementNS(XULNS, "treechildren");
+  item.appendChild(children);
+  for (var i in win.tabs)
+    addTab(children, win.tabs[i]);
+}
+
+function loadState(event)
+{
+  gArgs = window.arguments[0];
+  var parent = document.getElementById("treechildren");
+  var windows = gArgs.state.windows;
+  for (var i in windows)
+    addWindow(parent, windows[i]);
+}
+
+window.addEventListener("load", loadState, false);
+ 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/session/session.js	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,78 @@
+var session = {
+
+init: function(event)
+{
+  var menu = document.getElementById("nightly-session-restore");
+  var ds = Components.classes["@mozilla.org/file/directory_service;1"]
+                     .getService(Components.interfaces.nsIProperties);
+  var file = ds.get("ProfD", Ci.nsIFile);
+  file.append("sessionstore.bak");
+  if (!file.exists)
+    menu.setAttribute("disabled", "true");
+},
+
+_readFile: function(file)
+{
+  try
+  {
+    var stream = Components.classes["@mozilla.org/network/file-input-stream;1"]
+                           .createInstance(Components.interfaces.nsIFileInputStream);
+    stream.init(file, 0x01, 0, 0);
+    var cvstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"]
+                             .createInstance(Components.interfaces.nsIConverterInputStream);
+    cvstream.init(stream, "UTF-8", 1024, Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
+    
+    var content = "";
+    var data = {};
+    while (cvstream.readString(4096, data))
+      content += data.value;
+    cvstream.close();
+    
+    return content.replace(/\r\n?/g, "\n");
+  }
+  catch (ex) { }
+  
+  return null;
+},
+
+restore: function()
+{
+  var ds = Components.classes["@mozilla.org/file/directory_service;1"]
+                     .getService(Components.interfaces.nsIProperties);
+  var file = ds.get("ProfD", Ci.nsIFile);
+  file.append("sessionstore.bak");
+  if (file.exists)
+  {
+    var data = this._readFile(file);
+    if (data)
+    {
+      try
+      {
+        var s = Components.utils.Sandbox("about:blank");
+        var state = Components.utils.evalInSandbox(data, s);
+        var args = {
+          state: state,
+          result: false
+        };
+        window.openDialog("chrome://nightly/content/session/session.xul", "_blank", "chrome,all,modal", args);
+        if (args.result)
+        {
+          var ss = Components.classes["@mozilla.org/browser/sessionstore;1"]
+                             .getService(Components.interfaces.nsISessionStore);
+          var win = OpenBrowserWindow();
+          win.addEventListener("load", function() { ss.setWindowState(win, args.state.toSource(), true); }, false);
+        }
+        return;
+      }
+      catch (ex)
+      {
+      }
+    }
+    alert("Unable to read from file, this is unrecoverable.");
+  }
+  else
+    alert("There is no session information to restore.");
+}
+}
+
+window.addEventListener("load", session.init, false);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/session/session.xul	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE window SYSTEM "chrome://nightly/locale/nightly.dtd">
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://nightly/skin/session/session.css" type="text/css"?>
+
+<dialog id="NightlySessionRestore" buttons="accept,cancel" style="width: 30em; height: 25em"
+        ondialogaccept="acceptRestore();" buttonlabelaccept="Restore"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <script type="application/x-javascript" src="dialog.js" />
+
+  <tree flex="1" hidecolumnpicker="true" editable="true">
+    <treecols>
+      <treecol id="name" label="Title" flex="1" editable="false" primary="true"/>
+      <treecol id="restore" label="Restore" type="checkbox" editable="true"/>
+    </treecols>
+    <treechildren id="treechildren">
+    </treechildren>
+  </tree>
+  
+</dialog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/songbird.js	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,55 @@
+var nightlyApp = {
+
+storedTitle: document.documentElement.getAttribute("titlemodifier"),
+
+init: function()
+{
+  // var brandbundle = document.getElementById("bundle_brand");
+  var bundleSvc = Components.classes["@mozilla.org/intl/stringbundle;1"]
+  					.getService(Components.interfaces.nsIStringBundleService);
+  var brandbundle = bundleSvc.
+  					createBundle("chrome://branding/locale/brand.properties");
+
+  if (nightly.variables.name==null)
+  {
+    nightly.variables.name=brandbundle.GetStringFromName("brandShortName");
+  }
+  nightly.variables.brandname=brandbundle.GetStringFromName("brandFullName");
+  nightly.variables.defaulttitle=nightlyApp.storedTitle;
+},
+
+detectLeaks: function(event)
+{
+  var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
+                     .getService(Components.interfaces.nsIWindowMediator);
+  var win = wm.getMostRecentWindow("Nightly:LeakReporter");
+  if (win)
+    win.focus();
+  else
+    window.openDialog("chrome://nightly/content/leaks/leaks.xul", "_blank", "chrome,all,dialog=no");
+},
+
+openURL: function(url, event)
+{
+  openUILink(url, event, false, true);
+},
+
+setCustomTitle: function(title)
+{
+  var titlebar = document.getElementsByTagName("sb-sys-titlebar")[0];
+  titlebar.setAttribute("value", title);
+},
+
+setBlankTitle: function()
+{
+  var titlebar = document.getElementsByTagName("sb-sys-titlebar")[0];
+  titlebar.setAttribute("value", "");
+},
+
+setStandardTitle: function()
+{
+  var titlebar = document.getElementsByTagName("sb-sys-titlebar")[0];
+  titlebar.setAttribute("value", nightlyApp.storedTitle);
+}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/songbirdOverlay.xul	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,56 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE window [
+<!ENTITY % nightlyDTD SYSTEM "chrome://nightly/locale/nightly.dtd">
+%nightlyDTD;
+<!ENTITY % leaksDTD SYSTEM "chrome://nightly/locale/leaks.dtd">
+%leaksDTD;
+]>
+
+<overlay id="NightlySongbirdOverlay"
+         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+       
+  <script type="application/x-javascript" src="nightly.js" />
+  <script type="application/x-javascript" src="songbird.js" />
+  <script type="application/x-javascript" src="breakpad/breakpad.js" />
+  <script type="application/x-javascript" src="chrome://nightly/content/platform.js" />
+
+  <keyset id="mainKeyset">
+    <key key="s" modifiers="accel,shift" oncommand="nightly.getScreenshot();"/>
+  </keyset>
+
+  <popupset id="mainPopupSet">
+    <tooltip orient="vertical" id="nightly-crashreport-tooltip" onpopupshowing="return crashreports.popupTooltip(event)">
+      <label/>
+    </tooltip>
+    <popup id="nightly-crashreport-context">
+      <menuitem oncommand="crashreports.copy(event)" label="&nightly.crashreports.copyid;"/>
+    </popup>
+  </popupset>
+  
+  <menupopup id="menu_ToolsPopup">
+    <menu id="nightly-menu" label="Nightly Tester Tools" insertafter="devToolsSeparator">
+      <menupopup onpopupshowing="nightly.menuPopup(event,this);">
+        <menuitem id="build-copy" label="&nightly.id.copy.label;" oncommand="nightly.copyTemplate('buildid');"/>
+        <menuitem id="build-insert" label="&nightly.id.insert.label;" oncommand="nightly.insertTemplate('buildid');"/>
+        <menuitem id="list-copy" label="&nightly.extensions.copy.label;" oncommand="nightly.copyExtensions();"/>
+        <menuitem id="list-insert" label="&nightly.extensions.insert.label;" oncommand="nightly.insertExtensions();"/>
+        <menuseparator/>
+        <menuitem label="&nightly.screenshot.full.label;" oncommand="nightly.getScreenshot();"/>
+        <menuseparator/>
+        <menuitem label="&nightly.openprofile.label;" oncommand="nightly.openProfileDir();"/>
+        <menuseparator id="nightly-crashreports-separator"/>
+        <menu id="nightly-crashreports-recent" label="&nightly.crashreports.recentlist;" oncommand="crashreports.viewIncident(event);" onclick="checkForMiddleClick(this, event);">
+          <menupopup id="nightly-crashreports-incidents">
+            <menuitem disabled="true" label="&nightly.leaks.loading.label;"/>
+          </menupopup>
+        </menu>
+        <menuseparator/>
+        <menuitem label="&nightly.leakreporter.label;" oncommand="nightlyApp.detectLeaks(event);" onclick="checkForMiddleClick(this, event);"/>
+        <menuseparator/>
+        <menuitem label="&nightly.options.label;" oncommand="nightly.launchOptions();"/>
+      </menupopup>
+    </menu>
+  </menupopup>
+  
+</overlay>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/suite.js	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,36 @@
+var nightlyApp = {
+
+init: function()
+{
+  var brandbundle = document.getElementById("bundle_brand");
+  if (nightly.variables.name==null)
+  {
+    nightly.variables.name=brandbundle.getString("brandShortName");
+  }
+  nightly.variables.brandname=brandbundle.getString("brandFullName");
+  nightly.variables.defaulttitle=nightlyApp.storedTitle;
+},
+
+detectLeaks: function(event)
+{
+  this.openURL('chrome://nightly/content/leaks/leaks.xul', event);
+},
+
+openURL: function(url, event)
+{
+  openTopWin(url);
+},
+
+setCustomTitle: function(title)
+{
+},
+
+setBlankTitle: function()
+{
+},
+
+setStandardTitle: function()
+{
+}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/suiteOverlay.xul	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE window [
+<!ENTITY % nightlyDTD SYSTEM "chrome://nightly/locale/nightly.dtd">
+%nightlyDTD;
+<!ENTITY % leaksDTD SYSTEM "chrome://nightly/locale/leaks.dtd">
+%leaksDTD;
+]>
+
+<overlay id="NightlySuiteOverlay"
+         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+       
+  <script type="application/x-javascript" src="nightly.js" />
+  <script type="application/x-javascript" src="suite.js" />
+  <script type="application/x-javascript" src="breakpad/breakpad.js" />
+  <script type="application/x-javascript" src="chrome://nightly/content/platform.js" />
+
+  <!-- Sidebar -->
+  <broadcasterset id="mainBroadcasterSet">
+    <broadcaster id="viewCrashReportsSidebar"
+          autoCheck="false" 
+          label="&nightly.crashreports.sidebar.title;"
+          type="checkbox"
+          group="sidebar"
+          sidebarurl="chrome://nightly/content/breakpad/sidebar.xul"
+          oncommand="toggleSidebar('viewCrashReportsSidebar');"/>
+  </broadcasterset>
+
+  <keyset id="navKeys">
+    <key key="s" modifiers="accel,shift" oncommand="nightly.getScreenshot();"/>
+  </keyset>
+
+  <popupset id="mainPopupSet">
+    <tooltip orient="vertical" id="nightly-crashreport-tooltip" onpopupshowing="return crashreports.popupTooltip(event)">
+      <label/>
+    </tooltip>
+    <popup id="nightly-crashreport-context">
+      <menuitem oncommand="crashreports.copy(event)" label="&nightly.crashreports.copyid;"/>
+    </popup>
+  </popupset>
+  
+  <menupopup id="taskPopup">
+    <menu id="nightly-menu" label="Nightly Tester Tools" insertbefore="sep_switchprofile">
+      <menupopup onpopupshowing="nightly.menuPopup(event,this);">
+        <menuitem id="build-copy" label="&nightly.id.copy.label;" oncommand="nightly.copyTemplate('buildid');"/>
+        <menuitem id="build-insert" label="&nightly.id.insert.label;" oncommand="nightly.insertTemplate('buildid');"/>
+        <menuitem id="list-copy" label="&nightly.extensions.copy.label;" oncommand="nightly.copyExtensions();"/>
+        <menuitem id="list-insert" label="&nightly.extensions.insert.label;" oncommand="nightly.insertExtensions();"/>
+        <menuseparator/>
+        <menuitem label="&nightly.openprofile.label;" oncommand="nightly.openProfileDir();"/>
+        <menuseparator id="nightly-crashreports-separator"/>
+        <menu id="nightly-crashreports-recent" label="&nightly.crashreports.recentlist;" oncommand="crashreports.viewIncident(event);" onclick="checkForMiddleClick(this, event);">
+          <menupopup id="nightly-crashreports-incidents">
+            <menuitem disabled="true" label="&nightly.leaks.loading.label;"/>
+          </menupopup>
+        </menu>
+        <menuitem id="nightly-breakpad-sidebar" observes="viewBreakpadSidebar"/>
+        <menuseparator/>
+        <menuitem label="&nightly.leakreporter.label;" oncommand="nightlyApp.detectLeaks(event);"/>
+        <menuseparator/>
+        <menuitem label="&nightly.options.label;" oncommand="nightly.launchOptions();"/>
+      </menupopup>
+    </menu>
+  </menupopup>
+  
+</overlay>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/content/winPlatform.js	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,4 @@
+var nightlyplatform = {
+  eol: "\r\n"
+}
+ 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/locale/en-US/configwarning.dtd	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,8 @@
+<!ENTITY dialog.title  "Nightly Tester Tools">
+<!ENTITY dialog.style  "width: 45em">
+
+<!ENTITY title         "&brandShortName; is ignoring add-on compatibility">
+<!ENTITY subtitle      "Nightly Tester Tools can manage add-on compatibility
+                        using a safer method that works on an individual basis.">
+<!ENTITY question      "Do you want to switch to use Nightly Tester Tools to
+                        control compatibility?">
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/locale/en-US/incompatible.dtd	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,11 @@
+<!ENTITY window.title        "Make Compatible">
+<!ENTITY window.style        "width: 40em; height: 25em">
+<!ENTITY window.accept       "Force Install">
+<!ENTITY window.cancel       "Skip">
+
+<!ENTITY warning.label       "Forcing incompatible add-ons to run could cause
+                              hangs, crashes, memory leaks, data corruption or
+                              other problems.">
+
+<!ENTITY incompatible.label  "This add-on is incompatible with this version of &brandShortName;.">
+<!ENTITY insecure.label      "This add-on cannot update securely. Updates must be disabled.">
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/locale/en-US/leaks.dtd	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,20 @@
+<!ENTITY nightly.leaks.title                  "Leak Log Analyzer">
+
+<!ENTITY nightly.leaks.logfile.label          "Log file:">
+<!ENTITY nightly.leaks.browse.label           "Browse...">
+<!ENTITY nightly.leaks.displayfull.label      "Display full log">
+<!ENTITY nightly.leaks.loading.label          "Loading...">
+<!ENTITY nightly.leaks.overview.label         "Overview">
+<!ENTITY nightly.leaks.fulllog.label          "Complete Log">
+<!ENTITY nightly.leaks.copy.label             "Copy to Clipboard">
+<!ENTITY nightly.leaks.save.label             "Save As...">
+<!ENTITY nightly.leaks.summary.label          "Summary">
+<!ENTITY nightly.leaks.details.label          "Details">
+
+<!ENTITY nightly.leaks.display.label          "Display:">
+<!ENTITY nightly.leaks.docshellfilter.label   "Docshells">
+<!ENTITY nightly.leaks.windowfilter.label     "Windows">
+<!ENTITY nightly.leaks.documentfilter.label   "Documents">
+<!ENTITY nightly.leaks.leakedfilter.label     "Leaked">
+<!ENTITY nightly.leaks.collectedfilter.label  "Collected">
+<!ENTITY nightly.leaks.unknownfilter.label    "Unknown">
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/locale/en-US/leaks.properties	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,14 @@
+nightly.leaks.sessiondate.label=Session ended %S
+nightly.leaks.windowleaks.label=Leaked %S out of %S DOM windows
+nightly.leaks.documentleaks.label=Leaked %S out of %S documents
+nightly.leaks.docshellleaks.label=Leaked %S out of %S docshells
+nightly.leaks.summary.label=Summary
+nightly.leaks.details.label=Details
+nightly.leaks.outerleak.text=Leaked outer window %S at address %S.
+nightly.leaks.innerleak.text=Leaked inner window %S (outer %S) at address %S.
+nightly.leaks.documentleak.text=Leaked document at address %S.
+nightly.leaks.docshellleak.text=Leaked docshell at address %S.
+nightly.leaks.urileak.text=with URI "%S".
+nightly.leaks.filepicker.title=Select Log File
+nightly.leaks.filepicker.filterlog=Log Files (*.log)
+nightly.leaks.filepicker.filterall=All Files (*.*)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/locale/en-US/nightly.dtd	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,25 @@
+<!ENTITY nightly.openprofile.label            "Open Profile Folder">
+
+<!ENTITY nightly.id.copy.label                "Copy Build ID to Clipboard">
+<!ENTITY nightly.id.insert.label              "Insert Build ID into Textbox">
+<!ENTITY nightly.id.insert.tooltip            "Inserts the build identifier into the current text box.">
+
+<!ENTITY nightly.extensions.copy.label        "Copy List of Extensions to Clipboard">
+<!ENTITY nightly.extensions.insert.label      "Insert List of Extensions into Textbox">
+<!ENTITY nightly.appenable.label              "Override compatibility">
+<!ENTITY nightly.enableall.label              "Override all compatibility">
+<!ENTITY nightly.enableall.tooltip            "Overrides compatibility for all listed incompatible add-ons">
+
+<!ENTITY nightly.leakreporter.label           "Analyse Leak Log">
+
+<!ENTITY nightly.options.label                "Options">
+
+<!ENTITY nightly.screenshot.full.label        "Take Screenshot">
+
+<!ENTITY nightly.crashreports.sidebar.title   "Crash Reports Sidebar">
+<!ENTITY nightly.crashreports.copyid          "Copy">
+<!ENTITY nightly.crashreports.id              "ID">
+<!ENTITY nightly.crashreports.date            "Date">
+<!ENTITY nightly.crashreports.recentlist      "Recent Incidents">
+
+<!ENTITY nightly.session.restore              "Restore from last session...">
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/locale/en-US/nightly.properties	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,3 @@
+extensions.{8620c15f-30dc-4dba-a131-7c5d20cf4a29}.description=Useful tools for the nightly tester.
+nightly.notextbox.message=You must select a text box before using this function.
+nightly.noextensions.message=No extensions were found.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/locale/en-US/options.dtd	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,14 @@
+<!ENTITY nightly.options.height               "30em">
+
+<!ENTITY nightly.options.title                "Nightly Tester Options">
+
+
+<!ENTITY nightly.paneTitlebar.title           "Titlebar">
+<!ENTITY nightly.paneTitlebar.description     "You can use a custom title to always display the current build in the titlebar.">
+
+<!ENTITY nightly.customtitle.label            "Use custom title">
+<!ENTITY nightly.customtemplate.label         "Custom title template:">
+<!ENTITY nightly.variables.description        "The following variables can be used in the title (case insensitive).">
+<!ENTITY nightly.variable.label               "Variable">
+<!ENTITY nightly.variabledesc.label           "Description">
+<!ENTITY nightly.variablevalue.label          "Value">
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/locale/en-US/screenshot.dtd	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,9 @@
+<!ENTITY screenshot.window.title        "Screenshot Grabber">
+
+<!ENTITY screenshot.save.label          "Save As...">
+<!ENTITY screenshot.submit.label        "Submit to ImageShack...">
+<!ENTITY screenshot.copy.label          "Copy to Clipboard">
+<!ENTITY screenshot.redraw.label        "Redraw">
+<!ENTITY screenshot.zoom.label          "Zoom:">
+<!ENTITY screenshot.window.label        "Window:">
+<!ENTITY screenshot.timer.label         "Capture in: 5">
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/locale/en-US/screenshot.properties	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,4 @@
+screenshot.filepicker.title=Save Screenshot As...
+screenshot.filepicker.filterJPG=JPG files. (*.jpg)
+screenshot.filepicker.filterPNG=PNG files. (*.png)
+screenshot.timer.label=Capture in: %S
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/locale/en-US/variables.properties	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,18 @@
+variable.AppID.description=Application Identifier
+variable.Vendor.description=Application Vendor
+variable.Name.description=Application Name
+variable.Version.description=Application Version
+variable.AppBuildID.description=Application Build Identifier
+variable.PlatformBuildID.description=XUL Platform Build Identifier
+variable.PlatformVersion.description=XUL Platform Version
+variable.GeckoBuildID.description=Gecko Build Identifier
+variable.GeckoVersion.description=Gecko Version
+variable.BrandName.description=Application Brand Name
+variable.UserAgent.description=User Agent String
+variable.Locale.description=Current Locale
+variable.OS.description=Compilation OS
+variable.Processor.description=Compilation Processor
+variable.Compiler.description=Compiler
+variable.DefaultTitle.description=Default Application Title
+variable.Profile.description=Current Profile
+variable.Toolkit.description=Graphics Toolkit
Binary file chrome/nightly.jar has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/skin/browser.css	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,7 @@
+#nightly-tester-enter {
+  list-style-image: url("chrome://nightly/skin/idlarge.png");
+}
+
+toolbar[iconsize="small"] #nightly-tester-enter {
+  list-style-image: url("chrome://nightly/skin/idsmall.png");
+}
Binary file chrome/skin/cbox-check.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/skin/configwarning.css	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,9 @@
+dialog {
+  padding: 1em;
+}
+
+#title {
+  font-weight: bold;
+  font-size: 110%;
+  margin-bottom: 1em;
+}
Binary file chrome/skin/crashreports/crash.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/skin/crashreports/sidebar.css	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,5 @@
+treechildren#treeroot::-moz-tree-image(name) {
+  padding-right: 2px;
+  margin: 0px 2px;
+  list-style-image: url("chrome://nightly/skin/crashreports/crash.png") !important;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/skin/extensions/extensions.css	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,3 @@
+#enableallButton {
+  list-style-image: none !important;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/skin/extensions/incompatible.css	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,20 @@
+#warning {
+  font-weight: bold;
+}
+
+richlistitem {
+  padding: 2px;
+  border-bottom: 1px dotted;
+}
+
+.name-version label {
+  font-weight: bold;
+}
+
+[secure="true"] .insecure {
+  display: none;
+}
+
+[compatible="true"] .incompatible {
+  display: none;
+}
Binary file chrome/skin/idlarge.png has changed
Binary file chrome/skin/idsmall.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/skin/leaks/leaks.css	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,4 @@
+browser {
+  background-color: white;
+  border: 1px solid threedshadow;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/skin/options/options.css	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,14 @@
+.content-box {
+  -moz-box-flex: 1;
+}
+
+subpane {
+  -moz-binding: url('chrome://nightly/content/options/subpane.xml#subpane');
+  padding-left: 2em;
+}
+
+#NightlyTesterOptions {
+  padding: 0;
+  width: 40em;
+  height: 35em;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/skin/screenshot/screenshot.css	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,6 @@
+window {
+}
+
+scrollbox {
+  overflow: auto;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chrome/skin/session/session.css	Tue Dec 02 20:38:20 2008 +0900
@@ -0,0 +1,3 @@
+treechildren::-moz-tree-checkbox(checked) {
+  list-style-image: url("chrome://nightly/skin/cbox-check.gif");
+}